Merge lp:~donadigo/switchboard-plug-networking/vpn into lp:~elementary-pantheon/switchboard-plug-networking/trunk

Proposed by Adam Bieńkowski
Status: Merged
Approved by: Danielle Foré
Approved revision: 273
Merged at revision: 272
Proposed branch: lp:~donadigo/switchboard-plug-networking/vpn
Merge into: lp:~elementary-pantheon/switchboard-plug-networking/trunk
Diff against target: 1380 lines (+794/-108)
19 files modified
src/CMakeLists.txt (+4/-0)
src/Plug.vala (+20/-20)
src/Utils.vala (+0/-10)
src/Widgets/Device/DeviceItem.vala (+5/-8)
src/Widgets/Device/DevicePage.vala (+5/-7)
src/Widgets/DeviceList.vala (+37/-14)
src/Widgets/EtherInterface.vala (+4/-4)
src/Widgets/HotspotInterface.vala (+2/-3)
src/Widgets/Page.vala (+30/-11)
src/Widgets/Proxy/ProxyPage.vala (+1/-2)
src/Widgets/SettingsButton.vala (+41/-0)
src/Widgets/VPNInfoBox.vala (+153/-0)
src/Widgets/VPNPage.vala (+327/-0)
src/Widgets/WifiInterface.vala (+8/-10)
src/common/Utils.vala (+7/-1)
src/common/Widgets/AbstractWifiInterface.vala (+0/-1)
src/common/Widgets/NMVisualizer.vala (+25/-13)
src/common/Widgets/VPNMenuItem.vala (+121/-0)
src/common/Widgets/WifiMenuItem.vala (+4/-4)
To merge this branch: bzr merge lp:~donadigo/switchboard-plug-networking/vpn
Reviewer Review Type Date Requested Status
Danielle Foré ux Needs Fixing
Corentin Noël code Pending
Review via email: mp+300922@code.launchpad.net

Commit message

- Fix bug #1440563: "Configure VPN".
- Fix bug #1579183: "Ignore virtual network hardware".
- Minor code clean ups.

Description of the change

Fixes bug #1440563: "Configure VPN" and bug #1579183: "Ignore virtual network hardware".

This branch adds VPN support, mainly for adding / displaying / editing and removing VPN connections from the plug. It makes use of the connection editor provided from Gnome which is already present in "Advanced settings" of devices. Then it updates the plug with new information as it's being changed.

Also it prevents virtual devices from showing now, which is an common update from:
https://code.launchpad.net/~donadigo/wingpanel-indicator-network/ignore-virtual-hardware/+merge/300343

There are also some code clean ups but they are rather minor.

To post a comment you must log in.
Revision history for this message
Danielle Foré (danrabbit) wrote :

I think Corentin had a nicer design for adding and managing VPNs. Maybe we can get him to share his sketches from the snappy sprint in #UX or upload his WIP branch. But the basics were that we followed the design for the Wireless section where you have one section "VPN" and then you manage the connections inside of that section.

review: Needs Fixing (ux)
Revision history for this message
Danielle Foré (danrabbit) wrote :

* Please use the icon "network-vpn", not "network-wireless-encrypted"
* Since we can't select in the list without activating, let's remove the "-" icon for now

review: Needs Fixing (ux)
Revision history for this message
Adam Bieńkowski (donadigo) wrote :

Updated.

Revision history for this message
Danielle Foré (danrabbit) wrote :

can you put the status back on VPN? I know it looks weird right now, but that's an icons bug and there's a report for it.

272. By Adam Bieńkowski

Add back the VPN status icon

273. By Adam Bieńkowski

