Merge lp:~pete-woods/indicator-network/ethernet-support into lp:indicator-network

Proposed by Pete Woods
Status: Merged
Approved by: Pete Woods
Approved revision: 651
Merged at revision: 650
Proposed branch: lp:~pete-woods/indicator-network/ethernet-support
Merge into: lp:indicator-network
Diff against target: 4190 lines (+2700/-328)
60 files modified
data/nm-device-ethernet.xml (+51/-0)
debian/changelog (+9/-0)
debian/control (+3/-3)
debian/rules (+2/-9)
po/indicator-network.pot (+152/-116)
src/indicator/CMakeLists.txt (+7/-0)
src/indicator/factory.cpp (+6/-0)
src/indicator/factory.h (+4/-1)
src/indicator/icons.cpp (+21/-0)
src/indicator/icons.h (+2/-0)
src/indicator/menu-builder.cpp (+11/-4)
src/indicator/menuitems/ethernet-connection-item.cpp (+73/-0)
src/indicator/menuitems/ethernet-connection-item.h (+46/-0)
src/indicator/menuitems/ethernet-item.cpp (+103/-0)
src/indicator/menuitems/ethernet-item.h (+54/-0)
src/indicator/menuitems/ethernet-link-item.cpp (+109/-0)
src/indicator/menuitems/ethernet-link-item.h (+40/-0)
src/indicator/menuitems/section.h (+2/-0)
src/indicator/menuitems/wifi-link-item.cpp (+3/-3)
src/indicator/menuitems/wifi-link-item.h (+1/-1)
src/indicator/menuitems/wwan-link-item.h (+2/-1)
src/indicator/nmofono/connection/active-connection-manager.cpp (+5/-0)
src/indicator/nmofono/connection/active-connection-manager.h (+3/-0)
src/indicator/nmofono/connection/active-connection.cpp (+31/-0)
src/indicator/nmofono/connection/active-connection.h (+6/-0)
src/indicator/nmofono/connection/available-connection.cpp (+96/-0)
src/indicator/nmofono/connection/available-connection.h (+68/-0)
src/indicator/nmofono/ethernet/ethernet-link.cpp (+379/-0)
src/indicator/nmofono/ethernet/ethernet-link.h (+93/-0)
src/indicator/nmofono/link.h (+8/-2)
src/indicator/nmofono/manager-impl.cpp (+67/-36)
src/indicator/nmofono/manager-impl.h (+5/-2)
src/indicator/nmofono/manager.h (+7/-4)
src/indicator/nmofono/nm-device-statistics-monitor.cpp (+4/-29)
src/indicator/nmofono/nm-device-statistics-monitor.h (+1/-1)
src/indicator/nmofono/wifi/wifi-link-impl.cpp (+19/-20)
src/indicator/nmofono/wifi/wifi-link-impl.h (+3/-1)
src/indicator/nmofono/wifi/wifi-link.h (+2/-1)
src/indicator/root-state.cpp (+16/-0)
src/indicator/sections/ethernet-link-section.cpp (+211/-0)
src/indicator/sections/ethernet-link-section.h (+45/-0)
src/indicator/sections/ethernet-section.cpp (+140/-0)
src/indicator/sections/ethernet-section.h (+44/-0)
src/indicator/sections/quick-access-section.h (+2/-1)
src/indicator/sections/vpn-section.cpp (+0/-1)
src/indicator/sections/wifi-section.cpp (+76/-40)
src/indicator/sections/wifi-section.h (+2/-1)
src/indicator/sections/wwan-section.cpp (+2/-2)
src/indicator/sections/wwan-section.h (+2/-1)
src/menumodel-cpp/menu-item.cpp (+12/-0)
src/menumodel-cpp/menu-item.h (+2/-0)
src/menumodel-cpp/menu.cpp (+5/-0)
src/menumodel-cpp/menu.h (+2/-0)
src/qdbus-stubs/CMakeLists.txt (+7/-0)
tests/data/networkmanager.py (+103/-28)
tests/integration/CMakeLists.txt (+0/-3)
tests/integration/indicator-network-test-base.cpp (+74/-7)
tests/integration/indicator-network-test-base.h (+18/-1)
tests/integration/test-connectivity-api-sim.cpp (+1/-1)
tests/integration/test-indicator.cpp (+438/-8)
To merge this branch: bzr merge lp:~pete-woods/indicator-network/ethernet-support
Reviewer Review Type Date Requested Status
unity-api-1-bot continuous-integration Needs Fixing
Indicator Applet Developers Pending
Review via email: mp+311755@code.launchpad.net

Commit message

Add ethernet support.

Description of the change

Add ethernet support.

To post a comment you must log in.
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)
Revision history for this message
unity-api-1-bot (unity-api-1-bot) wrote :
review: Needs Fixing (continuous-integration)

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'data/nm-device-ethernet.xml'
2--- data/nm-device-ethernet.xml 1970-01-01 00:00:00 +0000
3+++ data/nm-device-ethernet.xml 2016-12-05 18:14:38 +0000
4@@ -0,0 +1,51 @@
5+<?xml version="1.0" encoding="UTF-8"?>
6+<node name="/">
7+ <interface name="org.freedesktop.NetworkManager.Device.Wired">
8+ <annotation name="org.gtk.GDBus.C.Name" value="DeviceEthernet"/>
9+
10+ <!--
11+ HwAddress:
12+
13+ Active hardware address of the device.
14+ -->
15+ <property name="HwAddress" type="s" access="read"/>
16+
17+ <!--
18+ PermHwAddress:
19+
20+ Permanent hardware address of the device.
21+ -->
22+ <property name="PermHwAddress" type="s" access="read"/>
23+
24+ <!--
25+ Speed:
26+
27+ Design speed of the device, in megabits/second (Mb/s).
28+ -->
29+ <property name="Speed" type="u" access="read"/>
30+
31+ <!--
32+ S390Subchannels:
33+
34+ Array of S/390 subchannels for S/390 or z/Architecture devices.
35+ -->
36+ <property name="S390Subchannels" type="as" access="read"/>
37+
38+ <!--
39+ Carrier:
40+
41+ Indicates whether the physical carrier is found (e.g. whether a cable is
42+ plugged in or not).
43+ -->
44+ <property name="Carrier" type="b" access="read"/>
45+
46+ <!--
47+ PropertiesChanged:
48+ @properties: A dictionary mapping property names to variant boxed values
49+ -->
50+ <signal name="PropertiesChanged">
51+ <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
52+ <arg name="properties" type="a{sv}"/>
53+ </signal>
54+ </interface>
55+</node>
56
57=== modified file 'debian/changelog'
58--- debian/changelog 2016-11-11 11:09:08 +0000
59+++ debian/changelog 2016-12-05 18:14:38 +0000
60@@ -1,3 +1,12 @@
61+indicator-network (0.9.0-0ubuntu1) UNRELEASED; urgency=medium
62+
63+ * Add ethernet support to indicator (and NM dbus template).
64+ * Switch to common active connection interface throughout the codebase.
65+ * Re-enable tests on all arches except powerpc, ppc64el, s390x.
66+ * Fix Wi-Fi widget visibility.
67+
68+ -- Pete <pete.woods@canonical.com> Fri, 25 Nov 2016 22:35:52 +0000
69+
70 indicator-network (0.8.0+17.04.20161111-0ubuntu1) zesty; urgency=medium
71
72 * Fix memory corruption inside unix signal handler (LP: #1632275)
73
74=== modified file 'debian/control'
75--- debian/control 2016-10-30 15:13:34 +0000
76+++ debian/control 2016-12-05 18:14:38 +0000
77@@ -12,10 +12,10 @@
78 graphviz,
79 intltool,
80 libglib2.0-dev,
81- libgmenuharness-dev (>= 0.1.1),
82+ libgmenuharness-dev (>= 0.1.2),
83 libqofono-dev,
84 libqofono-qt5-0,
85- libqtdbusmock1-dev (>= 0.4),
86+ libqtdbusmock1-dev (>= 0.6),
87 libqtdbustest1-dev,
88 libsecret-1-dev,
89 liburl-dispatcher1-dev,
90@@ -51,7 +51,7 @@
91 network-manager,
92 network-manager-openvpn,
93 network-manager-pptp,
94- ubuntu-mobile-icons (>= 13.04+13.10.20131014),
95+ ubuntu-mobile-icons (>= 16.10+16.04.20161205),
96 Suggests: ofono,
97 urfkill
98 Conflicts: chewie,
99
100=== modified file 'debian/rules'
101--- debian/rules 2016-10-30 18:35:53 +0000
102+++ debian/rules 2016-12-05 18:14:38 +0000
103@@ -8,15 +8,8 @@
104 export DPKG_GENSYMBOLS_CHECK_LEVEL = 4
105
106 ENABLE_TESTS = ON
107-ifneq (,$(filter $(DEB_HOST_ARCH),arm64 s390x powerpc ppc64el))
108- ENABLE_TESTS = OFF
109-endif
110-ifneq (,$(filter $(DEB_HOST_ARCH),i386))
111- ifeq (Ubuntu,$(DEB_VENDOR))
112- ifeq (vivid,$(DEB_DISTRIBUTION))
113- ENABLE_TESTS = OFF
114- endif
115- endif
116+ifneq (,$(filter $(DEB_HOST_ARCH),s390x powerpc ppc64el))
117+ ENABLE_TESTS = OFF
118 endif
119
120 %:
121
122=== modified file 'po/indicator-network.pot'
123--- po/indicator-network.pot 2016-04-29 14:08:19 +0000
124+++ po/indicator-network.pot 2016-12-05 18:14:38 +0000
125@@ -8,7 +8,7 @@
126 msgstr ""
127 "Project-Id-Version: PACKAGE VERSION\n"
128 "Report-Msgid-Bugs-To: \n"
129-"POT-Creation-Date: 2016-04-29 12:38+0300\n"
130+"POT-Creation-Date: 2016-11-30 16:30+0000\n"
131 "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
132 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
133 "Language-Team: LANGUAGE <LL@li.org>\n"
134@@ -38,64 +38,51 @@
135 msgid "Cancel"
136 msgstr ""
137
138-#: ../src/indicator/menuitems/wifi-link-item.cpp:109
139-msgid "Other network…"
140-msgstr ""
141-
142-#: ../src/indicator/menuitems/wwan-link-item.cpp:90
143-msgid "No SIM"
144-msgstr ""
145-
146-#: ../src/indicator/menuitems/wwan-link-item.cpp:97
147-msgid "SIM Error"
148-msgstr ""
149-
150-#: ../src/indicator/menuitems/wwan-link-item.cpp:105
151-msgid "SIM Locked"
152-msgstr ""
153-
154-#: ../src/indicator/menuitems/wwan-link-item.cpp:118
155-msgid "Unregistered"
156-msgstr ""
157-
158-#: ../src/indicator/menuitems/wwan-link-item.cpp:123
159-msgid "Unknown"
160-msgstr ""
161-
162-#: ../src/indicator/menuitems/wwan-link-item.cpp:128
163-msgid "Denied"
164-msgstr ""
165-
166-#: ../src/indicator/menuitems/wwan-link-item.cpp:133
167-msgid "Searching"
168-msgstr ""
169-
170-#: ../src/indicator/menuitems/wwan-link-item.cpp:145
171-msgid "No Signal"
172-msgstr ""
173-
174-#: ../src/indicator/menuitems/wwan-link-item.cpp:157
175-#: ../src/indicator/menuitems/wwan-link-item.cpp:164
176-msgid "Offline"
177-msgstr ""
178-
179-#. TODO Move this into a new class
180-#: ../src/indicator/factory.cpp:187
181-msgid "Wi-Fi"
182-msgstr ""
183-
184-#. TODO Move this into a new class
185-#: ../src/indicator/factory.cpp:198
186-msgid "Flight Mode"
187-msgstr ""
188-
189-#: ../src/indicator/factory.cpp:208
190-msgid "Cellular data"
191-msgstr ""
192-
193-#. TODO Move this into a new class
194-#: ../src/indicator/factory.cpp:219
195-msgid "Hotspot"
196+#: ../src/indicator/vpn-status-notifier.cpp:48
197+msgid "The VPN connection '%1' failed."
198+msgstr ""
199+
200+#: ../src/indicator/vpn-status-notifier.cpp:50
201+msgid ""
202+"The VPN connection '%1' failed because the network connection was "
203+"interrupted."
204+msgstr ""
205+
206+#: ../src/indicator/vpn-status-notifier.cpp:51
207+msgid ""
208+"The VPN connection '%1' failed because the VPN service stopped unexpectedly."
209+msgstr ""
210+
211+#: ../src/indicator/vpn-status-notifier.cpp:52
212+msgid ""
213+"The VPN connection '%1' failed because the VPN service returned invalid "
214+"configuration."
215+msgstr ""
216+
217+#: ../src/indicator/vpn-status-notifier.cpp:53
218+msgid ""
219+"The VPN connection '%1' failed because the connection attempt timed out."
220+msgstr ""
221+
222+#: ../src/indicator/vpn-status-notifier.cpp:54
223+msgid ""
224+"The VPN connection '%1' failed because the VPN service did not start in time."
225+msgstr ""
226+
227+#: ../src/indicator/vpn-status-notifier.cpp:55
228+msgid "The VPN connection '%1' failed because the VPN service failed to start."
229+msgstr ""
230+
231+#: ../src/indicator/vpn-status-notifier.cpp:56
232+msgid "The VPN connection '%1' failed because there were no valid VPN secrets."
233+msgstr ""
234+
235+#: ../src/indicator/vpn-status-notifier.cpp:57
236+msgid "The VPN connection '%1' failed because of invalid VPN secrets."
237+msgstr ""
238+
239+#: ../src/indicator/vpn-status-notifier.cpp:68
240+msgid "VPN Connection Failed"
241 msgstr ""
242
243 #: ../src/indicator/sim-unlock-dialog.cpp:144
244@@ -186,70 +173,119 @@
245 msgid "PIN codes did not match."
246 msgstr ""
247
248-#: ../src/indicator/vpn-status-notifier.cpp:48
249-msgid "The VPN connection '%1' failed."
250-msgstr ""
251-
252-#: ../src/indicator/vpn-status-notifier.cpp:50
253-msgid ""
254-"The VPN connection '%1' failed because the network connection was "
255-"interrupted."
256-msgstr ""
257-
258-#: ../src/indicator/vpn-status-notifier.cpp:51
259-msgid ""
260-"The VPN connection '%1' failed because the VPN service stopped unexpectedly."
261-msgstr ""
262-
263-#: ../src/indicator/vpn-status-notifier.cpp:52
264-msgid ""
265-"The VPN connection '%1' failed because the VPN service returned invalid "
266-"configuration."
267-msgstr ""
268-
269-#: ../src/indicator/vpn-status-notifier.cpp:53
270-msgid ""
271-"The VPN connection '%1' failed because the connection attempt timed out."
272-msgstr ""
273-
274-#: ../src/indicator/vpn-status-notifier.cpp:54
275-msgid ""
276-"The VPN connection '%1' failed because the VPN service did not start in time."
277-msgstr ""
278-
279-#: ../src/indicator/vpn-status-notifier.cpp:55
280-msgid "The VPN connection '%1' failed because the VPN service failed to start."
281-msgstr ""
282-
283-#: ../src/indicator/vpn-status-notifier.cpp:56
284-msgid "The VPN connection '%1' failed because there were no valid VPN secrets."
285-msgstr ""
286-
287-#: ../src/indicator/vpn-status-notifier.cpp:57
288-msgid "The VPN connection '%1' failed because of invalid VPN secrets."
289-msgstr ""
290-
291-#: ../src/indicator/vpn-status-notifier.cpp:68
292-msgid "VPN Connection Failed"
293-msgstr ""
294-
295-#: ../src/indicator/sections/wwan-section.cpp:99
296+#: ../src/indicator/nmofono/vpn/vpn-manager.cpp:81
297+msgid "VPN connection %1"
298+msgstr ""
299+
300+#: ../src/indicator/menuitems/wifi-link-item.cpp:109
301+msgid "Other network…"
302+msgstr ""
303+
304+#: ../src/indicator/menuitems/ethernet-link-item.cpp:39
305+msgid "Connected"
306+msgstr ""
307+
308+#: ../src/indicator/menuitems/ethernet-link-item.cpp:40
309+msgid "Connecting"
310+msgstr ""
311+
312+#: ../src/indicator/menuitems/ethernet-link-item.cpp:41
313+msgid "Disabled"
314+msgstr ""
315+
316+#: ../src/indicator/menuitems/ethernet-link-item.cpp:42
317+msgid "Disconnected"
318+msgstr ""
319+
320+#: ../src/indicator/menuitems/ethernet-link-item.cpp:43
321+msgid "Online"
322+msgstr ""
323+
324+#: ../src/indicator/menuitems/ethernet-link-item.cpp:44
325+msgid "Failed"
326+msgstr ""
327+
328+#: ../src/indicator/menuitems/ethernet-link-item.cpp:56
329+msgid "Ethernet (%1)"
330+msgstr ""
331+
332+#: ../src/indicator/menuitems/ethernet-link-item.cpp:60
333+msgid "Ethernet"
334+msgstr ""
335+
336+#: ../src/indicator/menuitems/wwan-link-item.cpp:90
337+msgid "No SIM"
338+msgstr ""
339+
340+#: ../src/indicator/menuitems/wwan-link-item.cpp:97
341+msgid "SIM Error"
342+msgstr ""
343+
344+#: ../src/indicator/menuitems/wwan-link-item.cpp:105
345+msgid "SIM Locked"
346+msgstr ""
347+
348+#: ../src/indicator/menuitems/wwan-link-item.cpp:118
349+msgid "Unregistered"
350+msgstr ""
351+
352+#: ../src/indicator/menuitems/wwan-link-item.cpp:123
353+msgid "Unknown"
354+msgstr ""
355+
356+#: ../src/indicator/menuitems/wwan-link-item.cpp:128
357+msgid "Denied"
358+msgstr ""
359+
360+#: ../src/indicator/menuitems/wwan-link-item.cpp:133
361+msgid "Searching"
362+msgstr ""
363+
364+#: ../src/indicator/menuitems/wwan-link-item.cpp:145
365+msgid "No Signal"
366+msgstr ""
367+
368+#: ../src/indicator/menuitems/wwan-link-item.cpp:157
369+#: ../src/indicator/menuitems/wwan-link-item.cpp:164
370+msgid "Offline"
371+msgstr ""
372+
373+#. TRANSLATORS: this is the indicator title shown on the top header of the indicator area
374+#: ../src/indicator/root-state.cpp:340
375+msgid "Network"
376+msgstr ""
377+
378+#. TODO Move this into a new class
379+#: ../src/indicator/factory.cpp:193
380+msgid "Wi-Fi"
381+msgstr ""
382+
383+#. TODO Move this into a new class
384+#: ../src/indicator/factory.cpp:204
385+msgid "Flight Mode"
386+msgstr ""
387+
388+#: ../src/indicator/factory.cpp:214
389+msgid "Cellular data"
390+msgstr ""
391+
392+#. TODO Move this into a new class
393+#: ../src/indicator/factory.cpp:227
394+msgid "Hotspot"
395+msgstr ""
396+
397+#: ../src/indicator/sections/wwan-section.cpp:102
398 msgid "Cellular settings…"
399 msgstr ""
400
401-#: ../src/indicator/sections/vpn-section.cpp:140
402-msgid "VPN settings…"
403+#: ../src/indicator/sections/ethernet-section.cpp:114
404+msgid "Ethernet settings…"
405 msgstr ""
406
407 #: ../src/indicator/sections/wifi-section.cpp:65
408 msgid "Wi-Fi settings…"
409 msgstr ""
410
411-#. TRANSLATORS: this is the indicator title shown on the top header of the indicator area
412-#: ../src/indicator/root-state.cpp:306
413-msgid "Network"
414-msgstr ""
415-
416-#: ../src/indicator/nmofono/vpn/vpn-manager.cpp:81
417-msgid "VPN connection %1"
418+#: ../src/indicator/sections/vpn-section.cpp:139
419+msgid "VPN settings…"
420 msgstr ""
421
422=== modified file 'src/indicator/CMakeLists.txt'
423--- src/indicator/CMakeLists.txt 2016-10-30 15:13:34 +0000
424+++ src/indicator/CMakeLists.txt 2016-12-05 18:14:38 +0000
425@@ -25,6 +25,8 @@
426 nmofono/connection/active-connection.cpp
427 nmofono/connection/active-connection-manager.cpp
428 nmofono/connection/active-vpn-connection.cpp
429+ nmofono/connection/available-connection.cpp
430+ nmofono/ethernet/ethernet-link.cpp
431 nmofono/wifi/access-point.cpp
432 nmofono/wifi/access-point-impl.cpp
433 nmofono/wifi/grouped-access-point.cpp
434@@ -45,6 +47,8 @@
435 sim-unlock-dialog.cpp
436 root-state.cpp
437 vpn-status-notifier.cpp
438+ sections/ethernet-section.cpp
439+ sections/ethernet-link-section.cpp
440 sections/quick-access-section.cpp
441 sections/wifi-section.cpp
442 sections/vpn-section.cpp
443@@ -58,6 +62,9 @@
444 connectivity-service/dbus-sim.cpp
445
446 menuitems/access-point-item.cpp
447+ menuitems/ethernet-connection-item.cpp
448+ menuitems/ethernet-item.cpp
449+ menuitems/ethernet-link-item.cpp
450 menuitems/switch-item.cpp
451 menuitems/text-item.cpp
452 menuitems/vpn-item.cpp
453
454=== modified file 'src/indicator/factory.cpp'
455--- src/indicator/factory.cpp 2016-07-04 17:43:21 +0000
456+++ src/indicator/factory.cpp 2016-12-05 18:14:38 +0000
457@@ -88,6 +88,7 @@
458 singletonNotificationManager(),
459 singletonKillSwitch(),
460 singletonHotspotManager(),
461+ singletonActiveConnectionManager(),
462 QDBusConnection::systemBus());
463 }
464 return m_nmofono;
465@@ -155,6 +156,11 @@
466 return make_unique<QuickAccessSection>(d->singletonNmofono(), flightModeSwitch);
467 }
468
469+unique_ptr<EthernetSection> Factory::newEthernetSection()
470+{
471+ return make_unique<EthernetSection>(d->singletonNmofono());
472+}
473+
474 unique_ptr<WwanSection> Factory::newWwanSection(SwitchItem::Ptr mobileDataSwitch, SwitchItem::Ptr hotspotSwitch)
475 {
476 return make_unique<WwanSection>(d->singletonNmofono(), mobileDataSwitch, hotspotSwitch);
477
478=== modified file 'src/indicator/factory.h'
479--- src/indicator/factory.h 2016-05-05 14:15:23 +0000
480+++ src/indicator/factory.h 2016-12-05 18:14:38 +0000
481@@ -26,10 +26,11 @@
482 #include <connectivity-service/connectivity-service.h>
483 #include <menumodel-cpp/menu-exporter.h>
484 #include <menumodel-cpp/action-group-merger.h>
485+#include <sections/ethernet-section.h>
486 #include <sections/quick-access-section.h>
487-#include <sections/vpn-section.h>
488 #include <sections/wifi-section.h>
489 #include <sections/wwan-section.h>
490+#include <sections/vpn-section.h>
491 #include <menuitems/switch-item.h>
492
493 #include <memory>
494@@ -58,6 +59,8 @@
495
496 virtual std::unique_ptr<WwanSection> newWwanSection(SwitchItem::Ptr mobileDataSwitch, SwitchItem::Ptr hotspotSwitch);
497
498+ virtual EthernetSection::UPtr newEthernetSection();
499+
500 virtual std::unique_ptr<WifiSection> newWiFiSection(SwitchItem::Ptr wifiSwitch);
501
502 virtual std::unique_ptr<VpnSection> newVpnSection();
503
504=== modified file 'src/indicator/icons.cpp'
505--- src/indicator/icons.cpp 2015-08-13 16:41:41 +0000
506+++ src/indicator/icons.cpp 2016-12-05 18:14:38 +0000
507@@ -89,3 +89,24 @@
508 // shouldn't be reached
509 return QString();
510 }
511+
512+QString Icons::ethernetIcon(nmofono::Link::Status status)
513+{
514+ switch (status)
515+ {
516+ case Link::Status::connected:
517+ return "network-wired-connected";
518+ case Link::Status::connecting:
519+ return "network-wired-connecting";
520+ case Link::Status::disabled:
521+ return "network-wired-disabled";
522+ case Link::Status::offline:
523+ return "network-wired-offline";
524+ case Link::Status::online:
525+ return "network-wired-active";
526+ case Link::Status::failed:
527+ return "network-wired-error";
528+ }
529+ // shouldn't be reached
530+ return QString();
531+}
532
533=== modified file 'src/indicator/icons.h'
534--- src/indicator/icons.h 2015-08-13 16:41:41 +0000
535+++ src/indicator/icons.h 2016-12-05 18:14:38 +0000
536@@ -34,4 +34,6 @@
537 static QString bearerIcon(nmofono::wwan::Modem::Bearer bearer);
538
539 static QString wifiIcon(nmofono::wifi::WifiLink::Signal signal);
540+
541+ static QString ethernetIcon(nmofono::Link::Status status);
542 };
543
544=== modified file 'src/indicator/menu-builder.cpp'
545--- src/indicator/menu-builder.cpp 2016-10-28 15:26:53 +0000
546+++ src/indicator/menu-builder.cpp 2016-12-05 18:14:38 +0000
547@@ -47,10 +47,11 @@
548 SwitchItem::Ptr m_hotspotSwitch;
549 SwitchItem::Ptr m_wifiSwitch;
550
551- QuickAccessSection::Ptr m_quickAccessSection;
552- WifiSection::Ptr m_wifiSection;
553- WwanSection::Ptr m_wwanSection;
554- VpnSection::Ptr m_vpnSection;
555+ QuickAccessSection::SPtr m_quickAccessSection;
556+ EthernetSection::SPtr m_ethernetSection;
557+ WifiSection::SPtr m_wifiSection;
558+ WwanSection::SPtr m_wwanSection;
559+ VpnSection::SPtr m_vpnSection;
560
561 MenuExporter::UPtr m_desktopMenuExporter;
562 MenuExporter::UPtr m_desktopGreeterMenuExporter;
563@@ -156,6 +157,7 @@
564
565 d->m_quickAccessSection = factory.newQuickAccessSection(d->m_flightModeSwitch);
566 d->m_wwanSection = factory.newWwanSection(d->m_mobileDataSwitch, d->m_hotspotSwitch);
567+ d->m_ethernetSection = factory.newEthernetSection();
568 d->m_wifiSection = factory.newWiFiSection(d->m_wifiSwitch);
569 d->m_vpnSection = factory.newVpnSection();
570
571@@ -169,6 +171,11 @@
572 d->m_phoneMenu->addSection(d->m_wwanSection);
573 d->m_phoneGreeterMenu->addSection(d->m_wwanSection);
574
575+ d->m_desktopMenu->addSection(d->m_ethernetSection);
576+ d->m_desktopGreeterMenu->addSection(d->m_ethernetSection);
577+ d->m_phoneMenu->addSection(d->m_ethernetSection);
578+ d->m_phoneGreeterMenu->addSection(d->m_ethernetSection);
579+
580 d->m_desktopMenu->addSection(d->m_wifiSection);
581 d->m_desktopGreeterMenu->addSection(d->m_wifiSection);
582 d->m_phoneMenu->addSection(d->m_wifiSection);
583
584=== added file 'src/indicator/menuitems/ethernet-connection-item.cpp'
585--- src/indicator/menuitems/ethernet-connection-item.cpp 1970-01-01 00:00:00 +0000
586+++ src/indicator/menuitems/ethernet-connection-item.cpp 2016-12-05 18:14:38 +0000
587@@ -0,0 +1,73 @@
588+/*
589+ * Copyright (C) 2014 Canonical, Ltd.
590+ *
591+ * This program is free software: you can redistribute it and/or modify it
592+ * under the terms of the GNU General Public License version 3, as published
593+ * by the Free Software Foundation.
594+ *
595+ * This program is distributed in the hope that it will be useful, but
596+ * WITHOUT ANY WARRANTY; without even the implied warranties of
597+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
598+ * PURPOSE. See the GNU General Public License for more details.
599+ *
600+ * You should have received a copy of the GNU General Public License along
601+ * with this program. If not, see <http://www.gnu.org/licenses/>.
602+ *
603+ * Authors:
604+ * Pete Woods <pete.woods@canonical.com>
605+ */
606+
607+#include <menuitems/ethernet-connection-item.h>
608+#include <QDebug>
609+
610+using namespace std;
611+
612+using namespace nmofono::connection;
613+
614+class EthernetConnectionItem::Private : public QObject
615+{
616+Q_OBJECT
617+
618+public:
619+ Private(EthernetConnectionItem& parent) :
620+ p(parent)
621+ {
622+ }
623+
624+public Q_SLOTS:
625+ void
626+ connectionIdChanged(const QString& connectionId)
627+ {
628+ m_item->setLabel(connectionId);
629+ }
630+
631+public:
632+ EthernetConnectionItem& p;
633+
634+ AvailableConnection::SPtr m_connection;
635+
636+ MenuItem::Ptr m_item;
637+};
638+
639+EthernetConnectionItem::EthernetConnectionItem(
640+ AvailableConnection::SPtr connection, Action::Ptr action) :
641+ d(new Private(*this))
642+{
643+ d->m_connection = connection;
644+ connect(d->m_connection.get(), &AvailableConnection::connectionIdChanged,
645+ d.get(), &Private::connectionIdChanged);
646+
647+ d->m_item = make_shared<MenuItem>(d->m_connection->connectionId());
648+ d->m_item->setActionAndTargetValue(
649+ "indicator." + action->name(),
650+ TypedVariant<string>(connection->connectionUuid().toStdString()));
651+}
652+
653+MenuItem::Ptr
654+EthernetConnectionItem::menuItem()
655+{
656+ return d->m_item;
657+}
658+
659+#include "ethernet-connection-item.moc"
660+
661
662=== added file 'src/indicator/menuitems/ethernet-connection-item.h'
663--- src/indicator/menuitems/ethernet-connection-item.h 1970-01-01 00:00:00 +0000
664+++ src/indicator/menuitems/ethernet-connection-item.h 2016-12-05 18:14:38 +0000
665@@ -0,0 +1,46 @@
666+/*
667+ * Copyright (C) 2016 Canonical, Ltd.
668+ *
669+ * This program is free software: you can redistribute it and/or modify it
670+ * under the terms of the GNU General Public License version 3, as published
671+ * by the Free Software Foundation.
672+ *
673+ * This program is distributed in the hope that it will be useful, but
674+ * WITHOUT ANY WARRANTY; without even the implied warranties of
675+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
676+ * PURPOSE. See the GNU General Public License for more details.
677+ *
678+ * You should have received a copy of the GNU General Public License along
679+ * with this program. If not, see <http://www.gnu.org/licenses/>.
680+ *
681+ * Authors:
682+ * Pete Woods <pete.woods@canonical.com>
683+ */
684+
685+#pragma once
686+
687+#include <menuitems/item.h>
688+#include <menumodel-cpp/menu-item.h>
689+#include <nmofono/connection/available-connection.h>
690+
691+#include <unity/util/DefinesPtrs.h>
692+
693+#include <QObject>
694+#include <QString>
695+
696+class EthernetConnectionItem : public Item
697+{
698+
699+public:
700+ UNITY_DEFINES_PTRS(EthernetConnectionItem);
701+
702+ EthernetConnectionItem() = delete;
703+ ~EthernetConnectionItem() = default;
704+ EthernetConnectionItem(nmofono::connection::AvailableConnection::SPtr connection, Action::Ptr action);
705+
706+ virtual MenuItem::Ptr menuItem();
707+
708+private:
709+ class Private;
710+ std::shared_ptr<Private> d;
711+};
712
713=== added file 'src/indicator/menuitems/ethernet-item.cpp'
714--- src/indicator/menuitems/ethernet-item.cpp 1970-01-01 00:00:00 +0000
715+++ src/indicator/menuitems/ethernet-item.cpp 2016-12-05 18:14:38 +0000
716@@ -0,0 +1,103 @@
717+/*
718+ * Copyright (C) 2016 Canonical, Ltd.
719+ *
720+ * This program is free software: you can redistribute it and/or modify it
721+ * under the terms of the GNU General Public License version 3, as published
722+ * by the Free Software Foundation.
723+ *
724+ * This program is distributed in the hope that it will be useful, but
725+ * WITHOUT ANY WARRANTY; without even the implied warranties of
726+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
727+ * PURPOSE. See the GNU General Public License for more details.
728+ *
729+ * You should have received a copy of the GNU General Public License along
730+ * with this program. If not, see <http://www.gnu.org/licenses/>.
731+ *
732+ * Authors:
733+ * Pete Woods <pete.woods@canonical.com>
734+ */
735+
736+#include "ethernet-item.h"
737+#include <QDebug>
738+
739+using namespace std;
740+
741+class EthernetItem::Private : public QObject
742+{
743+Q_OBJECT
744+
745+public Q_SLOTS:
746+ void
747+ actionActivated(const Variant&)
748+ {
749+ // Remember that the GAction was only activated, and hasn't had its state changed.
750+ bool newAutoConnectState = !(m_actionConnected->state().as<bool>());
751+ Q_EMIT p.autoConnectChanged(newAutoConnectState);
752+ }
753+
754+public:
755+ Private(EthernetItem& parent) :
756+ p(parent)
757+ {
758+ }
759+
760+ EthernetItem& p;
761+
762+ Action::Ptr m_actionConnected;
763+ Action::Ptr m_actionStatusLabel;
764+
765+ MenuItem::Ptr m_item;
766+};
767+
768+EthernetItem::EthernetItem(unsigned int id)
769+{
770+ d.reset(new Private(*this));
771+
772+ QString actionIdBase = "ethernet." + QString::number(id);
773+
774+ QString statusConnectedActionId = actionIdBase;
775+ QString statusLabelActionId = actionIdBase + "::status-label";
776+
777+ d->m_actionConnected = make_shared<Action>(statusConnectedActionId, nullptr, TypedVariant<bool>(false));
778+ d->m_actionStatusLabel = make_shared<Action>(statusLabelActionId, nullptr, TypedVariant<string>());
779+ m_actionGroup->add(d->m_actionConnected);
780+ m_actionGroup->add(d->m_actionStatusLabel);
781+
782+ connect(d->m_actionConnected.get(), &Action::activated, d.get(), &Private::actionActivated);
783+
784+ d->m_item = make_shared<MenuItem>();
785+ d->m_item->setAction("indicator." + statusConnectedActionId);
786+
787+ d->m_item->setAttribute("x-canonical-type", TypedVariant<string>("com.canonical.indicator.switch"));
788+ d->m_item->setAttribute("x-canonical-subtitle-action", TypedVariant<string>("indicator." + statusLabelActionId.toStdString()));
789+}
790+
791+EthernetItem::~EthernetItem()
792+{
793+}
794+
795+void
796+EthernetItem::setAutoConnect(bool autoConnect)
797+{
798+ d->m_actionConnected->setState(TypedVariant<bool>(autoConnect));
799+}
800+
801+void
802+EthernetItem::setStatusText(const QString &value)
803+{
804+ d->m_actionStatusLabel->setState(TypedVariant<string>(value.toStdString()));
805+}
806+
807+void
808+EthernetItem::setName(const QString &value)
809+{
810+ d->m_item->setLabel(value);
811+}
812+
813+MenuItem::Ptr
814+EthernetItem::menuItem()
815+{
816+ return d->m_item;
817+}
818+
819+#include "ethernet-item.moc"
820
821=== added file 'src/indicator/menuitems/ethernet-item.h'
822--- src/indicator/menuitems/ethernet-item.h 1970-01-01 00:00:00 +0000
823+++ src/indicator/menuitems/ethernet-item.h 2016-12-05 18:14:38 +0000
824@@ -0,0 +1,54 @@
825+/*
826+ * Copyright (C) 2016 Canonical, Ltd.
827+ *
828+ * This program is free software: you can redistribute it and/or modify it
829+ * under the terms of the GNU General Public License version 3, as published
830+ * by the Free Software Foundation.
831+ *
832+ * This program is distributed in the hope that it will be useful, but
833+ * WITHOUT ANY WARRANTY; without even the implied warranties of
834+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
835+ * PURPOSE. See the GNU General Public License for more details.
836+ *
837+ * You should have received a copy of the GNU General Public License along
838+ * with this program. If not, see <http://www.gnu.org/licenses/>.
839+ *
840+ * Authors:
841+ * Pete Woods <pete.woods@canonical.com>
842+ */
843+
844+#pragma once
845+
846+#include "item.h"
847+#include "menumodel-cpp/action.h"
848+#include "menumodel-cpp/menu-item.h"
849+#include "menumodel-cpp/gio-helpers/variant.h"
850+
851+#include <functional>
852+#include <vector>
853+
854+class EthernetItem : public Item
855+{
856+ Q_OBJECT
857+
858+ class Private;
859+ std::unique_ptr<Private> d;
860+
861+public:
862+ typedef std::shared_ptr<EthernetItem> Ptr;
863+
864+ EthernetItem(unsigned int id);
865+ virtual ~EthernetItem();
866+
867+ virtual MenuItem::Ptr menuItem();
868+
869+public Q_SLOTS:
870+ void setStatusText(const QString &value);
871+
872+ void setName(const QString &value);
873+
874+ void setAutoConnect(bool autoConnect);
875+
876+Q_SIGNALS:
877+ void autoConnectChanged(bool autoconnect);
878+};
879
880=== added file 'src/indicator/menuitems/ethernet-link-item.cpp'
881--- src/indicator/menuitems/ethernet-link-item.cpp 1970-01-01 00:00:00 +0000
882+++ src/indicator/menuitems/ethernet-link-item.cpp 2016-12-05 18:14:38 +0000
883@@ -0,0 +1,109 @@
884+/*
885+ * Copyright (C) 2016 Canonical, Ltd.
886+ *
887+ * This program is free software: you can redistribute it and/or modify it
888+ * under the terms of the GNU General Public License version 3, as published
889+ * by the Free Software Foundation.
890+ *
891+ * This program is distributed in the hope that it will be useful, but
892+ * WITHOUT ANY WARRANTY; without even the implied warranties of
893+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
894+ * PURPOSE. See the GNU General Public License for more details.
895+ *
896+ * You should have received a copy of the GNU General Public License along
897+ * with this program. If not, see <http://www.gnu.org/licenses/>.
898+ *
899+ * Author: Pete Woods <pete.woods@canonical.com>
900+ */
901+
902+#include <menuitems/ethernet-item.h>
903+#include <util/localisation.h>
904+#include <icons.h>
905+#include <menuitems/ethernet-link-item.h>
906+
907+#include <QDebug>
908+
909+using namespace std;
910+using namespace nmofono;
911+using namespace nmofono::ethernet;
912+
913+class EthernetLinkItem::Private: public QObject
914+{
915+ Q_OBJECT
916+
917+public Q_SLOTS:
918+ void
919+ statusUpdated(Link::Status status)
920+ {
921+ const static QMap<Link::Status, QString> statusMap{
922+ {Link::Status::connected, _("Connected")},
923+ {Link::Status::connecting, _("Connecting")},
924+ {Link::Status::disabled, _("Disabled")},
925+ {Link::Status::offline, _("Disconnected")},
926+ {Link::Status::online, _("Online")},
927+ {Link::Status::failed, _("Failed")},
928+ };
929+
930+ m_item->setStatusText(statusMap[status]);
931+ }
932+
933+ void
934+ updateIdentifierText()
935+ {
936+ if (m_showInterface)
937+ {
938+ m_item->setName(
939+ QString(_("Ethernet (%1)")).arg(m_ethernetLink->name()));
940+ }
941+ else
942+ {
943+ m_item->setName(QString(_("Ethernet")));
944+ }
945+ }
946+
947+public:
948+ EthernetLink::SPtr m_ethernetLink;
949+
950+ EthernetItem::Ptr m_item;
951+
952+ bool m_showInterface = true;
953+};
954+
955+EthernetLinkItem::EthernetLinkItem(EthernetLink::SPtr ethernetLink) :
956+ d(new Private)
957+{
958+ d->m_ethernetLink = ethernetLink;
959+
960+ d->m_item = make_shared<EthernetItem>(ethernetLink->id());
961+
962+ m_actionGroupMerger->add(d->m_item->actionGroup());
963+
964+ connect(d->m_ethernetLink.get(), &Link::statusUpdated, d.get(),
965+ &Private::statusUpdated);
966+ d->statusUpdated(d->m_ethernetLink->status());
967+
968+ connect(d->m_ethernetLink.get(), &Link::nameUpdated, d.get(),
969+ &Private::updateIdentifierText);
970+ d->updateIdentifierText();
971+
972+ connect(d->m_ethernetLink.get(), &EthernetLink::autoConnectChanged,
973+ d->m_item.get(), &EthernetItem::setAutoConnect);
974+ connect(d->m_item.get(), &EthernetItem::autoConnectChanged,
975+ d->m_ethernetLink.get(), &EthernetLink::setAutoConnect);
976+ d->m_item->setAutoConnect(d->m_ethernetLink->autoConnect());
977+}
978+
979+MenuItem::Ptr
980+EthernetLinkItem::menuItem()
981+{
982+ return d->m_item->menuItem();
983+}
984+
985+void
986+EthernetLinkItem::setShowInterface(bool showInterface)
987+{
988+ d->m_showInterface = showInterface;
989+ d->updateIdentifierText();
990+}
991+
992+#include "ethernet-link-item.moc"
993
994=== added file 'src/indicator/menuitems/ethernet-link-item.h'
995--- src/indicator/menuitems/ethernet-link-item.h 1970-01-01 00:00:00 +0000
996+++ src/indicator/menuitems/ethernet-link-item.h 2016-12-05 18:14:38 +0000
997@@ -0,0 +1,40 @@
998+/*
999+ * Copyright (C) 2016 Canonical, Ltd.
1000+ *
1001+ * This program is free software: you can redistribute it and/or modify it
1002+ * under the terms of the GNU General Public License version 3, as published
1003+ * by the Free Software Foundation.
1004+ *
1005+ * This program is distributed in the hope that it will be useful, but
1006+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1007+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1008+ * PURPOSE. See the GNU General Public License for more details.
1009+ *
1010+ * You should have received a copy of the GNU General Public License along
1011+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1012+ *
1013+ * Author: Pete Woods <pete.woods@canonical.com>
1014+ */
1015+
1016+#pragma once
1017+
1018+#include <menuitems/item.h>
1019+#include <nmofono/ethernet/ethernet-link.h>
1020+
1021+#include <unity/util/DefinesPtrs.h>
1022+
1023+class EthernetLinkItem : public Item
1024+{
1025+ class Private;
1026+ std::shared_ptr<Private> d;
1027+
1028+public:
1029+ UNITY_DEFINES_PTRS(EthernetLinkItem);
1030+
1031+ EthernetLinkItem(nmofono::ethernet::EthernetLink::SPtr link);
1032+ ~EthernetLinkItem() = default;
1033+
1034+ MenuItem::Ptr menuItem() override;
1035+
1036+ void setShowInterface(bool);
1037+};
1038
1039=== modified file 'src/indicator/menuitems/section.h'
1040--- src/indicator/menuitems/section.h 2015-04-24 08:47:08 +0000
1041+++ src/indicator/menuitems/section.h 2016-12-05 18:14:38 +0000
1042@@ -23,6 +23,8 @@
1043 #include "menumodel-cpp/action-group.h"
1044 #include "menumodel-cpp/menu-model.h"
1045
1046+#include <unity/util/DefinesPtrs.h>
1047+
1048 class Section
1049 {
1050 public:
1051
1052=== modified file 'src/indicator/menuitems/wifi-link-item.cpp'
1053--- src/indicator/menuitems/wifi-link-item.cpp 2015-10-06 10:14:57 +0000
1054+++ src/indicator/menuitems/wifi-link-item.cpp 2016-12-05 18:14:38 +0000
1055@@ -42,7 +42,7 @@
1056 public:
1057 ActionGroupMerger::Ptr m_actionGroupMerger;
1058
1059- wifi::WifiLink::Ptr m_link;
1060+ wifi::WifiLink::SPtr m_link;
1061
1062 /// @todo do something with me...
1063 Action::Ptr m_actionBusy;
1064@@ -73,7 +73,7 @@
1065
1066 Private() = delete;
1067 ~Private() {}
1068- Private(wifi::WifiLink::Ptr link)
1069+ Private(wifi::WifiLink::SPtr link)
1070 : m_link {link}
1071 {
1072 m_actionGroupMerger = std::make_shared<ActionGroupMerger>();
1073@@ -196,7 +196,7 @@
1074 };
1075
1076
1077-WifiLinkItem::WifiLinkItem(wifi::WifiLink::Ptr link)
1078+WifiLinkItem::WifiLinkItem(wifi::WifiLink::SPtr link)
1079 : d{new Private(link)}
1080 {
1081 }
1082
1083=== modified file 'src/indicator/menuitems/wifi-link-item.h'
1084--- src/indicator/menuitems/wifi-link-item.h 2015-04-24 08:47:08 +0000
1085+++ src/indicator/menuitems/wifi-link-item.h 2016-12-05 18:14:38 +0000
1086@@ -31,7 +31,7 @@
1087 public:
1088 typedef std::shared_ptr<WifiLinkItem> Ptr;
1089
1090- WifiLinkItem(nmofono::wifi::WifiLink::Ptr link);
1091+ WifiLinkItem(nmofono::wifi::WifiLink::SPtr link);
1092 virtual ~WifiLinkItem();
1093
1094 virtual MenuItem::Ptr menuItem();
1095
1096=== modified file 'src/indicator/menuitems/wwan-link-item.h'
1097--- src/indicator/menuitems/wwan-link-item.h 2015-04-24 08:47:08 +0000
1098+++ src/indicator/menuitems/wwan-link-item.h 2016-12-05 18:14:38 +0000
1099@@ -28,7 +28,8 @@
1100 std::shared_ptr<Private> d;
1101
1102 public:
1103- typedef std::shared_ptr<WwanLinkItem> Ptr;
1104+ UNITY_DEFINES_PTRS(WwanLinkItem);
1105+
1106 WwanLinkItem(nmofono::wwan::Modem::Ptr, nmofono::Manager::Ptr manager);
1107 virtual ~WwanLinkItem();
1108
1109
1110=== modified file 'src/indicator/nmofono/connection/active-connection-manager.cpp'
1111--- src/indicator/nmofono/connection/active-connection-manager.cpp 2016-05-26 13:51:39 +0000
1112+++ src/indicator/nmofono/connection/active-connection-manager.cpp 2016-12-05 18:14:38 +0000
1113@@ -109,6 +109,11 @@
1114 return d->m_connections.values().toSet();
1115 }
1116
1117+ActiveConnection::SPtr ActiveConnectionManager::connection(const QDBusObjectPath& path) const
1118+{
1119+ return d->m_connections.value(path);
1120+}
1121+
1122 bool ActiveConnectionManager::deactivate(ActiveConnection::SPtr activeConnection)
1123 {
1124 auto reply = d->m_manager->DeactivateConnection(activeConnection->path());
1125
1126=== modified file 'src/indicator/nmofono/connection/active-connection-manager.h'
1127--- src/indicator/nmofono/connection/active-connection-manager.h 2015-10-06 10:19:30 +0000
1128+++ src/indicator/nmofono/connection/active-connection-manager.h 2016-12-05 18:14:38 +0000
1129@@ -18,6 +18,7 @@
1130
1131 #pragma once
1132
1133+#include <QDBusObjectPath>
1134 #include <QObject>
1135 #include <QSet>
1136
1137@@ -41,6 +42,8 @@
1138
1139 QSet<ActiveConnection::SPtr> connections() const;
1140
1141+ ActiveConnection::SPtr connection(const QDBusObjectPath& path) const;
1142+
1143 bool deactivate(ActiveConnection::SPtr activeConnection);
1144
1145 Q_SIGNALS:
1146
1147=== modified file 'src/indicator/nmofono/connection/active-connection.cpp'
1148--- src/indicator/nmofono/connection/active-connection.cpp 2015-12-17 10:41:14 +0000
1149+++ src/indicator/nmofono/connection/active-connection.cpp 2016-12-05 18:14:38 +0000
1150@@ -62,6 +62,10 @@
1151 {
1152 setConnectionPath(qvariant_cast<QDBusObjectPath>(value));
1153 }
1154+ else if (property == "SpecificObject")
1155+ {
1156+ setSpecificObject(qvariant_cast<QDBusObjectPath>(value));
1157+ }
1158 }
1159 }
1160
1161@@ -121,6 +125,17 @@
1162 Q_EMIT p.connectionPathChanged(m_connectionPath);
1163 }
1164
1165+ void setSpecificObject(const QDBusObjectPath& specificObject)
1166+ {
1167+ if (specificObject == m_specificObject)
1168+ {
1169+ return;
1170+ }
1171+
1172+ m_specificObject = specificObject;
1173+ Q_EMIT p.specificObjectChanged(m_specificObject);
1174+ }
1175+
1176 public:
1177 ActiveConnection& p;
1178
1179@@ -128,6 +143,8 @@
1180
1181 ActiveVpnConnection::SPtr m_activeVpnConnection;
1182
1183+ QString m_uuid;
1184+
1185 QString m_id;
1186
1187 QString m_type;
1188@@ -135,6 +152,8 @@
1189 State m_state = State::unknown;
1190
1191 QDBusObjectPath m_connectionPath;
1192+
1193+ QDBusObjectPath m_specificObject;
1194 };
1195
1196 ActiveConnection::ActiveConnection(const QDBusObjectPath& path, const QDBusConnection& systemConnection) :
1197@@ -142,10 +161,12 @@
1198 {
1199 d->m_activeConnection = make_shared<OrgFreedesktopNetworkManagerConnectionActiveInterface>(NM_DBUS_SERVICE, path.path(), systemConnection);
1200
1201+ d->m_uuid = d->m_activeConnection->uuid();
1202 d->setId(d->m_activeConnection->id());
1203 d->setType(d->m_activeConnection->type());
1204 d->setState(static_cast<State>(d->m_activeConnection->state()));
1205 d->setConnectionPath(d->m_activeConnection->connection());
1206+ d->setSpecificObject(d->m_activeConnection->specificObject());
1207
1208 connect(d->m_activeConnection.get(), &OrgFreedesktopNetworkManagerConnectionActiveInterface::PropertiesChanged, d.get(), &Priv::propertiesChanged);
1209 }
1210@@ -155,6 +176,11 @@
1211 return d->m_id;
1212 }
1213
1214+QString ActiveConnection::uuid() const
1215+{
1216+ return d->m_uuid;
1217+}
1218+
1219 QString ActiveConnection::type() const
1220 {
1221 return d->m_type;
1222@@ -170,6 +196,11 @@
1223 return d->m_connectionPath;
1224 }
1225
1226+QDBusObjectPath ActiveConnection::specificObject() const
1227+{
1228+ return d->m_specificObject;
1229+}
1230+
1231 QDBusObjectPath ActiveConnection::path() const
1232 {
1233 return QDBusObjectPath(d->m_activeConnection->path());
1234
1235=== modified file 'src/indicator/nmofono/connection/active-connection.h'
1236--- src/indicator/nmofono/connection/active-connection.h 2015-12-17 10:41:14 +0000
1237+++ src/indicator/nmofono/connection/active-connection.h 2016-12-05 18:14:38 +0000
1238@@ -54,12 +54,16 @@
1239
1240 QString id() const;
1241
1242+ QString uuid() const;
1243+
1244 QString type() const;
1245
1246 State state() const;
1247
1248 QDBusObjectPath connectionPath() const;
1249
1250+ QDBusObjectPath specificObject() const;
1251+
1252 QDBusObjectPath path() const;
1253
1254 ActiveVpnConnection::SPtr vpnConnection() const;
1255@@ -73,6 +77,8 @@
1256
1257 void connectionPathChanged(const QDBusObjectPath& connectionPath);
1258
1259+ void specificObjectChanged(const QDBusObjectPath& specificObject);
1260+
1261 protected:
1262 class Priv;
1263 std::shared_ptr<Priv> d;
1264
1265=== added file 'src/indicator/nmofono/connection/available-connection.cpp'
1266--- src/indicator/nmofono/connection/available-connection.cpp 1970-01-01 00:00:00 +0000
1267+++ src/indicator/nmofono/connection/available-connection.cpp 2016-12-05 18:14:38 +0000
1268@@ -0,0 +1,96 @@
1269+/*
1270+ * Copyright (C) 2015 Canonical, Ltd.
1271+ *
1272+ * This program is free software: you can redistribute it and/or modify it
1273+ * under the terms of the GNU General Public License version 3, as published
1274+ * by the Free Software Foundation.
1275+ *
1276+ * This program is distributed in the hope that it will be useful, but
1277+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1278+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1279+ * PURPOSE. See the GNU General Public License for more details.
1280+ *
1281+ * You should have received a copy of the GNU General Public License along
1282+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1283+ *
1284+ * Author: Pete Woods <pete.woods@canonical.com>
1285+ */
1286+
1287+#include <nmofono/connection/available-connection.h>
1288+#include <NetworkManagerSettingsConnectionInterface.h>
1289+
1290+using namespace std;
1291+
1292+namespace nmofono
1293+{
1294+namespace connection
1295+{
1296+
1297+class AvailableConnection::Priv: public QObject
1298+{
1299+ Q_OBJECT
1300+
1301+public:
1302+ Priv(AvailableConnection& parent) :
1303+ p(parent)
1304+ {
1305+ }
1306+
1307+public Q_SLOTS:
1308+ void updated()
1309+ {
1310+ QVariantDictMap settings = m_connectionInterface->GetSettings();
1311+
1312+ auto connection = settings.value("connection");
1313+ m_connectionUuid = connection.value("uuid").toString();
1314+ setConnectionId(connection.value("id").toString());
1315+ }
1316+
1317+ void setConnectionId(const QString& connectionId)
1318+ {
1319+ if (connectionId == m_connectionId)
1320+ {
1321+ return;
1322+ }
1323+
1324+ m_connectionId = connectionId;
1325+ Q_EMIT p.connectionIdChanged(m_connectionId);
1326+ }
1327+
1328+public:
1329+ AvailableConnection& p;
1330+
1331+ shared_ptr<OrgFreedesktopNetworkManagerSettingsConnectionInterface> m_connectionInterface;
1332+
1333+ QString m_connectionUuid;
1334+
1335+ QString m_connectionId;
1336+};
1337+
1338+AvailableConnection::AvailableConnection(const QDBusObjectPath& path, const QDBusConnection& systemConnection) :
1339+ d(new Priv(*this))
1340+{
1341+ d->m_connectionInterface = make_shared<OrgFreedesktopNetworkManagerSettingsConnectionInterface>(NM_DBUS_SERVICE, path.path(), systemConnection);
1342+ connect(d->m_connectionInterface.get(), &OrgFreedesktopNetworkManagerSettingsConnectionInterface::Updated, d.get(), &Priv::updated);
1343+ d->updated();
1344+}
1345+
1346+QDBusObjectPath AvailableConnection::path() const
1347+{
1348+ return QDBusObjectPath(d->m_connectionInterface->path());
1349+}
1350+
1351+QString AvailableConnection::connectionUuid() const
1352+{
1353+ return d->m_connectionUuid;
1354+}
1355+
1356+QString AvailableConnection::connectionId() const
1357+{
1358+ return d->m_connectionId;
1359+}
1360+
1361+}
1362+}
1363+
1364+#include "available-connection.moc"
1365
1366=== added file 'src/indicator/nmofono/connection/available-connection.h'
1367--- src/indicator/nmofono/connection/available-connection.h 1970-01-01 00:00:00 +0000
1368+++ src/indicator/nmofono/connection/available-connection.h 2016-12-05 18:14:38 +0000
1369@@ -0,0 +1,68 @@
1370+/*
1371+ * Copyright (C) 2015 Canonical, Ltd.
1372+ *
1373+ * This program is free software: you can redistribute it and/or modify it
1374+ * under the terms of the GNU General Public License version 3, as published
1375+ * by the Free Software Foundation.
1376+ *
1377+ * This program is distributed in the hope that it will be useful, but
1378+ * WITHOUT ANY WARRANTY; without even the implied warranties of
1379+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
1380+ * PURPOSE. See the GNU General Public License for more details.
1381+ *
1382+ * You should have received a copy of the GNU General Public License along
1383+ * with this program. If not, see <http://www.gnu.org/licenses/>.
1384+ *
1385+ * Author: Pete Woods <pete.woods@canonical.com>
1386+ */
1387+
1388+#pragma once
1389+
1390+#include <QDBusConnection>
1391+#include <QDBusObjectPath>
1392+#include <QObject>
1393+
1394+#include <unity/util/DefinesPtrs.h>
1395+#include <NetworkManager.h>
1396+
1397+namespace nmofono
1398+{
1399+namespace ethernet
1400+{
1401+class EthernetLink;
1402+}
1403+
1404+namespace connection
1405+{
1406+
1407+class AvailableConnection: public QObject
1408+{
1409+ Q_OBJECT
1410+
1411+public:
1412+ UNITY_DEFINES_PTRS(AvailableConnection);
1413+
1414+ AvailableConnection(const QDBusObjectPath& path, const QDBusConnection& systemConnection);
1415+
1416+ ~AvailableConnection() = default;
1417+
1418+ QDBusObjectPath path() const;
1419+
1420+ QString connectionId() const;
1421+
1422+ QString connectionUuid() const;
1423+
1424+Q_SIGNALS:
1425+ void connectionIdChanged(const QString &);
1426+
1427+ void connectionUuidChanged(const QString &);
1428+
1429+protected:
1430+ class Priv;
1431+ std::shared_ptr<Priv> d;
1432+
1433+ friend ethernet::EthernetLink;
1434+};
1435+
1436+}
1437+}
1438
1439=== added directory 'src/indicator/nmofono/ethernet'
1440=== added file 'src/indicator/nmofono/ethernet/ethernet-link.cpp'
1441--- src/indicator/nmofono/ethernet/ethernet-link.cpp 1970-01-01 00:00:00 +0000
1442+++ src/indicator/nmofono/ethernet/ethernet-link.cpp 2016-12-05 18:14:38 +0000
1443@@ -0,0 +1,379 @@
1444+/*
1445+ * Copyright © 2016 Canonical Ltd.
1446+ *
1447+ * This program is free software: you can redistribute it and/or modify it
1448+ * under the terms of the GNU Lesser General Public License version 3,
1449+ * as published by the Free Software Foundation.
1450+ *
1451+ * This program is distributed in the hope that it will be useful,
1452+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1453+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1454+ * GNU Lesser General Public License for more details.
1455+ *
1456+ * You should have received a copy of the GNU Lesser General Public License
1457+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1458+ *
1459+ * Authors:
1460+ * Pete Woods <pete.woods@canonical.com>
1461+ */
1462+
1463+#include <nmofono/connection/available-connection.h>
1464+#include <nmofono/ethernet/ethernet-link.h>
1465+#include <util/dbus-property-cache.h>
1466+#include <util/localisation.h>
1467+
1468+#include <NetworkManagerDeviceWiredInterface.h>
1469+
1470+#include <NetworkManager.h>
1471+#include <iostream>
1472+
1473+using namespace std;
1474+using namespace nmofono;
1475+using namespace nmofono::connection;
1476+
1477+namespace nmofono
1478+{
1479+namespace ethernet
1480+{
1481+
1482+struct EthernetLink::Private : public QObject
1483+{
1484+Q_OBJECT
1485+
1486+public:
1487+ Private(EthernetLink& parent) :
1488+ p(parent)
1489+ {
1490+ }
1491+
1492+public Q_SLOTS:
1493+ void
1494+ updateStatus(uint new_state, uint, uint)
1495+ {
1496+ Status status = Status::disabled;
1497+
1498+ switch (new_state)
1499+ {
1500+ case NM_DEVICE_STATE_DISCONNECTED:
1501+ case NM_DEVICE_STATE_DEACTIVATING:
1502+ case NM_DEVICE_STATE_UNMANAGED:
1503+ case NM_DEVICE_STATE_UNAVAILABLE:
1504+ status = Status::offline;
1505+ break;
1506+ case NM_DEVICE_STATE_UNKNOWN:
1507+ case NM_DEVICE_STATE_FAILED:
1508+ status = Status::failed;
1509+ break;
1510+ case NM_DEVICE_STATE_PREPARE:
1511+ case NM_DEVICE_STATE_CONFIG:
1512+ case NM_DEVICE_STATE_NEED_AUTH:
1513+ case NM_DEVICE_STATE_IP_CONFIG:
1514+ case NM_DEVICE_STATE_IP_CHECK:
1515+ status = Status::connecting;
1516+ break;
1517+ case NM_DEVICE_STATE_SECONDARIES:
1518+ case NM_DEVICE_STATE_ACTIVATED:
1519+ status = Status::connected;
1520+ break;
1521+ }
1522+
1523+ setStatus(status);
1524+
1525+ updateActiveConnection();
1526+ }
1527+
1528+ void
1529+ updateAvailableConnections()
1530+ {
1531+ auto availableConnectionPaths = m_dev->availableConnections().toSet();
1532+ auto current(m_availableConnections.keys().toSet());
1533+
1534+ auto toRemove(current);
1535+ toRemove.subtract(availableConnectionPaths);
1536+
1537+ auto toAdd(availableConnectionPaths);
1538+ toAdd.subtract(current);
1539+
1540+ if (toAdd.isEmpty() && toRemove.isEmpty())
1541+ {
1542+ return;
1543+ }
1544+
1545+ for (auto connectionPath : toRemove)
1546+ {
1547+ m_availableConnections.take(connectionPath);
1548+ }
1549+
1550+ for (auto connectionPath : toAdd)
1551+ {
1552+ m_availableConnections[connectionPath] = make_shared<AvailableConnection>(connectionPath, m_dev->connection());
1553+ }
1554+
1555+ if (m_preferredConnection)
1556+ {
1557+ if (!m_availableConnections.contains(m_preferredConnection->path()))
1558+ {
1559+ setPreferredConnection(AvailableConnection::SPtr());
1560+ }
1561+ }
1562+
1563+ Q_EMIT p.availableConnectionsChanged();
1564+ }
1565+
1566+ void
1567+ updateActiveConnection()
1568+ {
1569+ auto activeConnectionPath = m_dev->activeConnection();
1570+ auto activeConnection = m_connectionManager->connection(activeConnectionPath);
1571+
1572+ bool foundActiveConnection = false;
1573+ if (activeConnection)
1574+ {
1575+ for (QMapIterator<QDBusObjectPath, AvailableConnection::SPtr> it(m_availableConnections); it.hasNext();)
1576+ {
1577+ it.next();
1578+
1579+ auto availableConnection(it.value());
1580+ if (availableConnection->connectionUuid() == activeConnection->uuid())
1581+ {
1582+ setPreferredConnection(availableConnection);
1583+ foundActiveConnection = true;
1584+ }
1585+ }
1586+ }
1587+
1588+ // If we couldn't find an active connection, we'll have to fall back to the first available one.
1589+ if (!m_preferredConnection && !foundActiveConnection && !m_availableConnections.isEmpty())
1590+ {
1591+ setPreferredConnection(m_availableConnections.first());
1592+ }
1593+ }
1594+
1595+ void
1596+ setPreferredConnection(AvailableConnection::SPtr availableConnection)
1597+ {
1598+ if (m_preferredConnection == availableConnection)
1599+ {
1600+ return;
1601+ }
1602+
1603+ m_preferredConnection = availableConnection;
1604+ Q_EMIT p.preferredConnectionChanged(m_preferredConnection);
1605+ }
1606+
1607+ void
1608+ setName(const QString& name)
1609+ {
1610+ if (m_name == name)
1611+ {
1612+ return;
1613+ }
1614+
1615+ m_name = name;
1616+ Q_EMIT p.nameUpdated(m_name);
1617+ }
1618+
1619+ void
1620+ setStatus(Status status)
1621+ {
1622+ if (m_status == status)
1623+ {
1624+ return;
1625+ }
1626+
1627+ m_status = status;
1628+ Q_EMIT p.statusUpdated(m_status);
1629+ }
1630+
1631+ void
1632+ setAutoConnect(bool autoConnect)
1633+ {
1634+ if (m_autoConnect == autoConnect)
1635+ {
1636+ return;
1637+ }
1638+
1639+ m_autoConnect = autoConnect;
1640+ Q_EMIT p.autoConnectChanged(m_autoConnect);
1641+ }
1642+
1643+ void
1644+ devicePropertyChanged(const QString& name, const QVariant& value)
1645+ {
1646+ if (name == "Autoconnect")
1647+ {
1648+ setAutoConnect(value.toBool());
1649+ }
1650+ }
1651+
1652+public:
1653+ EthernetLink& p;
1654+
1655+ shared_ptr<OrgFreedesktopNetworkManagerDeviceInterface> m_dev;
1656+
1657+ shared_ptr<OrgFreedesktopNetworkManagerInterface> m_nm;
1658+
1659+ shared_ptr<OrgFreedesktopNetworkManagerSettingsInterface> m_settings;
1660+
1661+ shared_ptr<OrgFreedesktopNetworkManagerDeviceWiredInterface> m_wired;
1662+
1663+ shared_ptr<util::DBusPropertyCache> m_devicePropertyCache;
1664+
1665+ ActiveConnectionManager::SPtr m_connectionManager;
1666+
1667+ QMap<QDBusObjectPath, AvailableConnection::SPtr> m_availableConnections;
1668+
1669+ AvailableConnection::SPtr m_preferredConnection;
1670+
1671+ QString m_name;
1672+
1673+ Id m_id = 0;
1674+
1675+ Status m_status = Status::disabled;
1676+
1677+ bool m_autoConnect = false;
1678+};
1679+
1680+EthernetLink::EthernetLink(shared_ptr<OrgFreedesktopNetworkManagerDeviceInterface> dev, shared_ptr<OrgFreedesktopNetworkManagerInterface> nm, shared_ptr<OrgFreedesktopNetworkManagerSettingsInterface> settings, ActiveConnectionManager::SPtr connectionManager) :
1681+ d(new Private(*this))
1682+{
1683+ d->m_dev = dev;
1684+ d->m_nm = nm;
1685+ d->m_settings = settings;
1686+ d->m_connectionManager = connectionManager;
1687+ d->m_devicePropertyCache = make_shared<util::DBusPropertyCache>(NM_DBUS_SERVICE, NM_DBUS_INTERFACE_DEVICE, dev->path(), dev->connection());
1688+ connect(d->m_devicePropertyCache.get(), &util::DBusPropertyCache::propertyChanged, d.get(), &Private::devicePropertyChanged);
1689+
1690+ d->m_wired = make_shared<OrgFreedesktopNetworkManagerDeviceWiredInterface>(NM_DBUS_SERVICE, dev->path(), dev->connection());
1691+
1692+ // This regular expression extracts the number from the end of the DBus path
1693+ static QRegularExpression re("^[^\\d]+(\\d+)$");
1694+ auto match = re.match(d->m_dev->path());
1695+ d->m_id = match.captured(1).toUInt();
1696+ d->setName(d->m_dev->interface());
1697+
1698+ connect(d->m_dev.get(), &OrgFreedesktopNetworkManagerDeviceInterface::StateChanged, d.get(), &Private::updateStatus);
1699+ connect(d->m_connectionManager.get(), &ActiveConnectionManager::connectionsChanged, d.get(), &Private::updateActiveConnection);
1700+ connect(d->m_settings.get(), &OrgFreedesktopNetworkManagerSettingsInterface::ConnectionRemoved, d.get(), &Private::updateAvailableConnections);
1701+ connect(d->m_settings.get(), &OrgFreedesktopNetworkManagerSettingsInterface::NewConnection, d.get(), &Private::updateAvailableConnections);
1702+
1703+ d->updateAvailableConnections();
1704+ d->updateStatus(d->m_dev->state(), 0, 0);
1705+ d->setAutoConnect(d->m_devicePropertyCache->get("Autoconnect").toBool());
1706+}
1707+
1708+EthernetLink::~EthernetLink()
1709+{
1710+}
1711+
1712+Link::Type
1713+EthernetLink::type() const
1714+{
1715+ return Type::ethernet;
1716+}
1717+
1718+uint32_t
1719+EthernetLink::characteristics() const
1720+{
1721+ return Characteristics::empty;
1722+}
1723+
1724+Link::Status
1725+EthernetLink::status() const
1726+{
1727+ return d->m_status;
1728+}
1729+
1730+Link::Id
1731+EthernetLink::id() const
1732+{
1733+ return d->m_id;
1734+}
1735+
1736+QString
1737+EthernetLink::name() const
1738+{
1739+ return d->m_name;
1740+}
1741+
1742+QList<AvailableConnection::SPtr>
1743+EthernetLink::availableConnections() const
1744+{
1745+ return d->m_availableConnections.values();
1746+}
1747+
1748+AvailableConnection::SPtr
1749+EthernetLink::preferredConnection() const
1750+{
1751+ return d->m_preferredConnection;
1752+}
1753+
1754+bool
1755+EthernetLink::autoConnect() const
1756+{
1757+ return d->m_autoConnect;
1758+}
1759+
1760+void
1761+EthernetLink::setAutoConnect(bool autoConnect)
1762+{
1763+ if (autoConnect)
1764+ {
1765+ if (d->m_preferredConnection)
1766+ {
1767+ auto reply = d->m_nm->ActivateConnection(d->m_preferredConnection->path(), QDBusObjectPath(d->m_dev->path()), QDBusObjectPath("/"));
1768+ reply.waitForFinished();
1769+ if (reply.isError())
1770+ {
1771+ qWarning() << reply.error().message();
1772+ }
1773+ }
1774+ d->m_dev->setAutoconnect(true);
1775+ }
1776+ else
1777+ {
1778+ d->m_dev->setAutoconnect(false);
1779+ auto reply = d->m_dev->Disconnect();
1780+ reply.waitForFinished();
1781+ if (reply.isError())
1782+ {
1783+ qWarning() << reply.error().message();
1784+ }
1785+ }
1786+
1787+ Q_EMIT autoConnectChanged(autoConnect);
1788+}
1789+
1790+void
1791+EthernetLink::setPreferredConnection(AvailableConnection::SPtr preferredConnection)
1792+{
1793+ if (d->m_preferredConnection == preferredConnection)
1794+ {
1795+ return;
1796+ }
1797+
1798+ d->m_preferredConnection = preferredConnection;
1799+
1800+ if (d->m_autoConnect && preferredConnection)
1801+ {
1802+ auto reply = d->m_nm->ActivateConnection(d->m_preferredConnection->path(), QDBusObjectPath(d->m_dev->path()), QDBusObjectPath("/"));
1803+ reply.waitForFinished();
1804+ if (reply.isError())
1805+ {
1806+ qWarning() << reply.error().message();
1807+ }
1808+ }
1809+
1810+ Q_EMIT preferredConnectionChanged(preferredConnection);
1811+}
1812+
1813+QDBusObjectPath
1814+EthernetLink::devicePath() const
1815+{
1816+ return QDBusObjectPath(d->m_dev->path());
1817+}
1818+
1819+}
1820+}
1821+
1822+#include "ethernet-link.moc"
1823
1824=== added file 'src/indicator/nmofono/ethernet/ethernet-link.h'
1825--- src/indicator/nmofono/ethernet/ethernet-link.h 1970-01-01 00:00:00 +0000
1826+++ src/indicator/nmofono/ethernet/ethernet-link.h 2016-12-05 18:14:38 +0000
1827@@ -0,0 +1,93 @@
1828+/*
1829+ * Copyright © 2016 Canonical Ltd.
1830+ *
1831+ * This program is free software: you can redistribute it and/or modify it
1832+ * under the terms of the GNU Lesser General Public License version 3,
1833+ * as published by the Free Software Foundation.
1834+ *
1835+ * This program is distributed in the hope that it will be useful,
1836+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1837+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1838+ * GNU Lesser General Public License for more details.
1839+ *
1840+ * You should have received a copy of the GNU Lesser General Public License
1841+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1842+ *
1843+ * Authors:
1844+ * Pete Woods <pete.woods@canonical.com>
1845+ */
1846+
1847+#pragma once
1848+
1849+#include <nmofono/link.h>
1850+#include <nmofono/connection/active-connection-manager.h>
1851+#include <nmofono/connection/available-connection.h>
1852+#include <NetworkManagerInterface.h>
1853+#include <NetworkManagerSettingsInterface.h>
1854+#include <NetworkManagerDeviceInterface.h>
1855+
1856+#include <unity/util/DefinesPtrs.h>
1857+
1858+#include <QSet>
1859+
1860+namespace nmofono {
1861+namespace ethernet {
1862+
1863+#ifndef CONNECTIVITY_CPP_EXPORT
1864+#define CONNECTIVITY_CPP_EXPORT __attribute ((visibility ("default")))
1865+#endif
1866+
1867+class CONNECTIVITY_CPP_EXPORT
1868+EthernetLink : public Link
1869+{
1870+ Q_OBJECT
1871+
1872+public:
1873+ UNITY_DEFINES_PTRS(EthernetLink);
1874+
1875+ EthernetLink(std::shared_ptr<OrgFreedesktopNetworkManagerDeviceInterface> dev,
1876+ std::shared_ptr<OrgFreedesktopNetworkManagerInterface> nm,
1877+ std::shared_ptr<OrgFreedesktopNetworkManagerSettingsInterface> settings,
1878+ nmofono::connection::ActiveConnectionManager::SPtr connectionManager);
1879+
1880+ EthernetLink() = delete;
1881+ EthernetLink(const EthernetLink&) = delete;
1882+ ~EthernetLink();
1883+
1884+ Type type() const;
1885+
1886+ std::uint32_t characteristics() const;
1887+
1888+ Status status() const;
1889+
1890+ Id id() const;
1891+
1892+ QString name() const;
1893+
1894+ QList<connection::AvailableConnection::SPtr> availableConnections() const;
1895+
1896+ connection::AvailableConnection::SPtr preferredConnection() const;
1897+
1898+ bool autoConnect() const;
1899+
1900+ QDBusObjectPath devicePath() const;
1901+
1902+public Q_SLOTS:
1903+ void setPreferredConnection(connection::AvailableConnection::SPtr availableConnection);
1904+
1905+ void setAutoConnect(bool autoConnect);
1906+
1907+Q_SIGNALS:
1908+ void availableConnectionsChanged();
1909+
1910+ void preferredConnectionChanged(connection::AvailableConnection::SPtr availableConnection);
1911+
1912+ void autoConnectChanged(bool autoconnect);
1913+
1914+protected:
1915+ class Private;
1916+ std::shared_ptr<Private> d;
1917+};
1918+
1919+}
1920+}
1921
1922=== modified file 'src/indicator/nmofono/link.h'
1923--- src/indicator/nmofono/link.h 2015-08-05 15:14:28 +0000
1924+++ src/indicator/nmofono/link.h 2016-12-05 18:14:38 +0000
1925@@ -22,6 +22,8 @@
1926 #include <memory>
1927 #include <QObject>
1928
1929+#include <unity/util/DefinesPtrs.h>
1930+
1931 namespace nmofono {
1932
1933 #ifndef CONNECTIVITY_CPP_EXPORT
1934@@ -34,7 +36,7 @@
1935 Q_OBJECT
1936
1937 public:
1938- typedef std::shared_ptr<Link> Ptr;
1939+ UNITY_DEFINES_PTRS(Link);
1940
1941 Link(const Link&) = delete;
1942 virtual ~Link() = default;
1943@@ -45,6 +47,7 @@
1944 /// @private
1945 enum class Type
1946 {
1947+ ethernet,
1948 wifi,
1949 wired,
1950 wwan,
1951@@ -60,7 +63,8 @@
1952 connected, // the link is up, but not fully configured yet
1953 // happens with wifi for example when captive portal
1954 // login is required
1955- online
1956+ online,
1957+ failed
1958 };
1959
1960 /**
1961@@ -116,6 +120,8 @@
1962
1963 void statusUpdated(Status);
1964
1965+ void nameUpdated(const QString& name);
1966+
1967 protected:
1968 /// @private
1969 Link() = default;
1970
1971=== modified file 'src/indicator/nmofono/manager-impl.cpp'
1972--- src/indicator/nmofono/manager-impl.cpp 2016-10-30 15:13:34 +0000
1973+++ src/indicator/nmofono/manager-impl.cpp 2016-12-05 18:14:38 +0000
1974@@ -20,13 +20,10 @@
1975
1976 #include <nmofono/manager-impl.h>
1977 #include <nmofono/connectivity-service-settings.h>
1978+#include <nmofono/ethernet/ethernet-link.h>
1979 #include <nmofono/wifi/wifi-link-impl.h>
1980 #include <nmofono/wwan/sim-manager.h>
1981-#include <NetworkManagerActiveConnectionInterface.h>
1982-#include <NetworkManagerDeviceInterface.h>
1983 #include <NetworkManagerInterface.h>
1984-#include <NetworkManagerSettingsInterface.h>
1985-#include <NetworkManagerSettingsConnectionInterface.h>
1986
1987 #define slots
1988 #include <qofono-qt5/qofonomanager.h>
1989@@ -61,7 +58,9 @@
1990 Manager& p;
1991
1992 shared_ptr<OrgFreedesktopNetworkManagerInterface> nm;
1993+ shared_ptr<OrgFreedesktopNetworkManagerSettingsInterface> m_settingsInterface;
1994 shared_ptr<QOfonoManager> m_ofono;
1995+ connection::ActiveConnectionManager::SPtr m_activeConnectionManager;
1996
1997 bool m_flightMode = true;
1998 bool m_unstoppableOperationHappening = false;
1999@@ -76,7 +75,7 @@
2000
2001 QList<QDBusObjectPath> m_nmDevices;
2002
2003- QSet<Link::Ptr> m_nmLinks;
2004+ QSet<Link::SPtr> m_nmLinks;
2005 QMap<QString, wwan::Modem::Ptr> m_ofonoLinks;
2006
2007 SimUnlockDialog::Ptr m_unlockDialog;
2008@@ -527,10 +526,14 @@
2009 ManagerImpl::ManagerImpl(notify::NotificationManager::SPtr notificationManager,
2010 KillSwitch::Ptr killSwitch,
2011 HotspotManager::SPtr hotspotManager,
2012+ connection::ActiveConnectionManager::SPtr activeConnectionManager,
2013 const QDBusConnection& systemConnection) :
2014 d(new ManagerImpl::Private(*this))
2015 {
2016 d->nm = make_shared<OrgFreedesktopNetworkManagerInterface>(NM_DBUS_SERVICE, NM_DBUS_PATH, systemConnection);
2017+ d->m_settingsInterface = make_shared<OrgFreedesktopNetworkManagerSettingsInterface>(
2018+ NM_DBUS_SERVICE, NM_DBUS_PATH_SETTINGS, systemConnection);
2019+ d->m_activeConnectionManager = activeConnectionManager;
2020
2021 d->m_unlockDialog = make_shared<SimUnlockDialog>(notificationManager);
2022 connect(d->m_unlockDialog.get(), &SimUnlockDialog::ready, d.get(), &Private::sim_unlock_ready);
2023@@ -720,7 +723,7 @@
2024
2025 d->m_statisticsMonitor->remove(path.path());
2026
2027- Link::Ptr toRemove;
2028+ Link::SPtr toRemove;
2029 for (auto dev : d->m_nmLinks)
2030 {
2031 auto wifiLink = dynamic_pointer_cast<wifi::WifiLinkImpl>(dev);
2032@@ -754,41 +757,55 @@
2033 }
2034 }
2035
2036- Link::Ptr link;
2037+ Link::SPtr link;
2038 try {
2039 auto dev = make_shared<OrgFreedesktopNetworkManagerDeviceInterface>(
2040 NM_DBUS_SERVICE, path.path(), d->nm->connection());
2041- if (dev->deviceType() == NM_DEVICE_TYPE_WIFI) {
2042- wifi::WifiLink::Ptr tmp = make_shared<wifi::WifiLinkImpl>(dev,
2043- d->nm,
2044- d->m_killSwitch);
2045-
2046- // We're not interested in showing access points
2047- if (tmp->name() != d->m_hotspotManager->interface())
2048- {
2049- tmp->setDisconnectWifi(d->m_hotspotManager->disconnectWifi());
2050- QObject::connect(d->m_hotspotManager.get(), &HotspotManager::disconnectWifiChanged,
2051- tmp.get(), &wifi::WifiLink::setDisconnectWifi);
2052-
2053- link = tmp;
2054- }
2055- }
2056- else if (dev->deviceType() == NM_DEVICE_TYPE_MODEM)
2057+ switch (dev->deviceType())
2058 {
2059- if (dev->driver() == "ofono")
2060- {
2061- for (const auto &modem : d->m_ofonoLinks)
2062- {
2063- if (modem->ofonoPath() == dev->udi())
2064+ case NM_DEVICE_TYPE_WIFI:
2065+ {
2066+ wifi::WifiLink::SPtr tmp = make_shared<wifi::WifiLinkImpl>(dev,
2067+ d->nm,
2068+ d->m_killSwitch,
2069+ d->m_activeConnectionManager);
2070+
2071+ // We're not interested in showing access points
2072+ if (tmp->name() != d->m_hotspotManager->interface())
2073+ {
2074+ tmp->setDisconnectWifi(d->m_hotspotManager->disconnectWifi());
2075+ QObject::connect(d->m_hotspotManager.get(), &HotspotManager::disconnectWifiChanged,
2076+ tmp.get(), &wifi::WifiLink::setDisconnectWifi);
2077+
2078+ link = tmp;
2079+ }
2080+ break;
2081+ }
2082+ case NM_DEVICE_TYPE_ETHERNET:
2083+ {
2084+ link = make_shared<ethernet::EthernetLink>(
2085+ dev, d->nm, d->m_settingsInterface, d->m_activeConnectionManager);
2086+ break;
2087+ }
2088+ case NM_DEVICE_TYPE_MODEM:
2089+ {
2090+ if (dev->driver() == "ofono")
2091+ {
2092+ for (const auto &modem : d->m_ofonoLinks)
2093 {
2094- modem->setNmPath(path.path());
2095- d->m_statisticsMonitor->addLink(modem);
2096- break;
2097+ if (modem->ofonoPath() == dev->udi())
2098+ {
2099+ modem->setNmPath(path.path());
2100+ d->m_statisticsMonitor->addLink(modem);
2101+ break;
2102+ }
2103 }
2104 }
2105+ break;
2106 }
2107+ default:
2108+ break;
2109 }
2110-
2111 } catch (const exception &e) {
2112 qDebug() << ": failed to create Device proxy for "<< path.path() << ": ";
2113 qDebug() << "\t" << e.what();
2114@@ -813,10 +830,10 @@
2115 return d->m_unstoppableOperationHappening;
2116 }
2117
2118-QSet<Link::Ptr>
2119+QSet<Link::SPtr>
2120 ManagerImpl::links() const
2121 {
2122- QSet<Link::Ptr> result(d->m_nmLinks);
2123+ QSet<Link::SPtr> result(d->m_nmLinks);
2124 for(auto i: d->m_ofonoLinks)
2125 {
2126 result.insert(i);
2127@@ -917,10 +934,10 @@
2128 }
2129
2130
2131-QSet<wifi::WifiLink::Ptr>
2132+QSet<wifi::WifiLink::SPtr>
2133 ManagerImpl::wifiLinks() const
2134 {
2135- QSet<wifi::WifiLink::Ptr> result;
2136+ QSet<wifi::WifiLink::SPtr> result;
2137 for(auto link: d->m_nmLinks)
2138 {
2139 if (link->type() == Link::Type::wifi)
2140@@ -931,6 +948,20 @@
2141 return result;
2142 }
2143
2144+QSet<ethernet::EthernetLink::SPtr>
2145+ManagerImpl::ethernetLinks() const
2146+{
2147+ QSet<ethernet::EthernetLink::SPtr> result;
2148+ for(auto link: d->m_nmLinks)
2149+ {
2150+ if (link->type() == Link::Type::ethernet)
2151+ {
2152+ result.insert(dynamic_pointer_cast<ethernet::EthernetLink>(link));
2153+ }
2154+ }
2155+ return result;
2156+}
2157+
2158 QSet<wwan::Modem::Ptr>
2159 ManagerImpl::modemLinks() const
2160 {
2161
2162=== modified file 'src/indicator/nmofono/manager-impl.h'
2163--- src/indicator/nmofono/manager-impl.h 2016-10-29 20:09:30 +0000
2164+++ src/indicator/nmofono/manager-impl.h 2016-12-05 18:14:38 +0000
2165@@ -19,6 +19,7 @@
2166
2167 #pragma once
2168
2169+#include <nmofono/connection/active-connection-manager.h>
2170 #include <nmofono/manager.h>
2171 #include <nmofono/kill-switch.h>
2172 #include <nmofono/hotspot-manager.h>
2173@@ -51,6 +52,7 @@
2174 std::shared_ptr<notify::NotificationManager> notificationManager,
2175 KillSwitch::Ptr killSwitch,
2176 HotspotManager::SPtr hotspotManager,
2177+ connection::ActiveConnectionManager::SPtr activeConnectionManager,
2178 const QDBusConnection& systemBus);
2179
2180 // Public API
2181@@ -66,8 +68,9 @@
2182
2183 bool roaming() const override;
2184
2185- QSet<Link::Ptr> links() const override;
2186- QSet<wifi::WifiLink::Ptr> wifiLinks() const override;
2187+ QSet<Link::SPtr> links() const override;
2188+ QSet<wifi::WifiLink::SPtr> wifiLinks() const override;
2189+ QSet<ethernet::EthernetLink::SPtr> ethernetLinks() const override;
2190 QSet<wwan::Modem::Ptr> modemLinks() const override;
2191
2192 Manager::NetworkingStatus status() const override;
2193
2194=== modified file 'src/indicator/nmofono/manager.h'
2195--- src/indicator/nmofono/manager.h 2016-10-29 20:09:30 +0000
2196+++ src/indicator/nmofono/manager.h 2016-12-05 18:14:38 +0000
2197@@ -21,6 +21,7 @@
2198
2199 #include <nmofono/hotspot-manager.h>
2200 #include <nmofono/link.h>
2201+#include <nmofono/ethernet/ethernet-link.h>
2202 #include <nmofono/wifi/wifi-link.h>
2203 #include <nmofono/wwan/modem.h>
2204 #include <nmofono/wwan/sim.h>
2205@@ -83,10 +84,12 @@
2206 virtual bool unstoppableOperationHappening() const = 0;
2207
2208 /// @private
2209- Q_PROPERTY(QSet<Link::Ptr> links READ links NOTIFY linksUpdated)
2210- virtual QSet<Link::Ptr> links() const = 0;
2211-
2212- virtual QSet<wifi::WifiLink::Ptr> wifiLinks() const = 0;
2213+ Q_PROPERTY(QSet<Link::SPtr> links READ links NOTIFY linksUpdated)
2214+ virtual QSet<Link::SPtr> links() const = 0;
2215+
2216+ virtual QSet<wifi::WifiLink::SPtr> wifiLinks() const = 0;
2217+
2218+ virtual QSet<ethernet::EthernetLink::SPtr> ethernetLinks() const = 0;
2219
2220 virtual QSet<wwan::Modem::Ptr> modemLinks() const = 0;
2221
2222
2223=== modified file 'src/indicator/nmofono/nm-device-statistics-monitor.cpp'
2224--- src/indicator/nmofono/nm-device-statistics-monitor.cpp 2016-11-08 13:34:13 +0000
2225+++ src/indicator/nmofono/nm-device-statistics-monitor.cpp 2016-12-05 18:14:38 +0000
2226@@ -18,6 +18,7 @@
2227 */
2228
2229 #include <nmofono/nm-device-statistics-monitor.h>
2230+#include <nmofono/ethernet/ethernet-link.h>
2231
2232 #include <NetworkManager.h>
2233
2234@@ -153,10 +154,6 @@
2235
2236 void setUpInterface(const QString &path)
2237 {
2238-#ifdef INDICATOR_NETWORK_TRACE_MESSAGES
2239- qDebug() << path;
2240-#endif
2241-
2242 if (!m_interfaces.contains(path))
2243 {
2244 return;
2245@@ -175,9 +172,6 @@
2246
2247 void resetInterface(const QString &path)
2248 {
2249-#ifdef INDICATOR_NETWORK_TRACE_MESSAGES
2250- qDebug() << path;
2251-#endif
2252 if (!m_interfaces.contains(path))
2253 {
2254 return;
2255@@ -189,9 +183,6 @@
2256
2257 void connectAllInterfaces()
2258 {
2259-#ifdef INDICATOR_NETWORK_TRACE_MESSAGES
2260- qDebug() << "";
2261-#endif
2262 for (auto path : m_interfaces.keys())
2263 {
2264 setUpInterface(path);
2265@@ -200,9 +191,6 @@
2266
2267 void disconnectAllInterfaces()
2268 {
2269-#ifdef INDICATOR_NETWORK_TRACE_MESSAGES
2270- qDebug() << "";
2271-#endif
2272 for (auto path : m_interfaces.keys())
2273 {
2274 resetInterface(path);
2275@@ -215,9 +203,6 @@
2276 void handleDisplayPowerStateChange(int status, int reason)
2277 {
2278 Q_UNUSED(reason)
2279-#ifdef INDICATOR_NETWORK_TRACE_MESSAGES
2280- qDebug() << status;
2281-#endif
2282
2283 if (m_status != (Status)status) {
2284 m_status = (Status)status;
2285@@ -289,7 +274,7 @@
2286 }
2287
2288 void
2289-NMDeviceStatisticsMonitor::addLink(Link::Ptr link)
2290+NMDeviceStatisticsMonitor::addLink(Link::SPtr link)
2291 {
2292 #ifdef INDICATOR_NETWORK_TRACE_MESSAGES
2293 qDebug() << "adding" << link->name();
2294@@ -299,21 +284,15 @@
2295
2296 if (std::dynamic_pointer_cast<wifi::WifiLinkImpl>(link))
2297 {
2298-#ifdef INDICATOR_NETWORK_TRACE_MESSAGES
2299- qDebug() << " it's a WiFi link";
2300-#endif
2301 path = std::dynamic_pointer_cast<wifi::WifiLinkImpl>(link)->device_path().path();
2302 }
2303 else if (std::dynamic_pointer_cast<wwan::Modem>(link))
2304 {
2305-#ifdef INDICATOR_NETWORK_TRACE_MESSAGES
2306- qDebug() << " it's a modem link";
2307-#endif
2308 path = std::dynamic_pointer_cast<wwan::Modem>(link)->nmPath();
2309 }
2310- else
2311+ else if (std::dynamic_pointer_cast<ethernet::EthernetLink>(link))
2312 {
2313- qWarning() << "Unhandled link type with name:" << link->name();
2314+ path = std::dynamic_pointer_cast<ethernet::EthernetLink>(link)->devicePath().path();
2315 }
2316
2317 if (path.isEmpty())
2318@@ -335,10 +314,6 @@
2319 void
2320 NMDeviceStatisticsMonitor::remove(const QString &nmPath)
2321 {
2322-#ifdef INDICATOR_NETWORK_TRACE_MESSAGES
2323- qDebug() << "removing" << nmPath;
2324-#endif
2325-
2326 if (d->m_interfaces.contains(nmPath))
2327 {
2328 d->resetInterface(nmPath);
2329
2330=== modified file 'src/indicator/nmofono/nm-device-statistics-monitor.h'
2331--- src/indicator/nmofono/nm-device-statistics-monitor.h 2016-10-29 20:09:30 +0000
2332+++ src/indicator/nmofono/nm-device-statistics-monitor.h 2016-12-05 18:14:38 +0000
2333@@ -49,7 +49,7 @@
2334 NMDeviceStatisticsMonitor();
2335 ~NMDeviceStatisticsMonitor();
2336
2337- void addLink(Link::Ptr link);
2338+ void addLink(Link::SPtr link);
2339
2340 void remove(const QString &nmPath);
2341
2342
2343=== modified file 'src/indicator/nmofono/wifi/wifi-link-impl.cpp'
2344--- src/indicator/nmofono/wifi/wifi-link-impl.cpp 2016-10-30 18:42:22 +0000
2345+++ src/indicator/nmofono/wifi/wifi-link-impl.cpp 2016-12-05 18:14:38 +0000
2346@@ -23,7 +23,6 @@
2347 #include <url-dispatcher-cpp/url-dispatcher.h>
2348 #include <cassert>
2349
2350-#include <NetworkManagerActiveConnectionInterface.h>
2351 #include <NetworkManagerDeviceWirelessInterface.h>
2352 #include <NetworkManagerSettingsConnectionInterface.h>
2353
2354@@ -69,13 +68,14 @@
2355 shared_ptr<OrgFreedesktopNetworkManagerDeviceInterface> m_dev;
2356 OrgFreedesktopNetworkManagerDeviceWirelessInterface m_wireless;
2357 shared_ptr<OrgFreedesktopNetworkManagerInterface> m_nm;
2358+ connection::ActiveConnectionManager::SPtr m_activeConnectionManager;
2359
2360 KillSwitch::Ptr m_killSwitch;
2361
2362 map<AccessPointImpl::Key, shared_ptr<GroupedAccessPoint>> m_grouper;
2363 uint32_t m_lastState = 0;
2364 QString m_name;
2365- shared_ptr<OrgFreedesktopNetworkManagerConnectionActiveInterface> m_activeConnection;
2366+ connection::ActiveConnection::SPtr m_activeConnection;
2367 unique_ptr<QMetaObject::Connection> m_signalStrengthConnection;
2368 bool m_connecting = false;
2369 bool m_disconnectWifi = false;
2370@@ -180,24 +180,21 @@
2371 }
2372
2373 // already up-to-date
2374- if (m_activeConnection && m_activeConnection->path() == path.path())
2375+ if (m_activeConnection && m_activeConnection->path() == path)
2376 {
2377 return;
2378 }
2379
2380- try {
2381- m_activeConnection = make_shared<
2382- OrgFreedesktopNetworkManagerConnectionActiveInterface>(
2383- NM_DBUS_SERVICE, path.path(), m_dev->connection());
2384- uint state = m_activeConnection->state();
2385+ m_activeConnection = m_activeConnectionManager->connection(path);
2386+ if (m_activeConnection)
2387+ {
2388+ auto state = m_activeConnection->state();
2389 switch (state) {
2390- case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
2391- case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
2392- case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
2393- case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
2394- case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
2395- ;
2396-
2397+ case connection::ActiveConnection::State::unknown:
2398+ case connection::ActiveConnection::State::activating:
2399+ case connection::ActiveConnection::State::activated:
2400+ case connection::ActiveConnection::State::deactivating:
2401+ case connection::ActiveConnection::State::deactivated:
2402 // for Wi-Fi devices specific_object is the AccessPoint object.
2403 QDBusObjectPath ap_path = m_activeConnection->specificObject();
2404 for (auto &ap : m_groupedAccessPoints) {
2405@@ -216,10 +213,10 @@
2406 }
2407 }
2408 }
2409- } catch (exception &e) {
2410- qWarning() << "failed to get active connection:";
2411- qWarning() << "\tpath: " << path.path();
2412- qWarning() << "\t" << QString::fromStdString(e.what());
2413+ }
2414+ else
2415+ {
2416+ qWarning() << "Failed to get active connection:" << path.path();
2417 }
2418 }
2419
2420@@ -367,9 +364,11 @@
2421
2422 WifiLinkImpl::WifiLinkImpl(shared_ptr<OrgFreedesktopNetworkManagerDeviceInterface> dev,
2423 shared_ptr<OrgFreedesktopNetworkManagerInterface> nm,
2424- KillSwitch::Ptr killSwitch)
2425+ KillSwitch::Ptr killSwitch,
2426+ connection::ActiveConnectionManager::SPtr activeConnectionManager)
2427 : d(new Private(*this, dev, nm, killSwitch)) {
2428 d->m_name = d->m_dev->interface();
2429+ d->m_activeConnectionManager = activeConnectionManager;
2430
2431 connect(&d->m_wireless, &OrgFreedesktopNetworkManagerDeviceWirelessInterface::AccessPointAdded, d.get(), &Private::ap_added);
2432 connect(&d->m_wireless, &OrgFreedesktopNetworkManagerDeviceWirelessInterface::AccessPointRemoved, d.get(), &Private::ap_removed);
2433
2434=== modified file 'src/indicator/nmofono/wifi/wifi-link-impl.h'
2435--- src/indicator/nmofono/wifi/wifi-link-impl.h 2016-10-30 18:42:22 +0000
2436+++ src/indicator/nmofono/wifi/wifi-link-impl.h 2016-12-05 18:14:38 +0000
2437@@ -20,6 +20,7 @@
2438 #pragma once
2439
2440 #include <nmofono/kill-switch.h>
2441+#include <nmofono/connection/active-connection-manager.h>
2442 #include <nmofono/wifi/wifi-link.h>
2443 #include <util/qhash-sharedptr.h>
2444
2445@@ -39,7 +40,8 @@
2446
2447 WifiLinkImpl(std::shared_ptr<OrgFreedesktopNetworkManagerDeviceInterface> dev,
2448 std::shared_ptr<OrgFreedesktopNetworkManagerInterface> nm,
2449- KillSwitch::Ptr killSwitch);
2450+ KillSwitch::Ptr killSwitch,
2451+ connection::ActiveConnectionManager::SPtr activeConnectionManager);
2452 ~WifiLinkImpl();
2453
2454 // public API
2455
2456=== modified file 'src/indicator/nmofono/wifi/wifi-link.h'
2457--- src/indicator/nmofono/wifi/wifi-link.h 2015-10-06 10:19:30 +0000
2458+++ src/indicator/nmofono/wifi/wifi-link.h 2016-12-05 18:14:38 +0000
2459@@ -23,6 +23,7 @@
2460 #include <nmofono/wifi/access-point.h>
2461
2462 #include <QSet>
2463+#include <unity/util/DefinesPtrs.h>
2464
2465 namespace nmofono {
2466 namespace wifi {
2467@@ -38,7 +39,7 @@
2468 Q_OBJECT
2469
2470 public:
2471- typedef std::shared_ptr<WifiLink> Ptr;
2472+ UNITY_DEFINES_PTRS(WifiLink);
2473 typedef unsigned int Id;
2474
2475 enum class Mode
2476
2477=== modified file 'src/indicator/root-state.cpp'
2478--- src/indicator/root-state.cpp 2016-10-29 20:09:30 +0000
2479+++ src/indicator/root-state.cpp 2016-12-05 18:14:38 +0000
2480@@ -195,6 +195,22 @@
2481 // some sort of connection animation
2482 break;
2483 case Manager::NetworkingStatus::online:
2484+ multimap<Link::Id, ethernet::EthernetLink::SPtr> sortedEthernetLinks;
2485+ for (auto ethernetLink : m_manager->ethernetLinks())
2486+ {
2487+ sortedEthernetLinks.insert(make_pair(ethernetLink->id(), ethernetLink));
2488+ }
2489+ for (auto pair : sortedEthernetLinks)
2490+ {
2491+ auto ethernetLink = pair.second;
2492+
2493+ connect(ethernetLink.get(), &ethernet::EthernetLink::statusUpdated, this,
2494+ &Private::updateNetworkingIcon, Qt::UniqueConnection);
2495+
2496+ auto status = ethernetLink->status();
2497+ m_networkingIcons << Icons::ethernetIcon(status);
2498+ }
2499+
2500 for (auto wifiLink : m_manager->wifiLinks())
2501 {
2502 connect(wifiLink.get(), &wifi::WifiLink::statusUpdated, this,
2503
2504=== added file 'src/indicator/sections/ethernet-link-section.cpp'
2505--- src/indicator/sections/ethernet-link-section.cpp 1970-01-01 00:00:00 +0000
2506+++ src/indicator/sections/ethernet-link-section.cpp 2016-12-05 18:14:38 +0000
2507@@ -0,0 +1,211 @@
2508+/*
2509+ * Copyright (C) 2016 Canonical, Ltd.
2510+ *
2511+ * This program is free software: you can redistribute it and/or modify it
2512+ * under the terms of the GNU General Public License version 3, as published
2513+ * by the Free Software Foundation.
2514+ *
2515+ * This program is distributed in the hope that it will be useful, but
2516+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2517+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2518+ * PURPOSE. See the GNU General Public License for more details.
2519+ *
2520+ * You should have received a copy of the GNU General Public License along
2521+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2522+ *
2523+ * Authors:
2524+ * Pete Woods <pete.woods@canonical.com>
2525+ */
2526+
2527+#include <menuitems/ethernet-connection-item.h>
2528+#include <menuitems/ethernet-link-item.h>
2529+#include <sections/ethernet-link-section.h>
2530+
2531+#include "menumodel-cpp/action-group-merger.h"
2532+#include "menumodel-cpp/menu.h"
2533+#include "menumodel-cpp/menu-merger.h"
2534+
2535+#include <util/localisation.h>
2536+#include <util/qhash-sharedptr.h>
2537+
2538+using namespace std;
2539+using namespace nmofono;
2540+using namespace nmofono::connection;
2541+using namespace nmofono::ethernet;
2542+
2543+class EthernetLinkSection::Private : public QObject
2544+{
2545+Q_OBJECT
2546+public:
2547+ Manager::Ptr m_manager;
2548+
2549+ EthernetLink::SPtr m_link;
2550+
2551+ ActionGroupMerger::Ptr m_actionGroupMerger;
2552+
2553+ ActionGroup::Ptr m_actionGroup;
2554+
2555+ MenuMerger::Ptr m_menuMerger;
2556+
2557+ Menu::Ptr m_menu;
2558+
2559+ MenuItem::Ptr m_item;
2560+
2561+ Menu::Ptr m_linkMenu;
2562+
2563+ EthernetLinkItem::SPtr m_linkItem;
2564+
2565+ Menu::Ptr m_connectionsMenu;
2566+
2567+ QMap<AvailableConnection::SPtr, EthernetConnectionItem::SPtr> m_items;
2568+
2569+ Action::Ptr m_connectionAction;
2570+
2571+ Private()
2572+ {
2573+ }
2574+
2575+public Q_SLOTS:
2576+ void
2577+ linksChanged()
2578+ {
2579+ m_linkItem->setShowInterface(m_manager->ethernetLinks().size() > 1);
2580+ }
2581+
2582+ void
2583+ updateConnections()
2584+ {
2585+ auto connections = m_link->availableConnections().toSet();
2586+ auto current(m_items.keys().toSet());
2587+
2588+ auto removed(current);
2589+ removed.subtract(connections);
2590+
2591+ auto added(connections);
2592+ added.subtract(current);
2593+
2594+ for (auto connection : removed)
2595+ {
2596+ m_actionGroupMerger->remove(m_items[connection]->actionGroup());
2597+ m_items.remove(connection);
2598+ }
2599+
2600+ for (auto connection : added)
2601+ {
2602+ auto item = make_shared<EthernetConnectionItem>(connection, m_connectionAction);
2603+ m_items[connection] = item;
2604+ m_actionGroupMerger->add(item->actionGroup());
2605+
2606+ // Make sure we re-order if the ID changes
2607+ connect(connection.get(), &AvailableConnection::connectionIdChanged, this, &Private::updateConnections, Qt::UniqueConnection);
2608+ }
2609+
2610+ m_connectionsMenu->clear();
2611+
2612+ if (connections.size() <= 1)
2613+ {
2614+ return;
2615+ }
2616+
2617+ QMap<QString, EthernetConnectionItem::SPtr> sorted;
2618+ for (QMapIterator<AvailableConnection::SPtr, EthernetConnectionItem::SPtr> it(m_items); it.hasNext();)
2619+ {
2620+ it.next();
2621+ sorted[it.key()->connectionId()] = it.value();
2622+ }
2623+ for (auto item : sorted)
2624+ {
2625+ m_connectionsMenu->append(item->menuItem());
2626+ }
2627+ }
2628+
2629+ void
2630+ actionActivated(const Variant& value)
2631+ {
2632+ auto uuid = QString::fromStdString(value.as<string>());
2633+ QMapIterator<AvailableConnection::SPtr, EthernetConnectionItem::SPtr> it(m_items);
2634+ while (it.hasNext())
2635+ {
2636+ it.next();
2637+
2638+ auto connection = it.key();
2639+ if (connection->connectionUuid() == uuid)
2640+ {
2641+ m_link->setPreferredConnection(connection);
2642+ break;
2643+ }
2644+ }
2645+ }
2646+
2647+ void
2648+ preferredConnectionChanged(AvailableConnection::SPtr preferredConnection)
2649+ {
2650+ if (preferredConnection)
2651+ {
2652+ m_connectionAction->setState(TypedVariant<string>(preferredConnection->connectionUuid().toStdString()));
2653+ }
2654+ else
2655+ {
2656+ m_connectionAction->setState(TypedVariant<string>(""));
2657+ }
2658+ }
2659+};
2660+
2661+EthernetLinkSection::EthernetLinkSection(Manager::Ptr manager, EthernetLink::SPtr link) :
2662+ d(new Private())
2663+{
2664+ d->m_manager = manager;
2665+ d->m_link = link;
2666+
2667+ d->m_actionGroupMerger = make_shared<ActionGroupMerger>();
2668+ d->m_actionGroup = make_shared<ActionGroup>();
2669+ d->m_actionGroupMerger->add(d->m_actionGroup);
2670+
2671+ d->m_menuMerger = make_shared<MenuMerger>();
2672+
2673+ d->m_linkMenu = make_shared<Menu>();
2674+ d->m_linkItem = make_shared<EthernetLinkItem>(d->m_link);
2675+ d->m_linkMenu->append(d->m_linkItem->menuItem());
2676+ d->m_actionGroupMerger->add(d->m_linkItem->actionGroup());
2677+
2678+ d->m_connectionsMenu = make_shared<Menu>();
2679+
2680+ // have the ethernet link in its own section
2681+ d->m_item = MenuItem::newSection(d->m_menuMerger);
2682+ d->m_menu = make_shared<Menu>();
2683+ d->m_menu->append(d->m_item);
2684+
2685+ d->m_menuMerger->append(d->m_linkMenu);
2686+ d->m_menuMerger->append(d->m_connectionsMenu);
2687+
2688+ QString actionName = "ethernet." + QString::number(link->id()) + "::connection";
2689+ d->m_connectionAction = make_shared<Action>(actionName, G_VARIANT_TYPE_STRING, TypedVariant<string>(""));
2690+ d->m_actionGroup->add(d->m_connectionAction);
2691+
2692+ QObject::connect(d->m_manager.get(), &Manager::linksUpdated, d.get(), &Private::linksChanged);
2693+ d->linksChanged();
2694+ QObject::connect(d->m_link.get(), &EthernetLink::availableConnectionsChanged, d.get(), &Private::updateConnections);
2695+ d->updateConnections();
2696+ QObject::connect(d->m_link.get(), &EthernetLink::preferredConnectionChanged, d.get(), &Private::preferredConnectionChanged);
2697+ d->preferredConnectionChanged(d->m_link->preferredConnection());
2698+
2699+ QObject::connect(d->m_connectionAction.get(), &Action::activated, d.get(), &Private::actionActivated);
2700+}
2701+
2702+EthernetLinkSection::~EthernetLinkSection()
2703+{
2704+}
2705+
2706+ActionGroup::Ptr
2707+EthernetLinkSection::actionGroup()
2708+{
2709+ return d->m_actionGroupMerger->actionGroup();
2710+}
2711+
2712+MenuModel::Ptr
2713+EthernetLinkSection::menuModel()
2714+{
2715+ return d->m_menu;
2716+}
2717+
2718+#include "ethernet-link-section.moc"
2719
2720=== added file 'src/indicator/sections/ethernet-link-section.h'
2721--- src/indicator/sections/ethernet-link-section.h 1970-01-01 00:00:00 +0000
2722+++ src/indicator/sections/ethernet-link-section.h 2016-12-05 18:14:38 +0000
2723@@ -0,0 +1,45 @@
2724+/*
2725+ * Copyright (C) 2016 Canonical, Ltd.
2726+ *
2727+ * This program is free software: you can redistribute it and/or modify it
2728+ * under the terms of the GNU General Public License version 3, as published
2729+ * by the Free Software Foundation.
2730+ *
2731+ * This program is distributed in the hope that it will be useful, but
2732+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2733+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2734+ * PURPOSE. See the GNU General Public License for more details.
2735+ *
2736+ * You should have received a copy of the GNU General Public License along
2737+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2738+ *
2739+ * Authors:
2740+ * Pete Woods <pete.woods@canonical.com>
2741+ */
2742+
2743+#pragma once
2744+
2745+#include <nmofono/manager.h>
2746+#include <nmofono/ethernet/ethernet-link.h>
2747+
2748+#include <menuitems/section.h>
2749+
2750+class EthernetLinkSection : public Section
2751+{
2752+public:
2753+ UNITY_DEFINES_PTRS(EthernetLinkSection);
2754+
2755+ explicit EthernetLinkSection(nmofono::Manager::Ptr manager, nmofono::ethernet::EthernetLink::SPtr link);
2756+
2757+ ~EthernetLinkSection();
2758+
2759+ ActionGroup::Ptr
2760+ actionGroup() override;
2761+
2762+ MenuModel::Ptr
2763+ menuModel() override;
2764+
2765+protected:
2766+ class Private;
2767+ std::shared_ptr<Private> d;
2768+};
2769
2770=== added file 'src/indicator/sections/ethernet-section.cpp'
2771--- src/indicator/sections/ethernet-section.cpp 1970-01-01 00:00:00 +0000
2772+++ src/indicator/sections/ethernet-section.cpp 2016-12-05 18:14:38 +0000
2773@@ -0,0 +1,140 @@
2774+/*
2775+ * Copyright (C) 2016 Canonical, Ltd.
2776+ *
2777+ * This program is free software: you can redistribute it and/or modify it
2778+ * under the terms of the GNU General Public License version 3, as published
2779+ * by the Free Software Foundation.
2780+ *
2781+ * This program is distributed in the hope that it will be useful, but
2782+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2783+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2784+ * PURPOSE. See the GNU General Public License for more details.
2785+ *
2786+ * You should have received a copy of the GNU General Public License along
2787+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2788+ *
2789+ * Authors:
2790+ * Pete Woods <pete.woods@canonical.com>
2791+ */
2792+
2793+#include <sections/ethernet-link-section.h>
2794+#include <sections/ethernet-section.h>
2795+#include <menuitems/switch-item.h>
2796+#include <menuitems/text-item.h>
2797+
2798+#include "menumodel-cpp/action-group.h"
2799+#include "menumodel-cpp/action-group-merger.h"
2800+#include "menumodel-cpp/menu.h"
2801+#include "menumodel-cpp/menu-merger.h"
2802+
2803+#include <util/localisation.h>
2804+#include <util/qhash-sharedptr.h>
2805+
2806+using namespace std;
2807+using namespace nmofono;
2808+using namespace nmofono::ethernet;
2809+
2810+class EthernetSection::Private : public QObject
2811+{
2812+ Q_OBJECT
2813+public:
2814+ Manager::Ptr m_manager;
2815+
2816+ Menu::Ptr m_settingsMenu;
2817+
2818+ ActionGroupMerger::Ptr m_actionGroupMerger;
2819+
2820+ MenuMerger::Ptr m_menuMerger;
2821+
2822+ QMap<EthernetLink::SPtr, EthernetLinkSection::SPtr> m_items;
2823+
2824+ Private()
2825+ {
2826+ }
2827+
2828+public Q_SLOTS:
2829+ void linksChanged()
2830+ {
2831+ auto links = m_manager->ethernetLinks();
2832+ auto current(m_items.keys().toSet());
2833+
2834+ auto removed(current);
2835+ removed.subtract(links);
2836+
2837+ auto added(links);
2838+ added.subtract(current);
2839+
2840+ if (added.isEmpty() && removed.isEmpty())
2841+ {
2842+ return;
2843+ }
2844+
2845+ for (auto connection : removed)
2846+ {
2847+ m_actionGroupMerger->remove(m_items[connection]->actionGroup());
2848+ m_items.remove(connection);
2849+ }
2850+
2851+ for (auto link : added)
2852+ {
2853+ auto section = make_shared<EthernetLinkSection>(m_manager, link);
2854+ m_items[link] = section;
2855+ m_actionGroupMerger->add(section->actionGroup());
2856+ }
2857+
2858+ m_menuMerger->clear();
2859+
2860+ multimap<Link::Id, EthernetLinkSection::SPtr> sorted;
2861+ QMapIterator<EthernetLink::SPtr, EthernetLinkSection::SPtr> it(m_items);
2862+ while (it.hasNext())
2863+ {
2864+ it.next();
2865+ sorted.insert(make_pair(it.key()->id(), it.value()));
2866+ }
2867+ for (auto pair : sorted)
2868+ {
2869+ m_menuMerger->append(pair.second->menuModel());
2870+ }
2871+
2872+ if (!links.isEmpty())
2873+ {
2874+ m_menuMerger->append(m_settingsMenu);
2875+ }
2876+ }
2877+};
2878+
2879+EthernetSection::EthernetSection(Manager::Ptr manager)
2880+ : d{new Private()}
2881+{
2882+ d->m_manager = manager;
2883+
2884+ d->m_actionGroupMerger = make_shared<ActionGroupMerger>();
2885+ d->m_menuMerger = make_shared<MenuMerger>();
2886+
2887+ auto settingsItem = make_shared<TextItem>(_("Ethernet settings…"), "ethernet", "settings");
2888+ d->m_actionGroupMerger->add(settingsItem->actionGroup());
2889+
2890+ d->m_settingsMenu = make_shared<Menu>();
2891+ d->m_settingsMenu->append(settingsItem->menuItem());
2892+
2893+ QObject::connect(d->m_manager.get(), &Manager::linksUpdated, d.get(), &Private::linksChanged);
2894+ d->linksChanged();
2895+}
2896+
2897+EthernetSection::~EthernetSection()
2898+{
2899+}
2900+
2901+ActionGroup::Ptr
2902+EthernetSection::actionGroup()
2903+{
2904+ return d->m_actionGroupMerger->actionGroup();
2905+}
2906+
2907+MenuModel::Ptr
2908+EthernetSection::menuModel()
2909+{
2910+ return d->m_menuMerger;
2911+}
2912+
2913+#include "ethernet-section.moc"
2914
2915=== added file 'src/indicator/sections/ethernet-section.h'
2916--- src/indicator/sections/ethernet-section.h 1970-01-01 00:00:00 +0000
2917+++ src/indicator/sections/ethernet-section.h 2016-12-05 18:14:38 +0000
2918@@ -0,0 +1,44 @@
2919+/*
2920+ * Copyright (C) 2016 Canonical, Ltd.
2921+ *
2922+ * This program is free software: you can redistribute it and/or modify it
2923+ * under the terms of the GNU General Public License version 3, as published
2924+ * by the Free Software Foundation.
2925+ *
2926+ * This program is distributed in the hope that it will be useful, but
2927+ * WITHOUT ANY WARRANTY; without even the implied warranties of
2928+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
2929+ * PURPOSE. See the GNU General Public License for more details.
2930+ *
2931+ * You should have received a copy of the GNU General Public License along
2932+ * with this program. If not, see <http://www.gnu.org/licenses/>.
2933+ *
2934+ * Authors:
2935+ * Pete Woods <pete.woods@canonical.com>
2936+ */
2937+
2938+#pragma once
2939+
2940+#include <nmofono/manager.h>
2941+
2942+#include <menuitems/section.h>
2943+
2944+class EthernetSection : public Section
2945+{
2946+public:
2947+ UNITY_DEFINES_PTRS(EthernetSection);
2948+
2949+ explicit EthernetSection(nmofono::Manager::Ptr manager);
2950+
2951+ ~EthernetSection();
2952+
2953+ ActionGroup::Ptr
2954+ actionGroup() override;
2955+
2956+ MenuModel::Ptr
2957+ menuModel() override;
2958+
2959+protected:
2960+ class Private;
2961+ std::shared_ptr<Private> d;
2962+};
2963
2964=== modified file 'src/indicator/sections/quick-access-section.h'
2965--- src/indicator/sections/quick-access-section.h 2015-08-14 15:52:39 +0000
2966+++ src/indicator/sections/quick-access-section.h 2016-12-05 18:14:38 +0000
2967@@ -32,7 +32,8 @@
2968 std::shared_ptr<Private> d;
2969
2970 public:
2971- typedef std::shared_ptr<QuickAccessSection> Ptr;
2972+ UNITY_DEFINES_PTRS(QuickAccessSection);
2973+
2974 QuickAccessSection(nmofono::Manager::Ptr manager, SwitchItem::Ptr flightModeSwitch);
2975 virtual ~QuickAccessSection();
2976
2977
2978=== modified file 'src/indicator/sections/vpn-section.cpp'
2979--- src/indicator/sections/vpn-section.cpp 2015-10-20 10:20:17 +0000
2980+++ src/indicator/sections/vpn-section.cpp 2016-12-05 18:14:38 +0000
2981@@ -46,7 +46,6 @@
2982 Menu::Ptr m_topMenu;
2983 MenuItem::Ptr m_topItem;
2984
2985- MenuItem::Ptr m_vpnSettingsItem;
2986 Menu::Ptr m_vpnSettingsMenu;
2987 TextItem::Ptr m_openVpnSettings;
2988
2989
2990=== modified file 'src/indicator/sections/wifi-section.cpp'
2991--- src/indicator/sections/wifi-section.cpp 2015-08-14 15:52:39 +0000
2992+++ src/indicator/sections/wifi-section.cpp 2016-12-05 18:14:38 +0000
2993@@ -30,8 +30,10 @@
2994 #include "menumodel-cpp/menu-merger.h"
2995
2996 #include <util/localisation.h>
2997+#include <util/qhash-sharedptr.h>
2998
2999 using namespace nmofono;
3000+using namespace std;
3001
3002 class WifiSection::Private : public QObject
3003 {
3004@@ -40,36 +42,35 @@
3005 Manager::Ptr m_manager;
3006
3007 ActionGroupMerger::Ptr m_actionGroupMerger;
3008+ MenuMerger::Ptr m_menuMerger;
3009+
3010+ Menu::Ptr m_switchMenu;
3011 Menu::Ptr m_menu;
3012 Menu::Ptr m_settingsMenu;
3013
3014 SwitchItem::Ptr m_switch;
3015
3016- WifiLinkItem::Ptr m_wifiLink;
3017+ QMap<wifi::WifiLink::SPtr, WifiLinkItem::Ptr> m_items;
3018 TextItem::Ptr m_openWifiSettings;
3019
3020 Private(Manager::Ptr manager, SwitchItem::Ptr wifiSwitch)
3021 : m_manager{manager}, m_switch{wifiSwitch}
3022 {
3023- m_actionGroupMerger = std::make_shared<ActionGroupMerger>();
3024- m_menu = std::make_shared<Menu>();
3025- m_settingsMenu = std::make_shared<Menu>();
3026-
3027- /// @todo don't now really care about actully being able to detach the whole
3028- /// wifi chipset. on touch devices we always have wifi.
3029- if (m_manager->hasWifi()) {
3030- m_menu->append(m_switch->menuItem());
3031- m_settingsMenu->append(m_switch->menuItem());
3032- }
3033-
3034- m_openWifiSettings = std::make_shared<TextItem>(_("Wi-Fi settings…"), "wifi", "settings");
3035+ m_actionGroupMerger = make_shared<ActionGroupMerger>();
3036+ m_menuMerger = make_shared<MenuMerger>();
3037+ m_switchMenu = make_shared<Menu>();
3038+ m_menu = make_shared<Menu>();
3039+ m_settingsMenu = make_shared<Menu>();
3040+
3041+ m_openWifiSettings = make_shared<TextItem>(_("Wi-Fi settings…"), "wifi", "settings");
3042 connect(m_openWifiSettings.get(), &TextItem::activated, this, &Private::openWiFiSettings);
3043
3044+ m_actionGroupMerger->add(m_switch->actionGroup());
3045 m_actionGroupMerger->add(m_openWifiSettings->actionGroup());
3046- m_menu->append(m_openWifiSettings->menuItem());
3047+ m_menuMerger->append(m_switchMenu);
3048+ m_menuMerger->append(m_menu);
3049+ m_menuMerger->append(m_settingsMenu);
3050
3051- // We have this last because the menu item insertion location
3052- // depends on the presence of the WiFi settings item.
3053 updateLinks();
3054 connect(m_manager.get(), &Manager::linksUpdated, this, &Private::updateLinks);
3055 }
3056@@ -77,35 +78,70 @@
3057 public Q_SLOTS:
3058 void openWiFiSettings()
3059 {
3060- UrlDispatcher::send("settings:///system/wifi", [](std::string url, bool success){
3061+ UrlDispatcher::send("settings:///system/wifi", [](string url, bool success){
3062 if (!success)
3063- std::cerr << "URL Dispatcher failed on " << url << std::endl;
3064+ cerr << "URL Dispatcher failed on " << url << endl;
3065 });
3066 }
3067
3068 void updateLinks()
3069 {
3070- // remove all and recreate. we have top 1 now anyway
3071- if (m_wifiLink) {
3072- m_actionGroupMerger->remove(m_wifiLink->actionGroup());
3073- m_menu->removeAll(m_wifiLink->menuItem());
3074- m_settingsMenu->removeAll(m_wifiLink->menuItem());
3075- m_wifiLink.reset();
3076- }
3077-
3078- for (auto wifi_link : m_manager->wifiLinks()) {
3079- m_wifiLink = std::make_shared<WifiLinkItem>(wifi_link);
3080-
3081- m_actionGroupMerger->add(m_wifiLink->actionGroup());
3082- auto comp = [this](MenuItem::Ptr, MenuItem::Ptr other)
3083- {
3084- return other == m_openWifiSettings->menuItem();
3085- };
3086- m_menu->insert(m_wifiLink->menuItem(), comp);
3087- m_settingsMenu->insert(m_wifiLink->menuItem(), comp);
3088-
3089- // just take the first one
3090- break;
3091+ auto links = m_manager->wifiLinks();
3092+ auto current(m_items.keys().toSet());
3093+
3094+ auto removed(current);
3095+ removed.subtract(links);
3096+
3097+ auto added(links);
3098+ added.subtract(current);
3099+
3100+ if (removed.isEmpty() && added.isEmpty())
3101+ {
3102+ return;
3103+ }
3104+
3105+ for (auto link : removed)
3106+ {
3107+ m_actionGroupMerger->remove(m_items[link]->actionGroup());
3108+ m_items.remove(link);
3109+ }
3110+
3111+ for (auto link : added)
3112+ {
3113+ auto item = make_shared<WifiLinkItem>(link);
3114+ m_items[link] = item;
3115+ m_actionGroupMerger->add(item->actionGroup());
3116+ }
3117+
3118+ m_menu->clear();
3119+
3120+ multimap<Link::Id, WifiLinkItem::Ptr> sorted;
3121+ QMapIterator<wifi::WifiLink::SPtr, WifiLinkItem::Ptr> it(m_items);
3122+ while (it.hasNext())
3123+ {
3124+ it.next();
3125+ sorted.insert(make_pair(it.key()->id(), it.value()));
3126+ }
3127+ for (auto pair : sorted)
3128+ {
3129+ m_menu->append(pair.second->menuItem());
3130+ }
3131+
3132+ if (links.isEmpty())
3133+ {
3134+ m_switchMenu->removeAll(m_switch->menuItem());
3135+ m_settingsMenu->removeAll(m_openWifiSettings->menuItem());
3136+ }
3137+ else
3138+ {
3139+ if (m_settingsMenu->find(m_openWifiSettings->menuItem()) == m_settingsMenu->end())
3140+ {
3141+ m_settingsMenu->append(m_openWifiSettings->menuItem());
3142+ }
3143+ if (m_switchMenu->find(m_switch->menuItem()) == m_switchMenu->end())
3144+ {
3145+ m_switchMenu->append(m_switch->menuItem());
3146+ }
3147 }
3148 }
3149 };
3150@@ -127,7 +163,7 @@
3151 MenuModel::Ptr
3152 WifiSection::menuModel()
3153 {
3154- return d->m_menu;
3155+ return d->m_menuMerger;
3156 }
3157
3158 MenuModel::Ptr
3159
3160=== modified file 'src/indicator/sections/wifi-section.h'
3161--- src/indicator/sections/wifi-section.h 2015-08-14 15:52:39 +0000
3162+++ src/indicator/sections/wifi-section.h 2016-12-05 18:14:38 +0000
3163@@ -30,7 +30,8 @@
3164 std::shared_ptr<Private> d;
3165
3166 public:
3167- typedef std::shared_ptr<WifiSection> Ptr;
3168+ UNITY_DEFINES_PTRS(WifiSection);
3169+
3170 explicit WifiSection(nmofono::Manager::Ptr manager, SwitchItem::Ptr wifiSwitch);
3171 virtual ~WifiSection();
3172
3173
3174=== modified file 'src/indicator/sections/wwan-section.cpp'
3175--- src/indicator/sections/wwan-section.cpp 2016-07-05 10:49:27 +0000
3176+++ src/indicator/sections/wwan-section.cpp 2016-12-05 18:14:38 +0000
3177@@ -58,7 +58,7 @@
3178 SwitchItem::Ptr m_hotspotSwitch;
3179 TextItem::Ptr m_openCellularSettings;
3180
3181- QMap<wwan::Modem::Ptr, WwanLinkItem::Ptr> m_items;
3182+ QMap<wwan::Modem::Ptr, WwanLinkItem::SPtr> m_items;
3183
3184 Private() = delete;
3185 Private(Manager::Ptr modemManager, SwitchItem::Ptr mobileDataSwitch ,SwitchItem::Ptr hotspotSwitch);
3186@@ -139,7 +139,7 @@
3187 m_linkMenuMerger->clear();
3188
3189 multimap<int, WwanLinkItem::Ptr, wwan::Modem::Compare> sorted;
3190- QMapIterator<wwan::Modem::Ptr, WwanLinkItem::Ptr> it(m_items);
3191+ QMapIterator<wwan::Modem::Ptr, WwanLinkItem::SPtr> it(m_items);
3192 while (it.hasNext())
3193 {
3194 it.next();
3195
3196=== modified file 'src/indicator/sections/wwan-section.h'
3197--- src/indicator/sections/wwan-section.h 2016-05-05 14:15:23 +0000
3198+++ src/indicator/sections/wwan-section.h 2016-12-05 18:14:38 +0000
3199@@ -29,7 +29,8 @@
3200 std::shared_ptr<Private> d;
3201
3202 public:
3203- typedef std::shared_ptr<WwanSection> Ptr;
3204+ UNITY_DEFINES_PTRS(WwanSection);
3205+
3206 explicit WwanSection(nmofono::Manager::Ptr modemManager, SwitchItem::Ptr mobileDataSwitch, SwitchItem::Ptr hotspotSwitch);
3207 virtual ~WwanSection();
3208
3209
3210=== modified file 'src/menumodel-cpp/menu-item.cpp'
3211--- src/menumodel-cpp/menu-item.cpp 2016-05-26 13:51:39 +0000
3212+++ src/menumodel-cpp/menu-item.cpp 2016-12-05 18:14:38 +0000
3213@@ -102,6 +102,18 @@
3214 Q_EMIT changed();
3215 }
3216
3217+void MenuItem::setActionAndTargetValue(const QString &action, const Variant& target)
3218+{
3219+ if (m_action == action)
3220+ {
3221+ return;
3222+ }
3223+
3224+ m_action = action;
3225+ g_menu_item_set_action_and_target_value(m_gmenuitem.get(), m_action.toUtf8().constData(), target);
3226+ Q_EMIT changed();
3227+}
3228+
3229 void MenuItem::setAttribute(const QString &attribute,
3230 Variant value)
3231 {
3232
3233=== modified file 'src/menumodel-cpp/menu-item.h'
3234--- src/menumodel-cpp/menu-item.h 2015-10-06 10:14:57 +0000
3235+++ src/menumodel-cpp/menu-item.h 2016-12-05 18:14:38 +0000
3236@@ -74,6 +74,8 @@
3237
3238 void setAction(const QString &value);
3239
3240+ void setActionAndTargetValue(const QString &value, const Variant& target);
3241+
3242 void setAttribute(const QString &attribute,
3243 Variant value);
3244
3245
3246=== modified file 'src/menumodel-cpp/menu.cpp'
3247--- src/menumodel-cpp/menu.cpp 2015-04-01 15:28:56 +0000
3248+++ src/menumodel-cpp/menu.cpp 2016-12-05 18:14:38 +0000
3249@@ -147,6 +147,11 @@
3250 return m_items.end();
3251 }
3252
3253+std::size_t Menu::size() const
3254+{
3255+ return m_items.size();
3256+}
3257+
3258 // clear the whole menu
3259 void Menu::clear()
3260 {
3261
3262=== modified file 'src/menumodel-cpp/menu.h'
3263--- src/menumodel-cpp/menu.h 2015-04-24 08:47:08 +0000
3264+++ src/menumodel-cpp/menu.h 2016-12-05 18:14:38 +0000
3265@@ -79,6 +79,8 @@
3266
3267 iterator end();
3268
3269+ std::size_t size() const;
3270+
3271 // clear the whole menu
3272 void clear();
3273
3274
3275=== modified file 'src/qdbus-stubs/CMakeLists.txt'
3276--- src/qdbus-stubs/CMakeLists.txt 2016-10-29 20:09:30 +0000
3277+++ src/qdbus-stubs/CMakeLists.txt 2016-12-05 18:14:38 +0000
3278@@ -18,6 +18,7 @@
3279 set_source_files_properties(
3280 "${DATA_DIR}/nm-device.xml"
3281 "${DATA_DIR}/nm-device-statistics.xml"
3282+ "${DATA_DIR}/nm-device-ethernet.xml"
3283 "${DATA_DIR}/nm-device-wifi.xml"
3284 "${DATA_DIR}/nm-access-point.xml"
3285 "${DATA_DIR}/nm-active-connection.xml"
3286@@ -80,6 +81,12 @@
3287
3288 qt5_add_dbus_interface(
3289 CONNECTIVITY_BACKEND_SRC
3290+ "${DATA_DIR}/nm-device-ethernet.xml"
3291+ NetworkManagerDeviceWiredInterface
3292+)
3293+
3294+qt5_add_dbus_interface(
3295+ CONNECTIVITY_BACKEND_SRC
3296 "${DATA_DIR}/nm-device-wifi.xml"
3297 NetworkManagerDeviceWirelessInterface
3298 )
3299
3300=== modified file 'tests/data/networkmanager.py'
3301--- tests/data/networkmanager.py 2016-10-28 15:26:34 +0000
3302+++ tests/data/networkmanager.py 2016-12-05 18:14:38 +0000
3303@@ -171,6 +171,12 @@
3304 return active_conn
3305
3306
3307+def device_disconnect(self):
3308+ active_connection = self.Get(DEVICE_IFACE, 'ActiveConnection')
3309+ NM = dbusmock.get_object(MAIN_OBJ)
3310+ NM.RemoveActiveConnection(self.path, active_connection)
3311+
3312+
3313 def deactivate_connection(self, active_conn_path):
3314 NM = dbusmock.get_object(MAIN_OBJ)
3315
3316@@ -317,12 +323,16 @@
3317 'Interface': iface_name,
3318 'ActiveConnection': dbus.ObjectPath('/'),
3319 'AvailableConnections': dbus.Array([], signature='o'),
3320- 'AutoConnect': False,
3321+ 'Autoconnect': False, # Network Manager captializes this differently than other properties
3322 'Managed': True,
3323 'Driver': 'dbusmock',
3324 'IpInterface': ''}
3325
3326 obj = dbusmock.get_object(path)
3327+ obj.disconnect = device_disconnect
3328+ obj.AddMethods(DEVICE_IFACE, [
3329+ ('Disconnect', '', '', "self.disconnect(self)")
3330+ ])
3331 obj.AddProperties(DEVICE_IFACE, props)
3332 obj.AddProperties(DEVICE_STATISTICS_IFACE,
3333 {
3334@@ -352,7 +362,7 @@
3335 'Interface': ofono_path[1:],
3336 'ActiveConnection': dbus.ObjectPath('/'),
3337 'AvailableConnections': dbus.Array([], signature='o'),
3338- 'AutoConnect': False,
3339+ 'Autoconnect': False, # Network Manager captializes this differently than other properties
3340 'Managed': True,
3341 'Driver': 'ofono',
3342 'Udi': ofono_path,
3343@@ -370,6 +380,10 @@
3344 'TxBytes': dbus.UInt64(0),
3345 'RxBytes': dbus.UInt64(0),
3346 })
3347+ obj.disconnect = device_disconnect
3348+ obj.AddMethods(DEVICE_IFACE, [
3349+ ('Disconnect', '', '', "self.disconnect(self)")
3350+ ])
3351
3352 devices = self.Get(MAIN_IFACE, 'Devices')
3353 devices.append(path)
3354@@ -421,7 +435,7 @@
3355 {
3356 'ActiveConnection': dbus.ObjectPath('/'),
3357 'AvailableConnections': dbus.Array([], signature='o'),
3358- 'AutoConnect': False,
3359+ 'Autoconnect': False, # Network Manager captializes this differently than other properties
3360 'Managed': True,
3361 'Driver': 'dbusmock',
3362 'DeviceType': dbus.UInt32(2),
3363@@ -429,6 +443,10 @@
3364 'Interface': iface_name,
3365 'IpInterface': iface_name,
3366 })
3367+ dev_obj.disconnect = device_disconnect
3368+ dev_obj.AddMethods(DEVICE_IFACE, [
3369+ ('Disconnect', '', '', "self.disconnect(self)")
3370+ ])
3371 dev_obj.AddProperties(DEVICE_STATISTICS_IFACE,
3372 {
3373 'RefreshRateMs': dbus.UInt32(0),
3374@@ -635,13 +653,13 @@
3375 },
3376 [])
3377
3378+ active_connections = self.Get(MAIN_IFACE, 'ActiveConnections')
3379+ active_connections.append(dbus.ObjectPath(active_connection_path))
3380+ self.SetProperty(MAIN_OBJ, MAIN_IFACE, 'ActiveConnections', active_connections)
3381+
3382 for dev_path in devices:
3383 self.SetDeviceActive(dev_path, active_connection_path)
3384
3385- active_connections = self.Get(MAIN_IFACE, 'ActiveConnections')
3386- active_connections.append(dbus.ObjectPath(active_connection_path))
3387- self.SetProperty(MAIN_OBJ, MAIN_IFACE, 'ActiveConnections', active_connections)
3388-
3389 return active_connection_path
3390
3391
3392@@ -753,13 +771,47 @@
3393 https://developer.gnome.org/NetworkManager/0.9/spec.html
3394 #type-String_String_Variant_Map_Map
3395
3396- If you omit uuid, this method adds one for you.
3397+ If you omit connection uuid or timestamp, this method adds one for you.
3398+
3399+ Note that this automatically associates the connection settings object
3400+ with the first device that was created.
3401 '''
3402
3403- if 'uuid' not in connection_settings['connection']:
3404- connection_settings['connection']['uuid'] = str(uuid.uuid4())
3405-
3406 NM = dbusmock.get_object(MAIN_OBJ)
3407+ devices = NM.GetDevices()
3408+
3409+ dev = None
3410+
3411+ auto_connect = False
3412+ if 'autoconnect' in connection_settings['connection']:
3413+ auto_connect = connection_settings['connection']['autoconnect']
3414+
3415+ # Grab the first device if we are to auto-connect
3416+ if auto_connect and len(devices) > 0:
3417+ dev = devices[0]
3418+
3419+ connection_path = self.AddDeviceConnection(dev, connection_settings)
3420+
3421+ if auto_connect and dev:
3422+ activate_connection(NM, connection_path, dev, connection_path)
3423+
3424+ return connection_path
3425+
3426+
3427+@dbus.service.method(MOCK_IFACE,
3428+ in_signature='sa{sa{sv}}', out_signature='s')
3429+def AddDeviceConnection(self, dev_path, settings):
3430+ '''Add an available connection to an existing WiFi device and access point.
3431+
3432+ You have to specify device path and a settings map.
3433+
3434+ settings is a String String Variant Map Map. See
3435+ https://developer.gnome.org/NetworkManager/0.9/spec.html
3436+ #type-String_String_Variant_Map_Map
3437+
3438+ Returns the new object path.
3439+ '''
3440+
3441 settings_obj = dbusmock.get_object(SETTINGS_OBJ)
3442 main_connections = settings_obj.ListConnections()
3443
3444@@ -772,6 +824,39 @@
3445 count += 1
3446 connection_path = str(connection_obj_path)
3447
3448+ # Fill in the blanks if they haven't been provided
3449+ if not 'connection' in settings:
3450+ settings['connection'] = {}
3451+
3452+ if not 'uuid' in settings['connection']:
3453+ settings['connection']['uuid'] = str(uuid.uuid4())
3454+
3455+ if not 'timestamp' in settings['connection']:
3456+ settings['connection']['timestamp'] = dbus.UInt64(1374828522)
3457+
3458+ if not 'ipv4' in settings:
3459+ settings['ipv4'] = {
3460+ 'address-data': dbus.Array([], signature='a{sv}'),
3461+ 'addresses': dbus.Array([], signature='au'),
3462+ 'dns': dbus.Array([], signature='u'),
3463+ 'dns-search': dbus.Array([], signature='s'),
3464+ 'method': 'auto',
3465+ 'route-data': dbus.Array([], signature='a{sv}'),
3466+ 'routes': dbus.Array([], signature='au')
3467+ }
3468+
3469+ if not 'ipv6' in settings:
3470+ settings['ipv6'] = {
3471+ 'address-data': dbus.Array([], signature='a{sv}'),
3472+ 'addresses': dbus.Array([], signature='(ayuay)'),
3473+ 'dns': dbus.Array([], signature='ay'),
3474+ 'dns-search': dbus.Array([], signature='s'),
3475+ 'ip6-privacy': 0,
3476+ 'method': 'auto',
3477+ 'route-data': dbus.Array([], signature='a{sv}'),
3478+ 'routes': dbus.Array([], signature='(ayuayu)')
3479+ }
3480+
3481 self.AddObject(connection_path,
3482 CSETTINGS_IFACE,
3483 {
3484@@ -785,33 +870,23 @@
3485 ])
3486
3487 connection_obj = dbusmock.get_object(connection_path)
3488- connection_obj.settings = connection_settings
3489+ connection_obj.settings = settings
3490 connection_obj.connection_path = connection_path
3491 connection_obj.ConnectionDelete = ConnectionDelete
3492 connection_obj.ConnectionGetSettings = ConnectionGetSettings
3493 connection_obj.ConnectionGetSecrets = ConnectionGetSecrets
3494 connection_obj.ConnectionUpdate = ConnectionUpdate
3495
3496+ if dev_path and dev_path != '' and dev_path != '/':
3497+ dev_obj = dbusmock.get_object(dev_path)
3498+ connections = dev_obj.Get(DEVICE_IFACE, 'AvailableConnections')
3499+ connections.append(dbus.ObjectPath(connection_path))
3500+ dev_obj.Set(DEVICE_IFACE, 'AvailableConnections', connections)
3501+
3502 main_connections.append(connection_path)
3503 settings_obj.Set(SETTINGS_IFACE, 'Connections', main_connections)
3504-
3505 settings_obj.EmitSignal(SETTINGS_IFACE, 'NewConnection', 'o', [connection_path])
3506
3507- auto_connect = False
3508- if 'autoconnect' in connection_settings['connection']:
3509- auto_connect = connection_settings['connection']['autoconnect']
3510-
3511- if auto_connect:
3512- dev = None
3513- devices = NM.GetDevices()
3514-
3515- # Grab the first device.
3516- if len(devices) > 0:
3517- dev = devices[0]
3518-
3519- if dev:
3520- activate_connection(NM, connection_path, dev, connection_path)
3521-
3522 return connection_path
3523
3524
3525
3526=== modified file 'tests/integration/CMakeLists.txt'
3527--- tests/integration/CMakeLists.txt 2016-11-08 13:34:13 +0000
3528+++ tests/integration/CMakeLists.txt 2016-12-05 18:14:38 +0000
3529@@ -1,8 +1,5 @@
3530
3531 set(INDICATOR_NETWORK_TESTING_GSETTINGS_SCHEMA_DIR "${CMAKE_BINARY_DIR}/data") #need this somewhere higher up in the hierarchy
3532-#set(INDICATOR_NETWORK_UNDER_TESTING 1)
3533-#set(INDICATOR_NETWORK_TESTING_GSETTINGS_INI=${CMAKE_BINARY_DIR}/data/test_gsettings.ini)
3534-#set(GSETTINGS_SCHEMA_DIR="${INDICATOR_NETWORK_TESTING_GSETTINGS_SCHEMA_DIR}")
3535
3536 add_definitions(
3537 -DNETWORK_SERVICE_BIN="${CMAKE_BINARY_DIR}/src/indicator/indicator-network-service"
3538
3539=== modified file 'tests/integration/indicator-network-test-base.cpp'
3540--- tests/integration/indicator-network-test-base.cpp 2016-11-08 13:34:13 +0000
3541+++ tests/integration/indicator-network-test-base.cpp 2016-12-05 18:14:38 +0000
3542@@ -217,15 +217,21 @@
3543 "/com/canonical/indicator/network/unlocksim" + to_string(exportId));
3544 }
3545
3546-void IndicatorNetworkTestBase::startIndicator()
3547+void
3548+IndicatorNetworkTestBase::startIndicator()
3549 {
3550 try
3551 {
3552- indicator.reset(
3553- new QProcessDBusService(DBusTypes::DBUS_NAME,
3554- QDBusConnection::SessionBus,
3555- NETWORK_SERVICE_BIN,
3556- QStringList()));
3557+ if (qEnvironmentVariableIsSet("TEST_WITH_GDB"))
3558+ {
3559+ indicator.reset(new QProcessDBusService(DBusTypes::DBUS_NAME, QDBusConnection::SessionBus, "/usr/bin/gdb", QStringList
3560+ { "-batch", "-ex", "run", "-ex", "bt", NETWORK_SERVICE_BIN }));
3561+ }
3562+ else
3563+ {
3564+ indicator.reset(new QProcessDBusService(DBusTypes::DBUS_NAME, QDBusConnection::SessionBus,
3565+ NETWORK_SERVICE_BIN, QStringList()));
3566+ }
3567 indicator->start(dbusTestRunner.sessionConnection());
3568 }
3569 catch (exception const& e)
3570@@ -244,6 +250,40 @@
3571 {
3572 EXPECT_FALSE(reply.isError()) << reply.error().message().toStdString();
3573 }
3574+ QString path = reply;
3575+
3576+ if (state == NM_DEVICE_STATE_ACTIVATED)
3577+ {
3578+ setNmProperty(path, NM_DBUS_INTERFACE_DEVICE, "Autoconnect", true);
3579+ }
3580+
3581+ return reply;
3582+}
3583+
3584+QString IndicatorNetworkTestBase::createEthernetConnection(const QString& name, const QString& device)
3585+{
3586+ auto& networkManager(dbusMock.networkManagerInterface());
3587+
3588+ VariantDictMap settings{
3589+ {"802-3-ethernet", QVariantMap{
3590+ {"duplex", "full"},
3591+ {"mac-address", randomMac().toUtf8()},
3592+ {"mac-address-blacklist", QStringList()}
3593+ }},
3594+ {"connection", QVariantMap{
3595+ {"id", name},
3596+ {"interface-name", "ens33"},
3597+ {"type", "802-3-ethernet"},
3598+ {"permissions", QStringList()},
3599+ {"secondaries", QStringList()}
3600+ }}
3601+ };
3602+ auto reply = networkManager.AddDeviceConnection(device, settings);
3603+ reply.waitForFinished();
3604+ if (reply.isError())
3605+ {
3606+ EXPECT_FALSE(reply.isError()) << reply.error().message().toStdString();
3607+ }
3608 return reply;
3609 }
3610
3611@@ -273,7 +313,6 @@
3612 return reply;
3613 }
3614
3615-
3616 void IndicatorNetworkTestBase::setDeviceStatistics(const QString &device, quint64 tx, quint64 rx)
3617 {
3618 auto& networkManager(dbusMock.networkManagerInterface());
3619@@ -656,6 +695,34 @@
3620 .action("indicator.cellular.settings");
3621 }
3622
3623+mh::MenuItemMatcher IndicatorNetworkTestBase::ethernetInfo(const string& label,
3624+ const string& status,
3625+ Toggle autoConnect)
3626+{
3627+ return mh::MenuItemMatcher()
3628+ .checkbox()
3629+ .widget("com.canonical.indicator.switch")
3630+ .toggled(autoConnect == Toggle::enabled)
3631+ .label(label)
3632+ .pass_through_string_attribute("x-canonical-subtitle-action", status);
3633+}
3634+
3635+mh::MenuItemMatcher IndicatorNetworkTestBase::radio(const string& label,
3636+ Toggle toggled)
3637+{
3638+ return mh::MenuItemMatcher()
3639+ .radio()
3640+ .label(label)
3641+ .toggled(toggled == Toggle::enabled);
3642+}
3643+
3644+mh::MenuItemMatcher IndicatorNetworkTestBase::ethernetSettings()
3645+{
3646+ return mh::MenuItemMatcher()
3647+ .label("Ethernet settings…")
3648+ .action("indicator.ethernet.settings");
3649+}
3650+
3651 QString IndicatorNetworkTestBase::createVpnConnection(const QString& id,
3652 const QString& serviceType,
3653 const QStringMap& data,
3654
3655=== modified file 'tests/integration/indicator-network-test-base.h'
3656--- tests/integration/indicator-network-test-base.h 2016-10-30 15:13:34 +0000
3657+++ tests/integration/indicator-network-test-base.h 2016-12-05 18:14:38 +0000
3658@@ -131,6 +131,12 @@
3659 disconnected
3660 };
3661
3662+ enum class Toggle
3663+ {
3664+ enabled,
3665+ disabled
3666+ };
3667+
3668 IndicatorNetworkTestBase();
3669
3670 ~IndicatorNetworkTestBase();
3671@@ -149,6 +155,8 @@
3672
3673 QString createEthernetDevice(int state, const QString& id = "0");
3674
3675+ QString createEthernetConnection(const QString& name, const QString& device);
3676+
3677 QString createWiFiDevice(int state, const QString& id = "0");
3678
3679 QString createOfonoModemDevice(const QString &ofonoPath, const QString& id);
3680@@ -172,7 +180,7 @@
3681
3682 void removeWifiConnection(const QString& device, const QString& connection);
3683
3684- QString createActiveConnection(const QString& id, const QString& device, const QString& connection, const QString& specificObject);
3685+ QString createActiveConnection(const QString& id, const QString& device, const QString& connection, const QString& specificObject = "/");
3686
3687 void removeActiveConnection(const QString& device, const QString& active_connection);
3688
3689@@ -243,8 +251,17 @@
3690 bool locked = false,
3691 const std::string& connectivityIcon = "");
3692
3693+ static unity::gmenuharness::MenuItemMatcher ethernetInfo(const std::string& label,
3694+ const std::string& status,
3695+ Toggle autoConnect = Toggle::enabled);
3696+
3697+ static unity::gmenuharness::MenuItemMatcher radio(const std::string& label,
3698+ Toggle toggled);
3699+
3700 static unity::gmenuharness::MenuItemMatcher cellularSettings();
3701
3702+ static unity::gmenuharness::MenuItemMatcher ethernetSettings();
3703+
3704 static unity::gmenuharness::MenuItemMatcher vpnSettings();
3705
3706 static unity::gmenuharness::MenuItemMatcher vpnConnection(const std::string& name, ConnectionStatus connected = ConnectionStatus::disconnected);
3707
3708=== modified file 'tests/integration/test-connectivity-api-sim.cpp'
3709--- tests/integration/test-connectivity-api-sim.cpp 2016-06-17 11:55:15 +0000
3710+++ tests/integration/test-connectivity-api-sim.cpp 2016-12-05 18:14:38 +0000
3711@@ -75,7 +75,7 @@
3712 << "Present: " << (simState.present ? "y" : "n") << ", "
3713 << "MCC: " << simState.mcc.toStdString () << ", "
3714 << "MNC: " << simState.mnc.toStdString () << ", "
3715- << "Langs: " << QStringList(simState.preferredLanguages).join (",").toStdString ()
3716+ << "Langs: [" << QStringList(simState.preferredLanguages).join (",").toStdString () << "], "
3717 << "Roaming: " << (simState.dataRoamingEnabled ? "y" : "n")
3718 << ")";
3719 }
3720
3721=== modified file 'tests/integration/test-indicator.cpp'
3722--- tests/integration/test-indicator.cpp 2016-11-08 16:47:12 +0000
3723+++ tests/integration/test-indicator.cpp 2016-12-05 18:14:38 +0000
3724@@ -22,6 +22,9 @@
3725 #include <QTestEventLoop>
3726 #include <QSignalSpy>
3727
3728+#include <NetworkManagerDeviceInterface.h>
3729+#include <NetworkManagerActiveConnectionInterface.h>
3730+
3731 using namespace std;
3732 using namespace testing;
3733 using namespace connectivityqt;
3734@@ -52,12 +55,441 @@
3735 .item(modemInfo("", "fake.tel", "gsm-3g-full"))
3736 .item(cellularSettings())
3737 )
3738- .item(wifiEnableSwitch())
3739- .item(wifiSettings())
3740- .item(mh::MenuItemMatcher()
3741- .section()
3742- )
3743- ).match());
3744+ .item(mh::MenuItemMatcher()
3745+ .section()
3746+ )
3747+ ).match());
3748+}
3749+
3750+TEST_F(TestIndicator, OneDisabledEthernetAtStartup)
3751+{
3752+ setGlobalConnectedState(NM_STATE_DISCONNECTED);
3753+ auto device = createEthernetDevice(NM_DEVICE_STATE_DISCONNECTED);
3754+ auto connection = createEthernetConnection("Home", device);
3755+
3756+ ASSERT_NO_THROW(startIndicator());
3757+
3758+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
3759+ .item(mh::MenuItemMatcher()
3760+ .state_icons({"gsm-3g-full", "nm-no-connection"})
3761+ .submenu()
3762+ .item(flightModeSwitch())
3763+ .item(mh::MenuItemMatcher()) // <-- modems are under here
3764+ .item(mh::MenuItemMatcher()
3765+ .section()
3766+ .item(ethernetInfo("Ethernet",
3767+ "Disconnected",
3768+ Toggle::disabled)
3769+ )
3770+ )
3771+ .item(ethernetSettings())
3772+ .item(mh::MenuItemMatcher()
3773+ .section()
3774+ )
3775+ ).match());
3776+}
3777+
3778+TEST_F(TestIndicator, OneConnectedEthernetAtStartup)
3779+{
3780+ setGlobalConnectedState(NM_STATE_CONNECTED_GLOBAL);
3781+ auto device = createEthernetDevice(NM_DEVICE_STATE_ACTIVATED);
3782+ auto connection = createEthernetConnection("Home", device);
3783+ createActiveConnection("0", device, connection);
3784+
3785+ ASSERT_NO_THROW(startIndicator());
3786+
3787+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
3788+ .item(mh::MenuItemMatcher()
3789+ .state_icons({"gsm-3g-full", "network-wired-connected"})
3790+ .submenu()
3791+ .item(flightModeSwitch())
3792+ .item(mh::MenuItemMatcher()) // <-- modems are under here
3793+ .item(mh::MenuItemMatcher()
3794+ .section()
3795+ .item(ethernetInfo("Ethernet",
3796+ "Connected",
3797+ Toggle::enabled)
3798+ )
3799+ )
3800+ .item(ethernetSettings())
3801+ .item(mh::MenuItemMatcher()
3802+ .section()
3803+ )
3804+ ).match());
3805+}
3806+
3807+TEST_F(TestIndicator, TwoEthernetAtStartupConnectedAndDisconnected)
3808+{
3809+ setGlobalConnectedState(NM_STATE_CONNECTED_GLOBAL);
3810+
3811+ // Active and connected with two connections
3812+ auto eth0 = createEthernetDevice(NM_DEVICE_STATE_ACTIVATED, "0");
3813+ auto eth0connection0 = createEthernetConnection("Home", eth0);
3814+ auto eth0connection1 = createEthernetConnection("Work", eth0);
3815+ createActiveConnection("0", eth0, eth0connection0);
3816+
3817+ // Active but disconnected
3818+ auto eth1 = createEthernetDevice(NM_DEVICE_STATE_DISCONNECTED, "1");
3819+ setNmProperty(eth1, NM_DBUS_INTERFACE_DEVICE, "Autoconnect", true);
3820+ auto eth1connection0 = createEthernetConnection("Home", eth1);
3821+
3822+ ASSERT_NO_THROW(startIndicator());
3823+
3824+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
3825+ .item(mh::MenuItemMatcher()
3826+ .state_icons({"gsm-3g-full", "network-wired-connected", "network-wired-offline"})
3827+ .submenu()
3828+ .item(flightModeSwitch())
3829+ .item(mh::MenuItemMatcher()) // <-- modems are under here
3830+ .item(mh::MenuItemMatcher()
3831+ .section()
3832+ .item(ethernetInfo("Ethernet (eth0)",
3833+ "Connected",
3834+ Toggle::enabled)
3835+ )
3836+ .item(radio("Home", Toggle::enabled))
3837+ .item(radio("Work", Toggle::disabled))
3838+ )
3839+ .item(mh::MenuItemMatcher()
3840+ .section()
3841+ .item(ethernetInfo("Ethernet (eth1)",
3842+ "Disconnected",
3843+ Toggle::enabled)
3844+ )
3845+ )
3846+ .item(ethernetSettings())
3847+ .item(mh::MenuItemMatcher()
3848+ .section()
3849+ )
3850+ ).match());
3851+}
3852+
3853+TEST_F(TestIndicator, OneDisabledEthernetAfterStartup)
3854+{
3855+ setGlobalConnectedState(NM_STATE_DISCONNECTED);
3856+
3857+ ASSERT_NO_THROW(startIndicator());
3858+
3859+ auto device = createEthernetDevice(NM_DEVICE_STATE_DISCONNECTED);
3860+ auto connection = createEthernetConnection("Home", device);
3861+
3862+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
3863+ .item(mh::MenuItemMatcher()
3864+ .state_icons({"gsm-3g-full", "nm-no-connection"})
3865+ .submenu()
3866+ .item(flightModeSwitch())
3867+ .item(mh::MenuItemMatcher()) // <-- modems are under here
3868+ .item(mh::MenuItemMatcher()
3869+ .section()
3870+ .item(ethernetInfo("Ethernet",
3871+ "Disconnected",
3872+ Toggle::disabled)
3873+ )
3874+ )
3875+ .item(ethernetSettings())
3876+ .item(mh::MenuItemMatcher()
3877+ .section()
3878+ )
3879+ ).match());
3880+}
3881+
3882+TEST_F(TestIndicator, OneConnectedEthernetAfterStartup)
3883+{
3884+ setGlobalConnectedState(NM_STATE_CONNECTED_GLOBAL);
3885+
3886+ ASSERT_NO_THROW(startIndicator());
3887+
3888+ auto device = createEthernetDevice(NM_DEVICE_STATE_ACTIVATED);
3889+ auto connection = createEthernetConnection("Home", device);
3890+ createActiveConnection("0", device, connection);
3891+
3892+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
3893+ .item(mh::MenuItemMatcher()
3894+ .state_icons({"gsm-3g-full", "network-wired-connected"})
3895+ .submenu()
3896+ .item(flightModeSwitch())
3897+ .item(mh::MenuItemMatcher()) // <-- modems are under here
3898+ .item(mh::MenuItemMatcher()
3899+ .section()
3900+ .item(ethernetInfo("Ethernet",
3901+ "Connected",
3902+ Toggle::enabled)
3903+ )
3904+ )
3905+ .item(ethernetSettings())
3906+ .item(mh::MenuItemMatcher()
3907+ .section()
3908+ )
3909+ ).match());
3910+}
3911+
3912+TEST_F(TestIndicator, TwoEthernetAfterStartupConnectedAndDisconnected)
3913+{
3914+ setGlobalConnectedState(NM_STATE_CONNECTED_GLOBAL);
3915+
3916+ ASSERT_NO_THROW(startIndicator());
3917+
3918+ // Active and connected with two connections
3919+ auto eth0 = createEthernetDevice(NM_DEVICE_STATE_ACTIVATED, "0");
3920+ auto eth0connection0 = createEthernetConnection("Home", eth0);
3921+ auto eth0connection1 = createEthernetConnection("Work", eth0);
3922+ createActiveConnection("0", eth0, eth0connection0);
3923+
3924+ // Active but disconnected
3925+ auto eth1 = createEthernetDevice(NM_DEVICE_STATE_DISCONNECTED, "1");
3926+ setNmProperty(eth1, NM_DBUS_INTERFACE_DEVICE, "Autoconnect", true);
3927+ auto eth1connection0 = createEthernetConnection("Home", eth1);
3928+
3929+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
3930+ .item(mh::MenuItemMatcher()
3931+ .state_icons({"gsm-3g-full", "network-wired-connected", "network-wired-offline"})
3932+ .submenu()
3933+ .item(flightModeSwitch())
3934+ .item(mh::MenuItemMatcher()) // <-- modems are under here
3935+ .item(mh::MenuItemMatcher()
3936+ .section()
3937+ .item(ethernetInfo("Ethernet (eth0)",
3938+ "Connected",
3939+ Toggle::enabled)
3940+ )
3941+ .item(radio("Home", Toggle::enabled))
3942+ .item(radio("Work", Toggle::disabled))
3943+ )
3944+ .item(mh::MenuItemMatcher()
3945+ .section()
3946+ .item(ethernetInfo("Ethernet (eth1)",
3947+ "Disconnected",
3948+ Toggle::enabled)
3949+ )
3950+ )
3951+ .item(ethernetSettings())
3952+ .item(mh::MenuItemMatcher()
3953+ .section()
3954+ )
3955+ ).match());
3956+}
3957+
3958+TEST_F(TestIndicator, ConnectToEthernet)
3959+{
3960+ setGlobalConnectedState(NM_STATE_DISCONNECTED);
3961+ auto device = createEthernetDevice(NM_DEVICE_STATE_DISCONNECTED);
3962+ auto connection = createEthernetConnection("Home", device);
3963+ OrgFreedesktopNetworkManagerDeviceInterface deviceInterface(NM_DBUS_SERVICE, device, dbusTestRunner.systemConnection());
3964+
3965+ ASSERT_NO_THROW(startIndicator());
3966+
3967+ EXPECT_FALSE(deviceInterface.autoconnect());
3968+ EXPECT_EQ(NM_DEVICE_STATE_DISCONNECTED, deviceInterface.state());
3969+ QDBusObjectPath activeConnection = deviceInterface.activeConnection();
3970+ EXPECT_EQ("/", activeConnection.path().toStdString());
3971+
3972+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
3973+ .item(mh::MenuItemMatcher()
3974+ .state_icons({"gsm-3g-full", "nm-no-connection"})
3975+ .submenu()
3976+ .item(flightModeSwitch())
3977+ .item(mh::MenuItemMatcher()) // <-- modems are under here
3978+ .item(mh::MenuItemMatcher()
3979+ .section()
3980+ .item(ethernetInfo("Ethernet",
3981+ "Disconnected",
3982+ Toggle::disabled)
3983+ .activate()
3984+ )
3985+ )
3986+ .item(ethernetSettings())
3987+ .item(mh::MenuItemMatcher()
3988+ .section()
3989+ )
3990+ ).match());
3991+
3992+ setGlobalConnectedState(NM_STATE_CONNECTED_GLOBAL);
3993+
3994+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
3995+ .item(mh::MenuItemMatcher()
3996+ .state_icons({"gsm-3g-full", "network-wired-connected"})
3997+ .submenu()
3998+ .item(flightModeSwitch())
3999+ .item(mh::MenuItemMatcher()) // <-- modems are under here
4000+ .item(mh::MenuItemMatcher()
4001+ .section()
4002+ .item(ethernetInfo("Ethernet",
4003+ "Connected",
4004+ Toggle::enabled)
4005+ )
4006+ )
4007+ .item(ethernetSettings())
4008+ .item(mh::MenuItemMatcher()
4009+ .section()
4010+ )
4011+ ).match());
4012+
4013+ EXPECT_TRUE(deviceInterface.autoconnect());
4014+ EXPECT_EQ(NM_DEVICE_STATE_ACTIVATED, deviceInterface.state());
4015+ activeConnection = deviceInterface.activeConnection();
4016+ EXPECT_NE("/", activeConnection.path().toStdString());
4017+}
4018+
4019+TEST_F(TestIndicator, ConnectToEthernetSelectProfile)
4020+{
4021+ setGlobalConnectedState(NM_STATE_DISCONNECTED);
4022+ auto device = createEthernetDevice(NM_DEVICE_STATE_DISCONNECTED);
4023+ auto homeConnection = createEthernetConnection("Home", device);
4024+ auto roamingConnection = createEthernetConnection("Roaming", device);
4025+ auto workConnection = createEthernetConnection("Work", device);
4026+ OrgFreedesktopNetworkManagerDeviceInterface deviceInterface(NM_DBUS_SERVICE, device, dbusTestRunner.systemConnection());
4027+
4028+ ASSERT_NO_THROW(startIndicator());
4029+
4030+ EXPECT_FALSE(deviceInterface.autoconnect());
4031+ EXPECT_EQ(NM_DEVICE_STATE_DISCONNECTED, deviceInterface.state());
4032+ QDBusObjectPath activeConnection = deviceInterface.activeConnection();
4033+ EXPECT_EQ("/", activeConnection.path().toStdString());
4034+
4035+ // First select a different profile
4036+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
4037+ .item(mh::MenuItemMatcher()
4038+ .mode(mh::MenuItemMatcher::Mode::starts_with)
4039+ .state_icons({"gsm-3g-full", "nm-no-connection"})
4040+ .submenu()
4041+ .item(flightModeSwitch())
4042+ .item(mh::MenuItemMatcher()) // <-- modems are under here
4043+ .item(mh::MenuItemMatcher()
4044+ .section()
4045+ .item(ethernetInfo("Ethernet",
4046+ "Disconnected",
4047+ Toggle::disabled)
4048+ )
4049+ .item(radio("Home", Toggle::enabled))
4050+ .item(radio("Roaming", Toggle::disabled))
4051+ .item(radio("Work", Toggle::disabled).activate())
4052+ )
4053+ ).match());
4054+
4055+ // Now connect
4056+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
4057+ .item(mh::MenuItemMatcher()
4058+ .mode(mh::MenuItemMatcher::Mode::starts_with)
4059+ .state_icons({"gsm-3g-full", "nm-no-connection"})
4060+ .submenu()
4061+ .item(flightModeSwitch())
4062+ .item(mh::MenuItemMatcher()) // <-- modems are under here
4063+ .item(mh::MenuItemMatcher()
4064+ .section()
4065+ .item(ethernetInfo("Ethernet",
4066+ "Disconnected",
4067+ Toggle::disabled)
4068+ .activate()
4069+ )
4070+ .item(radio("Home", Toggle::disabled))
4071+ .item(radio("Roaming", Toggle::disabled))
4072+ .item(radio("Work", Toggle::enabled))
4073+ )
4074+ ).match());
4075+
4076+ setGlobalConnectedState(NM_STATE_CONNECTED_GLOBAL);
4077+
4078+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
4079+ .item(mh::MenuItemMatcher()
4080+ .mode(mh::MenuItemMatcher::Mode::starts_with)
4081+ .state_icons({"gsm-3g-full", "network-wired-connected"})
4082+ .submenu()
4083+ .item(flightModeSwitch())
4084+ .item(mh::MenuItemMatcher()) // <-- modems are under here
4085+ .item(mh::MenuItemMatcher()
4086+ .section()
4087+ .item(ethernetInfo("Ethernet",
4088+ "Connected",
4089+ Toggle::enabled)
4090+ )
4091+ .item(radio("Home", Toggle::disabled))
4092+ .item(radio("Roaming", Toggle::disabled))
4093+ .item(radio("Work", Toggle::enabled))
4094+ )
4095+ ).match());
4096+
4097+ EXPECT_TRUE(deviceInterface.autoconnect());
4098+ EXPECT_EQ(NM_DEVICE_STATE_ACTIVATED, deviceInterface.state());
4099+ activeConnection = deviceInterface.activeConnection();
4100+ ASSERT_NE("/", activeConnection.path().toStdString());
4101+
4102+ // Check we're connected to the "Work" profile
4103+ OrgFreedesktopNetworkManagerConnectionActiveInterface activeConnectionInterface(NM_DBUS_SERVICE, activeConnection.path(), dbusTestRunner.systemConnection());
4104+ auto connection = activeConnectionInterface.connection();
4105+ EXPECT_EQ(workConnection, connection.path());
4106+}
4107+
4108+
4109+TEST_F(TestIndicator, DisconnectFromEthernet)
4110+{
4111+ setGlobalConnectedState(NM_STATE_CONNECTED_GLOBAL);
4112+ auto device = createEthernetDevice(NM_DEVICE_STATE_ACTIVATED);
4113+ auto connection = createEthernetConnection("Home", device);
4114+ createActiveConnection("0", device, connection);
4115+ OrgFreedesktopNetworkManagerDeviceInterface deviceInterface(NM_DBUS_SERVICE, device, dbusTestRunner.systemConnection());
4116+
4117+ ASSERT_NO_THROW(startIndicator());
4118+
4119+ EXPECT_TRUE(deviceInterface.autoconnect());
4120+ EXPECT_EQ(NM_DEVICE_STATE_ACTIVATED, deviceInterface.state());
4121+ QDBusObjectPath activeConnection = deviceInterface.activeConnection();
4122+ EXPECT_NE("/", activeConnection.path().toStdString());
4123+
4124+ auto& deviceMockInterface = dbusMock.mockInterface(NM_DBUS_SERVICE, device, NM_DBUS_INTERFACE_DEVICE, QDBusConnection::SystemBus);
4125+ QSignalSpy deviceSpy(&deviceMockInterface, SIGNAL(MethodCalled(const QString &, const QVariantList &)));
4126+
4127+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
4128+ .item(mh::MenuItemMatcher()
4129+ .state_icons({"gsm-3g-full", "network-wired-connected"})
4130+ .submenu()
4131+ .item(flightModeSwitch())
4132+ .item(mh::MenuItemMatcher()) // <-- modems are under here
4133+ .item(mh::MenuItemMatcher()
4134+ .section()
4135+ .item(ethernetInfo("Ethernet",
4136+ "Connected",
4137+ Toggle::enabled)
4138+ .activate()
4139+ )
4140+ )
4141+ .item(ethernetSettings())
4142+ .item(mh::MenuItemMatcher()
4143+ .section()
4144+ )
4145+ ).match());
4146+
4147+ setGlobalConnectedState(NM_STATE_DISCONNECTED);
4148+
4149+ EXPECT_MATCHRESULT(mh::MenuMatcher(phoneParameters())
4150+ .item(mh::MenuItemMatcher()
4151+ .state_icons({"gsm-3g-full", "nm-no-connection"})
4152+ .submenu()
4153+ .item(flightModeSwitch())
4154+ .item(mh::MenuItemMatcher()) // <-- modems are under here
4155+ .item(mh::MenuItemMatcher()
4156+ .section()
4157+ .item(ethernetInfo("Ethernet",
4158+ "Disconnected",
4159+ Toggle::disabled)
4160+ )
4161+ )
4162+ .item(ethernetSettings())
4163+ .item(mh::MenuItemMatcher()
4164+ .section()
4165+ )
4166+ ).match());
4167+
4168+ WAIT_FOR_SIGNALS(deviceSpy, 1);
4169+ ASSERT_EQ(1, deviceSpy.size());
4170+ {
4171+ auto & call = deviceSpy.at(0);
4172+ EXPECT_EQ("Disconnect", call.at(0).toString());
4173+ }
4174+
4175+ EXPECT_FALSE(deviceInterface.autoconnect());
4176+ EXPECT_EQ(NM_DEVICE_STATE_DISCONNECTED, deviceInterface.state());
4177+ activeConnection = deviceInterface.activeConnection();
4178+ EXPECT_EQ("/", activeConnection.path().toStdString());
4179 }
4180
4181 TEST_F(TestIndicator, OneDisconnectedAccessPointAtStartup)
4182@@ -202,8 +634,6 @@
4183 .item(modemInfo("SIM 2", "fake.tel", "gsm-3g-full"))
4184 .item(cellularSettings())
4185 )
4186- .item(wifiEnableSwitch())
4187- .item(wifiSettings())
4188 .item(mh::MenuItemMatcher()
4189 .section()
4190 )

Subscribers

People subscribed via source and target branches