Revert VPNPage strings from the last commit

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/CMakeLists.txt'
2--- src/CMakeLists.txt 2015-12-07 16:07:16 +0000
3+++ src/CMakeLists.txt 2016-07-26 21:06:49 +0000
4@@ -27,11 +27,15 @@
5 Widgets/Proxy/ProxyExceptionsPage.vala
6 Widgets/Proxy/ProxyPage.vala
7 Widgets/InfoBox.vala
8+ Widgets/SettingsButton.vala
9+ Widgets/VPNPage.vala
10+ Widgets/VPNInfoBox.vala
11 Widgets/Footer.vala
12 Widgets/InfoScreen.vala
13 Widgets/Hotspot/HotspotDialog.vala
14 common/Utils.vala
15 common/Widgets/WifiMenuItem.vala
16+ common/Widgets/VPNMenuItem.vala
17 common/Widgets/AbstractWifiInterface.vala
18 common/Widgets/AbstractEtherInterface.vala
19 common/Widgets/AbstractHotspotInterface.vala
20
21=== modified file 'src/Plug.vala'
22--- src/Plug.vala 2016-06-27 20:16:52 +0000
23+++ src/Plug.vala 2016-07-26 21:06:49 +0000
24@@ -41,19 +41,21 @@
25 private Widgets.DeviceList device_list;
26 private Widgets.Footer footer;
27 private Widgets.InfoScreen no_devices;
28-
29+
30 protected override void add_interface (WidgetNMInterface widget_interface) {
31- device_list.add_device_to_list (widget_interface);
32+ device_list.add_iface_to_list (widget_interface);
33
34 select_first ();
35 show_all ();
36 }
37
38 protected override void remove_interface (WidgetNMInterface widget_interface) {
39- device_list.remove_device_from_list (widget_interface.device);
40+ device_list.remove_iface_from_list (widget_interface);
41+
42 if (content.get_visible_child () == widget_interface) {
43+ var row = device_list.get_selected_row ();
44 int index = device_list.get_selected_row ().get_index ();
45- if (index >= 0) {
46+ if (row != null && row.get_index () >= 0) {
47 device_list.get_row_at_index (index).activate ();
48 } else {
49 select_first ();
50@@ -64,6 +66,14 @@
51 show_all ();
52 }
53
54+ protected override void add_connection (NM.RemoteConnection connection) {
55+ device_list.add_connection (connection);
56+ }
57+
58+ protected override void remove_connection (NM.RemoteConnection connection) {
59+ device_list.remove_connection (connection);
60+ }
61+
62 private void select_first () {
63 device_list.select_first_item ();
64 }
65@@ -100,7 +110,7 @@
66 sidebar.pack_start (scrolled_window, true, true);
67 sidebar.pack_start (footer, false, false);
68
69- paned.pack1 (sidebar, true, true);
70+ paned.pack1 (sidebar, false, false);
71 paned.pack2 (content, true, false);
72 paned.set_position (240);
73
74@@ -115,13 +125,14 @@
75 /* Main function to connect all the signals */
76 private void connect_signals () {
77 device_list.row_activated.connect ((row) => {
78- if (content.get_children ().find (((Widgets.DeviceItem)row).page) == null) {
79- content.add (((Widgets.DeviceItem) row).page);
80+ var page = ((Widgets.DeviceItem)row).page;
81+ if (content.get_children ().find (page) == null) {
82+ content.add (page);
83 }
84
85- content.visible_child = ((Widgets.DeviceItem)row).page;
86+ content.visible_child = page;
87 });
88-
89+
90 device_list.show_no_devices.connect ((show) => {
91 scrolled_window.sensitive = !show;
92 if (show) {
93@@ -142,17 +153,6 @@
94 }
95 });
96 }
97-
98- /*private void show_error_dialog () {
99- var error_dialog = new Gtk.MessageDialog (null, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, " ");
100- error_dialog.text = _("Could not enable device: there are no available
101-connections for this device.");
102- error_dialog.deletable = false;
103- error_dialog.show_all ();
104- error_dialog.response.connect ((response_id) => {
105- error_dialog.destroy ();
106- });
107- }*/
108 }
109
110 public class Plug : Switchboard.Plug {
111
112=== modified file 'src/Utils.vala'
113--- src/Utils.vala 2016-06-06 21:45:31 +0000
114+++ src/Utils.vala 2016-07-26 21:06:49 +0000
115@@ -184,16 +184,6 @@
116 INVALID
117 }
118
119- public static Gtk.Button get_advanced_button_from_device (NM.Device? device, string title = _("Advanced Settings…")) {
120- var details_btn = new Gtk.Button.with_label (title);
121- details_btn.clicked.connect (() => {
122- new Granite.Services.SimpleCommand ("/usr/bin",
123- "nm-connection-editor --edit=" + device.get_active_connection ().get_uuid ()).run ();
124- });
125-
126- return details_btn;
127- }
128-
129 public static string state_to_string (NM.DeviceState state) {
130 switch (state) {
131 case NM.DeviceState.ACTIVATED:
132
133=== modified file 'src/Widgets/Device/DeviceItem.vala'
134--- src/Widgets/Device/DeviceItem.vala 2016-02-12 15:09:30 +0000
135+++ src/Widgets/Device/DeviceItem.vala 2016-07-26 21:06:49 +0000
136@@ -21,7 +21,7 @@
137 public class DeviceItem : Gtk.ListBoxRow {
138 public NM.Device? device = null;
139 private NM.RemoteSettings? nm_settings = null;
140- public Gtk.Box? page = null;
141+ public Gtk.Widget? page = null;
142 public Utils.ItemType type;
143
144 public Gtk.Label row_description;
145@@ -134,6 +134,7 @@
146 case Network.State.CONNECTED_WIFI_GOOD:
147 case Network.State.CONNECTED_WIFI_EXCELLENT:
148 case Network.State.CONNECTED_WIRED:
149+ case Network.State.CONNECTED_VPN:
150 status_image.icon_name = "user-available";
151 break;
152 case Network.State.DISCONNECTED:
153@@ -141,20 +142,16 @@
154 break;
155 case Network.State.FAILED_WIRED:
156 case Network.State.FAILED_WIFI:
157+ case Network.State.FAILED_VPN:
158 status_image.icon_name = "user-busy";
159 break;
160- /*case NM.DeviceState.UNMANAGED:
161- status_image.icon_name = "user-invisible";
162- break;*/
163 default:
164 status_image.icon_name = "user-away";
165 break;
166 }
167
168 row_description.label = Common.Utils.network_state_to_string (state);
169- }
170-
171- if (custom_mode != Utils.CustomMode.INVALID) {
172+ } else if (custom_mode != Utils.CustomMode.INVALID) {
173 switch (custom_mode) {
174 case Utils.CustomMode.PROXY_NONE:
175 row_description.label = _("Disabled");
176@@ -169,7 +166,7 @@
177 status_image.icon_name = "user-available";
178 break;
179 }
180- }
181+ }
182
183 row_description.label = "<span font_size='small'>" + row_description.label + "</span>";
184 }
185
186=== modified file 'src/Widgets/Device/DevicePage.vala'
187--- src/Widgets/Device/DevicePage.vala 2016-02-12 15:09:30 +0000
188+++ src/Widgets/Device/DevicePage.vala 2016-07-26 21:06:49 +0000
189@@ -18,11 +18,10 @@
190 */
191
192 namespace Network.Widgets {
193- public class DevicePage : Network.WidgetNMInterface {
194+ public class DevicePage : WidgetNMInterface {
195
196 public DevicePage (NM.Client client, NM.RemoteSettings settings, NM.Device device) {
197- info_box = new InfoBox.from_device (device);
198- this.init (device, info_box);
199+ this.init (device);
200
201 bottom_revealer.transition_type = Gtk.RevealerTransitionType.NONE;
202
203@@ -30,7 +29,7 @@
204 display_title = Utils.type_to_string (device.get_device_type ());
205
206 var details_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
207- details_box.pack_end (Utils.get_advanced_button_from_device (device), false, false, 0);
208+ details_box.pack_end (new SettingsButton.from_device (device), false, false, 0);
209
210 update ();
211
212@@ -42,14 +41,13 @@
213 }
214
215 public DevicePage.from_owner (DeviceItem? owner) {
216- info_box = new InfoBox.from_owner (owner);
217- this.init (owner.get_item_device (), info_box);
218+ this.init (owner.get_item_device ());
219
220 this.icon_name = owner.get_item_icon_name ();
221 display_title = Utils.type_to_string (device.get_device_type ());
222
223 var details_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 0);
224- details_box.pack_start (Utils.get_advanced_button_from_device (device), false, false, 0);
225+ details_box.pack_start (new SettingsButton.from_device (device), false, false, 0);
226
227 update ();
228
229
230=== modified file 'src/Widgets/DeviceList.vala'
231--- src/Widgets/DeviceList.vala 2016-02-12 15:09:30 +0000
232+++ src/Widgets/DeviceList.vala 2016-07-26 21:06:49 +0000
233@@ -24,6 +24,7 @@
234 private Gtk.Label virtual_l;
235 private Gtk.Label devices_l;
236 private DeviceItem proxy;
237+ private DeviceItem vpn;
238
239 public DeviceList () {
240 virtual_l = new Gtk.Label (_("Virtual"));
241@@ -42,21 +43,15 @@
242 bool show = (get_children ().length () > 0);
243 this.show_no_devices (!show);
244 this.add_proxy ();
245+ this.add_vpn ();
246 }
247
248- public void add_device_to_list (WidgetNMInterface iface) {
249- DeviceItem item;
250+ public void add_iface_to_list (WidgetNMInterface iface) {
251+ DeviceItem item;
252 if (iface is AbstractWifiInterface) {
253- item = new DeviceItem.from_interface (iface, "network-wireless");
254+ item = new DeviceItem.from_interface (iface, "network-wireless");
255 } else if (iface is AbstractHotspotInterface) {
256 item = new DeviceItem.from_interface (iface, "network-wireless-hotspot");
257- item.no_show_all = true;
258- iface.device.state_changed.connect ((state) => {
259- item.visible = (state != NM.DeviceState.UNAVAILABLE
260- && state != NM.DeviceState.UNMANAGED
261- && state != NM.DeviceState.UNKNOWN);
262- });
263-
264 item.type = Utils.ItemType.VIRTUAL;
265 } else {
266 if (iface.device.get_iface ().has_prefix ("usb")) {
267@@ -70,17 +65,37 @@
268 show_all ();
269 }
270
271- public void remove_device_from_list (NM.Device device) {
272+ public void remove_iface_from_list (WidgetNMInterface iface) {
273 foreach (Gtk.Widget _list_item in get_children ()) {
274 var list_item = (DeviceItem)_list_item;
275- if (list_item.device == device) {
276+ if (list_item.page == iface) {
277 remove_row_from_list (list_item);
278 }
279 }
280 }
281
282+ public void add_connection (NM.RemoteConnection connection) {
283+ switch (connection.get_connection_type ()) {
284+ case NM.SettingVpn.SETTING_NAME:
285+ ((VPNPage)vpn.page).add_connection (connection);
286+ break;
287+ default:
288+ break;
289+ }
290+ }
291+
292+ public void remove_connection (NM.RemoteConnection connection) {
293+ switch (connection.get_connection_type ()) {
294+ case NM.SettingVpn.SETTING_NAME:
295+ ((VPNPage)vpn.page).remove_connection (connection);
296+ break;
297+ default:
298+ break;
299+ }
300+ }
301+
302 public void remove_row_from_list (DeviceItem item) {
303- this.remove (item);
304+ this.remove (item);
305 show_all ();
306 }
307
308@@ -91,7 +106,15 @@
309
310 this.add (proxy);
311 }
312-
313+
314+ private void add_vpn () {
315+ vpn = new DeviceItem (_("VPN"), "", "network-vpn");
316+ vpn.page = new VPNPage (vpn);
317+ vpn.type = Utils.ItemType.VIRTUAL;
318+
319+ this.add (vpn);
320+ }
321+
322 public void select_first_item () {
323 this.get_row_at_index (0).activate ();
324 }
325
326=== modified file 'src/Widgets/EtherInterface.vala'
327--- src/Widgets/EtherInterface.vala 2016-07-19 08:02:20 +0000
328+++ src/Widgets/EtherInterface.vala 2016-07-26 21:06:49 +0000
329@@ -18,13 +18,13 @@
330 */
331
332 namespace Network.Widgets {
333- public class EtherInterface : Network.AbstractEtherInterface {
334+ public class EtherInterface : AbstractEtherInterface {
335 private Gtk.Revealer top_revealer;
336
337 public EtherInterface (NM.Client client, NM.RemoteSettings settings, NM.Device device) {
338- info_box = new InfoBox.from_device (device);
339+ this.init (device);
340+
341 info_box.halign = Gtk.Align.CENTER;
342- this.init (device, info_box);
343
344 this.icon_name = "network-wired";
345
346@@ -34,7 +34,7 @@
347 top_revealer.add (info_box);
348
349 var button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);
350- button_box.pack_end (Utils.get_advanced_button_from_device (device), false, false, 0);
351+ button_box.pack_end (new SettingsButton.from_device (device), false, false, 0);
352
353 bottom_box.add (button_box);
354
355
356=== modified file 'src/Widgets/HotspotInterface.vala'
357--- src/Widgets/HotspotInterface.vala 2016-02-12 15:09:30 +0000
358+++ src/Widgets/HotspotInterface.vala 2016-07-26 21:06:49 +0000
359@@ -30,15 +30,14 @@
360 public HotspotInterface (WifiInterface _root_iface) {
361 root_iface = _root_iface;
362 nm_settings = _root_iface.get_nm_settings ();
363- info_box = new InfoBox.from_device (root_iface.device);
364- this.init (root_iface.device, info_box);
365+ this.init (root_iface.device);
366
367 this.icon_name = "network-wireless-hotspot";
368
369 hotspot_revealer = new Gtk.Revealer ();
370 hotspot_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN;
371
372- hotspot_settings_btn = Utils.get_advanced_button_from_device (device, _("Hotspot Settings…"));
373+ hotspot_settings_btn = new SettingsButton.from_device (device, _("Hotspot Settings…"));
374
375 var hinfo_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
376
377
378=== modified file 'src/Widgets/Page.vala'
379--- src/Widgets/Page.vala 2016-06-06 21:45:31 +0000
380+++ src/Widgets/Page.vala 2016-07-26 21:06:49 +0000
381@@ -34,7 +34,19 @@
382
383 set {
384 _icon_name = value;
385- device_img.icon_name = _icon_name;
386+ device_img.icon_name = value;
387+ }
388+ }
389+
390+ private string _title;
391+ public string title {
392+ get {
393+ return _title;
394+ }
395+
396+ set {
397+ _title = value;
398+ device_label.label = value;
399 }
400 }
401
402@@ -57,16 +69,13 @@
403 bottom_revealer.add (bottom_box);
404 }
405
406- public void init (NM.Device _device, Widgets.InfoBox _info_box) {
407+ public void init (NM.Device? _device) {
408 this.device = _device;
409- this.info_box = _info_box;
410- info_box.margin_end = 16;
411- info_box.info_changed.connect (update);
412-
413- device_img = new Gtk.Image.from_icon_name (_icon_name, Gtk.IconSize.DIALOG);
414+
415+ device_img = new Gtk.Image.from_icon_name (icon_name, Gtk.IconSize.DIALOG);
416 device_img.pixel_size = 48;
417
418- device_label = new Gtk.Label (Utils.type_to_string (device.get_device_type ()));
419+ device_label = new Gtk.Label (null);
420 device_label.ellipsize = Pango.EllipsizeMode.MIDDLE;
421 device_label.get_style_context ().add_class ("h2");
422
423@@ -76,6 +85,14 @@
424
425 control_switch.notify["active"].connect (control_switch_activated);
426
427+ if (device != null) {
428+ this.info_box = new InfoBox.from_device (device);
429+ info_box.margin_end = 16;
430+ info_box.info_changed.connect (update);
431+
432+ title = Utils.type_to_string (device.get_device_type ());
433+ }
434+
435 control_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 12);
436 control_box.pack_start (device_img, false, false, 0);
437 control_box.pack_start (device_label, false, false, 0);
438@@ -86,9 +103,11 @@
439 }
440
441 public virtual void update () {
442- string sent_bytes, received_bytes;
443- this.get_activity_information (device.get_iface (), out sent_bytes, out received_bytes);
444- info_box.update_activity (sent_bytes, received_bytes);
445+ if (info_box != null) {
446+ string sent_bytes, received_bytes;
447+ this.get_activity_information (device.get_iface (), out sent_bytes, out received_bytes);
448+ info_box.update_activity (sent_bytes, received_bytes);
449+ }
450
451 update_switch ();
452
453
454=== modified file 'src/Widgets/Proxy/ProxyPage.vala'
455--- src/Widgets/Proxy/ProxyPage.vala 2016-02-12 15:09:30 +0000
456+++ src/Widgets/Proxy/ProxyPage.vala 2016-07-26 21:06:49 +0000
457@@ -42,7 +42,6 @@
458 stackswitcher.stack = stack;
459
460 proxy_settings.changed.connect (update_mode);
461-
462 update_mode ();
463
464 this.add (stackswitcher);
465@@ -52,7 +51,7 @@
466 stack.visible_child = configuration_page;
467 }
468
469- public void update_mode () {
470+ private void update_mode () {
471 var mode = Utils.CustomMode.INVALID;
472 switch (proxy_settings.mode) {
473 case "none":
474
475=== added file 'src/Widgets/SettingsButton.vala'
476--- src/Widgets/SettingsButton.vala 1970-01-01 00:00:00 +0000
477+++ src/Widgets/SettingsButton.vala 2016-07-26 21:06:49 +0000
478@@ -0,0 +1,41 @@
479+/*-
480+ * Copyright (c) 2015-2016 elementary LLC.
481+ *
482+ * This program is free software: you can redistribute it and/or modify
483+ * it under the terms of the GNU Lesser General Public License as published by
484+ * the Free Software Foundation, either version 2.1 of the License, or
485+ * (at your option) any later version.
486+ *
487+ * This program is distributed in the hope that it will be useful,
488+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
489+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
490+ * GNU Lesser General Public License for more details.
491+ *
492+ * You should have received a copy of the GNU Lesser General Public License
493+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
494+ *
495+ * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
496+ */
497+
498+ namespace Network.Widgets {
499+ public class SettingsButton : Gtk.Button {
500+ private string uuid = "";
501+
502+ construct {
503+ clicked.connect (() => {
504+ new Granite.Services.SimpleCommand ("/usr/bin",
505+ "nm-connection-editor --edit=%s".printf (uuid)).run ();
506+ });
507+ }
508+
509+ public SettingsButton.from_device (NM.Device device, string title = _("Advanced Settings…")) {
510+ label = title;
511+ uuid = device.get_active_connection ().get_uuid ();
512+ }
513+
514+ public SettingsButton.from_connection (NM.Connection connection, string title = _("Advanced Settings…")) {
515+ label = title;
516+ uuid = connection.get_uuid ();
517+ }
518+ }
519+}
520\ No newline at end of file
521
522=== added file 'src/Widgets/VPNInfoBox.vala'
523--- src/Widgets/VPNInfoBox.vala 1970-01-01 00:00:00 +0000
524+++ src/Widgets/VPNInfoBox.vala 2016-07-26 21:06:49 +0000
525@@ -0,0 +1,153 @@
526+/*-
527+ * Copyright (c) 2015-2016 elementary LLC.
528+ *
529+ * This program is free software: you can redistribute it and/or modify
530+ * it under the terms of the GNU Lesser General Public License as published by
531+ * the Free Software Foundation, either version 2.1 of the License, or
532+ * (at your option) any later version.
533+ *
534+ * This program is distributed in the hope that it will be useful,
535+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
536+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
537+ * GNU Lesser General Public License for more details.
538+ *
539+ * You should have received a copy of the GNU Lesser General Public License
540+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
541+ *
542+ * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
543+ */
544+
545+namespace Network.Widgets {
546+ public class VPNInfoBox : Gtk.Grid {
547+ private NM.RemoteConnection? connection = null;
548+ private string service_type;
549+
550+ private Gtk.Label type;
551+ private Gtk.Label gateway;
552+ private Gtk.Label username;
553+ private Gtk.Label password;
554+
555+ public VPNInfoBox () {
556+ column_spacing = 12;
557+ row_spacing = 6;
558+
559+ var type_head = new Gtk.Label (_("VPN Type:"));
560+ type_head.halign = Gtk.Align.END;
561+
562+ var gateway_head = new Gtk.Label (_("Gateway:"));
563+ gateway_head.halign = Gtk.Align.END;
564+
565+ var username_head = new Gtk.Label (_("Username:"));
566+ username_head.halign = Gtk.Align.END;
567+
568+ var password_head = new Gtk.Label (_("Password:"));
569+ password_head.halign = Gtk.Align.END;
570+
571+ type = new Gtk.Label ("");
572+ type.selectable = true;
573+ type.xalign = 0;
574+ type.no_show_all = true;
575+
576+ gateway = new Gtk.Label ("");
577+ gateway.selectable = true;
578+ gateway.xalign = 0;
579+ gateway.no_show_all = true;
580+
581+ username = new Gtk.Label ("");
582+ username.selectable = true;
583+ username.xalign = 0;
584+ username.no_show_all = true;
585+
586+ password = new Gtk.Label ("");
587+ password.selectable = true;
588+ password.xalign = 0;
589+ password_head.no_show_all = true;
590+
591+ attach (type_head, 0, 0);
592+ attach_next_to (type, type_head, Gtk.PositionType.RIGHT);
593+
594+ attach_next_to (gateway_head, type_head, Gtk.PositionType.BOTTOM);
595+ attach_next_to (gateway, gateway_head, Gtk.PositionType.RIGHT);
596+
597+ attach_next_to (username_head, gateway_head, Gtk.PositionType.BOTTOM);
598+ attach_next_to (username, username_head, Gtk.PositionType.RIGHT);
599+
600+ attach_next_to (password_head, username_head, Gtk.PositionType.BOTTOM);
601+ attach_next_to (password, password_head, Gtk.PositionType.RIGHT);
602+ }
603+
604+ public void set_connection (NM.RemoteConnection _connection) {
605+ connection = _connection;
606+ connection.changed.connect (update_status);
607+ update_status ();
608+ }
609+
610+ // From https://github.com/GNOME/gnome-control-center/blob/master/panels/network/net-vpn.c
611+ private string get_key_group_username () {
612+ switch (service_type) {
613+ case "openvpn":
614+ case "openconnect":
615+ return "username";
616+ case "vpnc":
617+ return "Xauth username";
618+ case "pptp":
619+ return "user";
620+ case "openswan":
621+ return "leftxauthusername";
622+ }
623+
624+ return "";
625+ }
626+
627+ private string get_key_group_password () {
628+ if (service_type == "vpnc") {
629+ return "Xauth password";
630+ }
631+
632+ return "";
633+ }
634+
635+ private string get_key_gateway () {
636+ switch (service_type) {
637+ case "openvpn":
638+ return "remote";
639+ case "vpnc":
640+ return "IPSec gateway";
641+ case "pptp":
642+ case "openconnect":
643+ return "gateway";
644+ case "openswan":
645+ return "right";
646+ }
647+
648+ return "";
649+ }
650+
651+
652+ private string get_service_type () {
653+ var setting_vpn = connection.get_setting_vpn ();
654+ string service_type = setting_vpn.get_service_type ();
655+ string[] arr = service_type.split (".");
656+ return arr[arr.length - 1];
657+ }
658+
659+ public void update_status () {
660+ if (connection == null) {
661+ return;
662+ }
663+
664+ service_type = get_service_type ();
665+
666+ var setting_vpn = connection.get_setting_vpn ();
667+ type.label = get_service_type ();
668+ gateway.label = setting_vpn.get_data_item (get_key_gateway ());
669+ username.label = setting_vpn.get_data_item (get_key_group_username ());
670+ password.label = setting_vpn.get_data_item (get_key_group_password ());
671+
672+ type.visible = type.label != "";
673+ gateway.visible = gateway.label != "";
674+ username.visible = username.label != "";
675+ password.visible = password.label != "";
676+ }
677+ }
678+}
679\ No newline at end of file
680
681=== added file 'src/Widgets/VPNPage.vala'
682--- src/Widgets/VPNPage.vala 1970-01-01 00:00:00 +0000
683+++ src/Widgets/VPNPage.vala 2016-07-26 21:06:49 +0000
684@@ -0,0 +1,327 @@
685+/*-
686+ * Copyright (c) 2015-2016 elementary LLC.
687+ *
688+ * This program is free software: you can redistribute it and/or modify
689+ * it under the terms of the GNU Lesser General Public License as published by
690+ * the Free Software Foundation, either version 2.1 of the License, or
691+ * (at your option) any later version.
692+ *
693+ * This program is distributed in the hope that it will be useful,
694+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
695+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
696+ * GNU Lesser General Public License for more details.
697+ *
698+ * You should have received a copy of the GNU Lesser General Public License
699+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
700+ *
701+ * Authored by: Adam Bieńkowski <donadigos159@gmail.com>
702+ */
703+
704+using Network.Widgets;
705+
706+namespace Network {
707+ public class VPNPage : WidgetNMInterface {
708+ private DeviceItem owner;
709+ private NM.VPNConnection? active_connection = null;
710+ private VPNMenuItem? active_vpn_item = null;
711+
712+ private Gtk.Frame connected_frame;
713+ private Gtk.ListBox vpn_list;
714+ private VPNInfoBox vpn_info_box;
715+ private VPNMenuItem blank_item;
716+ private Gtk.ScrolledWindow scrolled;
717+ private Gtk.Box? connected_box = null;
718+ private Gtk.Button? disconnect_btn;
719+ private Gtk.Button? settings_btn;
720+ private Gtk.ToggleButton? info_btn;
721+ private Gtk.Revealer top_revealer;
722+ private Gtk.Popover popover;
723+
724+ public VPNPage (DeviceItem _owner) {
725+ owner = _owner;
726+
727+ this.init (null);
728+ this.title = "Virtual Private Network";
729+ this.icon_name = "network-vpn";
730+
731+ this.spacing = 0;
732+ control_box.margin_bottom = 12;
733+
734+ vpn_info_box = new VPNInfoBox ();
735+
736+ popover = new Gtk.Popover (info_btn);
737+ popover.position = Gtk.PositionType.BOTTOM;
738+ popover.add (vpn_info_box);
739+ popover.hide.connect (() => {
740+ info_btn.active = false;
741+ });
742+
743+ connected_frame = new Gtk.Frame (null);
744+ connected_frame.override_background_color (0, { 255, 255, 255, 255 });
745+
746+ top_revealer = new Gtk.Revealer ();
747+ top_revealer.transition_type = Gtk.RevealerTransitionType.SLIDE_DOWN;
748+ top_revealer.add (connected_frame);
749+
750+ var no_connections_box = new Gtk.Box (Gtk.Orientation.VERTICAL, 6);
751+ no_connections_box.visible = true;
752+ no_connections_box.valign = Gtk.Align.CENTER;
753+
754+ var no_connections_label = new Gtk.Label (_("No VPN Connections"));
755+ no_connections_label.valign = Gtk.Align.CENTER;
756+ no_connections_label.wrap = true;
757+ no_connections_label.wrap_mode = Pango.WrapMode.WORD_CHAR;
758+ no_connections_label.max_width_chars = 30;
759+ no_connections_label.justify = Gtk.Justification.CENTER;
760+ no_connections_label.get_style_context ().add_class ("h2");
761+
762+ var second_label = new Gtk.Label (_("Add a new VPN connection to begin."));
763+ second_label.valign = Gtk.Align.CENTER;
764+ second_label.wrap = true;
765+ second_label.wrap_mode = Pango.WrapMode.WORD_CHAR;
766+ second_label.max_width_chars = 30;
767+ second_label.justify = Gtk.Justification.CENTER;
768+
769+ no_connections_box.add (no_connections_label);
770+ no_connections_box.add (second_label);
771+ no_connections_box.show_all ();
772+
773+ vpn_list = new Gtk.ListBox ();
774+ vpn_list.activate_on_single_click = false;
775+ vpn_list.visible = true;
776+ vpn_list.set_placeholder (no_connections_box);
777+
778+ var toolbar = new Gtk.Toolbar ();
779+ toolbar.get_style_context ().add_class (Gtk.STYLE_CLASS_INLINE_TOOLBAR);
780+ toolbar.icon_size = Gtk.IconSize.SMALL_TOOLBAR;
781+
782+ var add_button = new Gtk.ToolButton (new Gtk.Image.from_icon_name ("list-add-symbolic", Gtk.IconSize.SMALL_TOOLBAR), null);
783+ add_button.tooltip_text = _("Add VPN Connection…");
784+ add_button.clicked.connect (() => {
785+ add_button.sensitive = false;
786+ var command = new Granite.Services.SimpleCommand ("/usr/bin",
787+ "nm-connection-editor --create --type=vpn");
788+ command.done.connect ((exit) => {
789+ if (exit != 0) {
790+ var dialog = new Gtk.MessageDialog (null, Gtk.DialogFlags.MODAL, Gtk.MessageType.ERROR, Gtk.ButtonsType.CLOSE, _("Failed to run Connection Editor."));
791+ dialog.run ();
792+ dialog.destroy ();
793+ }
794+
795+ add_button.sensitive = true;
796+ });
797+
798+ command.run ();
799+ });
800+
801+ toolbar.add (add_button);
802+
803+ blank_item = new VPNMenuItem.blank ();
804+
805+ scrolled = new Gtk.ScrolledWindow (null, null);
806+ scrolled.expand = true;
807+ scrolled.add (vpn_list);
808+
809+ var list_root = new Gtk.Grid ();
810+ list_root.attach (scrolled, 0, 0, 1, 1);
811+ list_root.attach (toolbar, 0, 1, 1, 1);
812+
813+ var main_frame = new Gtk.Frame (null);
814+ main_frame.margin_bottom = 24;
815+ main_frame.margin_top = 12;
816+ main_frame.vexpand = true;
817+ main_frame.override_background_color (0, { 255, 255, 255, 255 });
818+ main_frame.add (list_root);
819+
820+ control_switch.no_show_all = true;
821+ control_switch.visible = false;
822+
823+ this.add (top_revealer);
824+ this.add (main_frame);
825+ this.add (bottom_revealer);
826+ this.show_all ();
827+
828+ client.notify["active-connections"].connect (update_active_connection);
829+ update ();
830+ }
831+
832+ protected override void update () {
833+ update_active_connection ();
834+
835+ bool sensitive = false;
836+ VPNMenuItem? item = null;
837+ if (active_connection != null) {
838+ switch (active_connection.get_vpn_state ()) {
839+ case NM.VPNConnectionState.UNKNOWN:
840+ case NM.VPNConnectionState.DISCONNECTED:
841+ state = State.DISCONNECTED;
842+ break;
843+ case NM.VPNConnectionState.PREPARE:
844+ case NM.VPNConnectionState.IP_CONFIG_GET:
845+ case NM.VPNConnectionState.CONNECT:
846+ state = State.CONNECTING_VPN;
847+ item = get_item_by_uuid (active_connection.get_uuid ());
848+ item.state = state;
849+ break;
850+ case NM.VPNConnectionState.FAILED:
851+ state = State.FAILED_VPN;
852+ break;
853+ case NM.VPNConnectionState.ACTIVATED:
854+ state = State.CONNECTED_VPN;
855+ item = get_item_by_uuid (active_connection.get_uuid ());
856+ item.state = state;
857+ sensitive = true;
858+ break;
859+ }
860+ } else {
861+ state = State.DISCONNECTED;
862+ }
863+
864+ if (item == null) {
865+ top_revealer.set_reveal_child (false);
866+ blank_item.set_active (true);
867+
868+ if (active_vpn_item != null) {
869+ active_vpn_item.no_show_all = false;
870+ active_vpn_item.visible = true;
871+ active_vpn_item.state = state;
872+ }
873+ } else {
874+ top_revealer.set_reveal_child (true);
875+ if (connected_frame != null && connected_frame.get_child () != null) {
876+ connected_frame.get_child ().destroy ();
877+ }
878+
879+ connected_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);
880+ item.no_show_all = true;
881+ item.visible = false;
882+
883+ var top_item = new VPNMenuItem (item.connection, null);
884+ top_item.hide_icons (false);
885+
886+ connected_box.add (top_item);
887+
888+ disconnect_btn = new Gtk.Button.with_label (_("Disconnect"));
889+ disconnect_btn.get_style_context ().add_class ("destructive-action");
890+ disconnect_btn.clicked.connect (vpn_deactivate_cb);
891+
892+ settings_btn = new SettingsButton.from_connection (item.connection, _("Settings…"));
893+
894+ info_btn = new Gtk.ToggleButton ();
895+ info_btn.margin_top = info_btn.margin_bottom = 6;
896+ info_btn.get_style_context ().add_class ("flat");
897+ info_btn.image = new Gtk.Image.from_icon_name ("view-more-symbolic", Gtk.IconSize.SMALL_TOOLBAR);
898+
899+ vpn_info_box.set_connection (item.connection);
900+
901+ popover.relative_to = info_btn;
902+
903+ info_btn.toggled.connect (() => {
904+ popover.visible = info_btn.get_active ();
905+ });
906+
907+ var button_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);
908+ button_box.homogeneous = true;
909+ button_box.margin = 6;
910+ button_box.pack_end (disconnect_btn, false, false, 0);
911+ button_box.pack_end (settings_btn, false, false, 0);
912+ button_box.show_all ();
913+
914+ connected_box.pack_end (button_box, false, false, 0);
915+ connected_box.pack_end (info_btn, false, false, 0);
916+ connected_frame.add (connected_box);
917+
918+ connected_box.show_all ();
919+ connected_frame.show_all ();
920+
921+ if (disconnect_btn != null) {
922+ disconnect_btn.sensitive = sensitive;
923+ }
924+
925+ if (settings_btn != null) {
926+ settings_btn.sensitive = sensitive;
927+ }
928+
929+ if (info_btn != null) {
930+ info_btn.sensitive = sensitive;
931+ }
932+ }
933+
934+ owner.switch_status (Utils.CustomMode.INVALID, state);
935+ update_switch ();
936+ }
937+
938+ protected override void update_switch () {
939+
940+ }
941+
942+ protected override void control_switch_activated () {
943+
944+ }
945+
946+ public void add_connection (NM.RemoteConnection connection) {
947+ var item = new VPNMenuItem (connection, get_previous_menu_item ());
948+ item.user_action.connect (vpn_activate_cb);
949+
950+ vpn_list.add (item);
951+ update ();
952+ this.show_all ();
953+ }
954+
955+ public void remove_connection (NM.RemoteConnection connection) {
956+ var item = get_item_by_uuid (connection.get_uuid ());
957+ item.destroy ();
958+ }
959+
960+ private VPNMenuItem? get_item_by_uuid (string uuid) {
961+ VPNMenuItem? item = null;
962+ foreach (var child in vpn_list.get_children ()) {
963+ var _item = (VPNMenuItem)child;
964+ if (_item.connection != null && _item.connection.get_uuid () == uuid && item == null) {
965+ item = (VPNMenuItem)child;
966+ }
967+ }
968+
969+ return item;
970+ }
971+
972+ private VPNMenuItem? get_previous_menu_item () {
973+ var children = vpn_list.get_children ();
974+ if (children.length () == 0) {
975+ return blank_item;
976+ }
977+
978+ return (VPNMenuItem)children.last ().data;
979+ }
980+
981+ private void update_active_connection () {
982+ active_connection = null;
983+
984+ client.get_active_connections ().foreach ((ac) => {
985+ if (ac.get_vpn () && active_connection == null) {
986+ active_connection = (NM.VPNConnection)ac;
987+ active_connection.vpn_state_changed.connect (update);
988+ }
989+ });
990+ }
991+
992+ private void vpn_activate_cb (VPNMenuItem item) {
993+ active_vpn_item = item;
994+ foreach (var child in vpn_list.get_children ()) {
995+ ((VPNMenuItem)child).hide_icons ();
996+ }
997+
998+ update ();
999+ client.activate_connection (item.connection, null, null, null);
1000+ }
1001+
1002+ private void vpn_deactivate_cb () {
1003+ update_active_connection ();
1004+ if (active_connection == null) {
1005+ return;
1006+ }
1007+
1008+ client.deactivate_connection (active_connection);
1009+ }
1010+ }
1011+}
1012\ No newline at end of file
1013
1014=== modified file 'src/Widgets/WifiInterface.vala'
1015--- src/Widgets/WifiInterface.vala 2016-07-03 17:45:10 +0000
1016+++ src/Widgets/WifiInterface.vala 2016-07-26 21:06:49 +0000
1017@@ -27,16 +27,16 @@
1018 protected Gtk.Box hotspot_mode_box;
1019 protected Gtk.Box? connected_box = null;
1020 protected Gtk.Revealer top_revealer;
1021- protected Gtk.Button disconnect_btn;
1022- protected Gtk.Button settings_btn;
1023- protected Gtk.Button hidden_btn;
1024+ protected Gtk.Button? disconnect_btn;
1025+ protected Gtk.Button? settings_btn;
1026+ protected Gtk.Button? hidden_btn;
1027 protected Gtk.ToggleButton info_btn;
1028 protected Gtk.Popover popover;
1029
1030- public WifiInterface (NM.Client nm_client, NM.RemoteSettings settings, NM.Device _device) {
1031- info_box = new InfoBox.from_device (_device);
1032+ public WifiInterface (NM.Client nm_client, NM.RemoteSettings settings, NM.Device device) {
1033+ this.init (device);
1034+
1035 info_box.margin = 12;
1036- this.init (_device, info_box);
1037
1038 popover = new Gtk.Popover (info_btn);
1039 popover.position = Gtk.PositionType.BOTTOM;
1040@@ -151,9 +151,7 @@
1041 }
1042
1043 disconnect_btn = settings_btn = null;
1044- }
1045-
1046- else if (wifi_device.get_active_access_point () != null && active_wifi_item != old_active) {
1047+ } else if (wifi_device.get_active_access_point () != null && active_wifi_item != old_active) {
1048
1049 if (old_active != null) {
1050 old_active.no_show_all = false;
1051@@ -179,7 +177,7 @@
1052 device.disconnect (null);
1053 });
1054
1055- settings_btn = Utils.get_advanced_button_from_device (wifi_device, _("Settings…"));
1056+ settings_btn = new SettingsButton.from_device (wifi_device, _("Settings…"));
1057 settings_btn.sensitive = (device.get_state () == NM.DeviceState.ACTIVATED);
1058
1059 info_btn = new Gtk.ToggleButton ();
1060
1061=== modified file 'src/common/Utils.vala'
1062--- src/common/Utils.vala 2016-06-06 21:45:31 +0000
1063+++ src/common/Utils.vala 2016-07-26 21:06:49 +0000
1064@@ -19,6 +19,7 @@
1065 DISCONNECTED,
1066 WIRED_UNPLUGGED,
1067 CONNECTED_WIRED,
1068+ CONNECTED_VPN,
1069 CONNECTED_WIFI,
1070 CONNECTED_WIFI_WEAK,
1071 CONNECTED_WIFI_OK,
1072@@ -26,8 +27,10 @@
1073 CONNECTED_WIFI_EXCELLENT,
1074 CONNECTING_WIFI,
1075 CONNECTING_WIRED,
1076+ CONNECTING_VPN,
1077 FAILED_WIRED,
1078- FAILED_WIFI
1079+ FAILED_WIFI,
1080+ FAILED_VPN
1081 }
1082
1083 namespace Network.Common.Utils {
1084@@ -41,12 +44,15 @@
1085 case Network.State.CONNECTED_WIFI_GOOD:
1086 case Network.State.CONNECTED_WIFI_EXCELLENT:
1087 case Network.State.CONNECTED_WIRED:
1088+ case Network.State.CONNECTED_VPN:
1089 return _("Connected");
1090 case Network.State.FAILED_WIRED:
1091 case Network.State.FAILED_WIFI:
1092+ case Network.State.FAILED_VPN:
1093 return _("Failed");
1094 case Network.State.CONNECTING_WIFI:
1095 case Network.State.CONNECTING_WIRED:
1096+ case Network.State.CONNECTING_VPN:
1097 return _("Connecting");
1098 case Network.State.WIRED_UNPLUGGED:
1099 return _("Cable unplugged");
1100
1101=== modified file 'src/common/Widgets/AbstractWifiInterface.vala'
1102--- src/common/Widgets/AbstractWifiInterface.vala 2016-02-12 17:40:30 +0000
1103+++ src/common/Widgets/AbstractWifiInterface.vala 2016-07-26 21:06:49 +0000
1104@@ -172,7 +172,6 @@
1105
1106 update ();
1107 }
1108-
1109 }
1110
1111 void update_active_ap () {
1112
1113=== modified file 'src/common/Widgets/NMVisualizer.vala'
1114--- src/common/Widgets/NMVisualizer.vala 2015-12-19 16:34:47 +0000
1115+++ src/common/Widgets/NMVisualizer.vala 2016-07-26 21:06:49 +0000
1116@@ -31,13 +31,15 @@
1117 /* Monitor network manager */
1118 nm_client = new NM.Client ();
1119 nm_settings = new NM.RemoteSettings (null);
1120+ nm_settings.new_connection.connect (new_connection_cb);
1121
1122 nm_client.device_added.connect (device_added_cb);
1123 nm_client.device_removed.connect (device_removed_cb);
1124
1125 var devices = nm_client.get_devices ();
1126- for (var i = 0; i < devices.length; i++)
1127+ for (var i = 0; i < devices.length; i++) {
1128 device_added_cb (devices.get (i));
1129+ }
1130
1131 show_all();
1132 }
1133@@ -45,6 +47,8 @@
1134 protected abstract void build_ui ();
1135 protected abstract void add_interface (WidgetNMInterface widget_interface);
1136 protected abstract void remove_interface (WidgetNMInterface widget_interface);
1137+ protected abstract void add_connection (NM.RemoteConnection connection);
1138+ protected abstract void remove_connection (NM.RemoteConnection connection);
1139
1140 void device_removed_cb (NM.Device device) {
1141 foreach (var widget_interface in network_interface) {
1142@@ -66,8 +70,7 @@
1143 var type = iface.get_type ().name ();
1144 if (count_type.has_key (type)) {
1145 count_type[type] = count_type[type] + 1;
1146- }
1147- else {
1148+ } else {
1149 count_type[type] = 1;
1150 }
1151 }
1152@@ -78,7 +81,21 @@
1153 }
1154 }
1155
1156+ void new_connection_cb (Object obj) {
1157+ var connection = (NM.RemoteConnection)obj;
1158+ connection.removed.connect (() => {
1159+ remove_connection (connection);
1160+ });
1161+
1162+ add_connection (connection);
1163+ }
1164+
1165 private void device_added_cb (NM.Device device) {
1166+ if (device.get_iface ().has_prefix ("vmnet") ||
1167+ device.get_iface ().has_prefix ("lo")) {
1168+ return;
1169+ }
1170+
1171 WidgetNMInterface? widget_interface = null;
1172 #if PLUG_NETWORK
1173 WidgetNMInterface? hotspot_interface = null;
1174@@ -87,7 +104,7 @@
1175 if (device is NM.DeviceWifi) {
1176 widget_interface = new WifiInterface (nm_client, nm_settings, device);
1177 #if PLUG_NETWORK
1178- hotspot_interface = new HotspotInterface((WifiInterface)widget_interface);
1179+ hotspot_interface = new HotspotInterface ((WifiInterface)widget_interface);
1180 #endif
1181
1182 debug ("Wifi interface added");
1183@@ -110,22 +127,18 @@
1184 if (hotspot_interface != null) {
1185 // Implementation call
1186 network_interface.append (hotspot_interface);
1187- add_interface(hotspot_interface);
1188+ add_interface (hotspot_interface);
1189 hotspot_interface.notify["state"].connect(update_state);
1190-
1191 }
1192 #endif
1193
1194 update_interfaces_names ();
1195-
1196-
1197- update_all();
1198-
1199- show_all();
1200+ update_all ();
1201+ show_all ();
1202 }
1203
1204 void update_all () {
1205- foreach(var inter in network_interface) {
1206+ foreach (var inter in network_interface) {
1207 inter.update ();
1208 }
1209 }
1210@@ -140,5 +153,4 @@
1211
1212 state = next_state;
1213 }
1214-
1215 }
1216
1217=== added file 'src/common/Widgets/VPNMenuItem.vala'
1218--- src/common/Widgets/VPNMenuItem.vala 1970-01-01 00:00:00 +0000
1219+++ src/common/Widgets/VPNMenuItem.vala 2016-07-26 21:06:49 +0000
1220@@ -0,0 +1,121 @@
1221+/*
1222+ * Copyright (c) 2015 Wingpanel Developers (http://launchpad.net/wingpanel)
1223+ *
1224+ * This program is free software: you can redistribute it and/or modify
1225+ * it under the terms of the GNU Library General Public License as published by
1226+ * the Free Software Foundation, either version 2.1 of the License, or
1227+ * (at your option) any later version.
1228+ *
1229+ * This program is distributed in the hope that it will be useful,
1230+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
1231+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1232+ * GNU Library General Public License for more details.
1233+ *
1234+ * You should have received a copy of the GNU Library General Public License
1235+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
1236+ */
1237+
1238+public class Network.VPNMenuItem : Gtk.ListBoxRow {
1239+ public signal void user_action();
1240+ public NM.RemoteConnection? connection;
1241+
1242+ public Network.State state { get; set; default = Network.State.DISCONNECTED; }
1243+
1244+ Gtk.RadioButton radio_button;
1245+ Gtk.Spinner spinner;
1246+ Gtk.Image error_img;
1247+ Gtk.Button remove_button;
1248+
1249+ public VPNMenuItem (NM.RemoteConnection _connection, VPNMenuItem? previous = null) {
1250+ connection = _connection;
1251+
1252+ var main_box = new Gtk.Box (Gtk.Orientation.HORIZONTAL, 6);
1253+ main_box.margin_start = main_box.margin_end = 6;
1254+ radio_button = new Gtk.RadioButton(null);
1255+ if (previous != null) radio_button.set_group (previous.get_group ());
1256+
1257+ radio_button.button_release_event.connect ( (b, ev) => {
1258+ user_action();
1259+ return false;
1260+ });
1261+
1262+ error_img = new Gtk.Image.from_icon_name ("process-error-symbolic", Gtk.IconSize.MENU);
1263+ error_img.set_tooltip_text (_("This Virtual Private Network could not be connected to."));
1264+
1265+ spinner = new Gtk.Spinner();
1266+ spinner.visible = false;
1267+ spinner.no_show_all = !spinner.visible;
1268+
1269+ remove_button = new Gtk.Button.from_icon_name ("user-trash-symbolic", Gtk.IconSize.MENU);
1270+ remove_button.get_style_context ().add_class ("flat");
1271+ remove_button.clicked.connect (() => {
1272+ connection.delete (null);
1273+ });
1274+
1275+ main_box.pack_start (radio_button, true, true);
1276+ main_box.pack_start (spinner, false, false);
1277+ main_box.pack_start (error_img, false, false);
1278+ main_box.pack_start (remove_button, false, false);
1279+
1280+ notify["state"].connect (update);
1281+ radio_button.notify["active"].connect (update);
1282+ this.add (main_box);
1283+ this.get_style_context ().add_class ("menuitem");
1284+
1285+ connection.changed.connect (update);
1286+ update ();
1287+ }
1288+
1289+ /**
1290+ * Only used for an item which is not displayed: hacky way to have no radio button selected.
1291+ **/
1292+ public VPNMenuItem.blank () {
1293+ radio_button = new Gtk.RadioButton(null);
1294+ }
1295+
1296+ unowned SList get_group () {
1297+ return radio_button.get_group();
1298+ }
1299+
1300+ public void set_active (bool active) {
1301+ radio_button.set_active (active);
1302+ }
1303+
1304+ private void update () {
1305+ radio_button.label = connection.get_id ();
1306+
1307+ switch (state) {
1308+ case State.FAILED_VPN:
1309+ show_item(error_img);
1310+ break;
1311+ case State.CONNECTING_VPN:
1312+ show_item(spinner);
1313+ break;
1314+ default:
1315+ hide_icons ();
1316+ break;
1317+ }
1318+ }
1319+
1320+ public void hide_icons (bool show_remove_button = true) {
1321+#if PLUG_NETWORK
1322+ hide_item (error_img);
1323+ hide_item (spinner);
1324+
1325+ if (!show_remove_button) {
1326+ hide_item (remove_button);
1327+ }
1328+#endif
1329+ }
1330+
1331+ void show_item(Gtk.Widget w) {
1332+ w.visible = true;
1333+ w.no_show_all = !w.visible;
1334+ }
1335+
1336+ void hide_item(Gtk.Widget w) {
1337+ w.visible = false;
1338+ w.no_show_all = !w.visible;
1339+ w.hide();
1340+ }
1341+}
1342\ No newline at end of file
1343
1344=== modified file 'src/common/Widgets/WifiMenuItem.vala'
1345--- src/common/Widgets/WifiMenuItem.vala 2015-08-07 12:58:10 +0000
1346+++ src/common/Widgets/WifiMenuItem.vala 2016-07-26 21:06:49 +0000
1347@@ -24,7 +24,7 @@
1348 }
1349 }
1350
1351- public Network.State state { get; set; default=Network.State.DISCONNECTED; }
1352+ public Network.State state { get; set; default = Network.State.DISCONNECTED; }
1353
1354 public uint8 strength {
1355 get {
1356@@ -95,6 +95,8 @@
1357 radio_button.notify["active"].connect (update);
1358 this.add (main_box);
1359 this.get_style_context ().add_class ("menuitem");
1360+
1361+ update ();
1362 }
1363
1364 /**
1365@@ -168,7 +170,7 @@
1366 show_icons = false;
1367 hide_item (error_img);
1368 hide_item (lock_img);
1369- hide_item (img_strength);
1370+ hide_item (img_strength);
1371 #endif
1372 }
1373
1374@@ -208,7 +210,5 @@
1375
1376 return _ap.length() > 0;
1377 }
1378-
1379-
1380 }
1381

Subscribers

People subscribed via source and target branches

to all changes: