~ubuntu-branches/ubuntu/maverick/awn-extras-applets/maverick

« back to all changes in this revision

Viewing changes to applets/maintained/bandwidth-monitor/interfaces_dialog.py

  • Committer: Bazaar Package Importer
  • Author(s): Julien Lavergne
  • Date: 2010-08-29 14:29:52 UTC
  • mto: This revision was merged to the branch mainline in revision 21.
  • Revision ID: james.westby@ubuntu.com-20100829142952-rhvuetyms9bv5uu7
Tags: upstream-0.4.0+bzr1372
ImportĀ upstreamĀ versionĀ 0.4.0+bzr1372

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!/usr/bin/python
 
2
# -*- coding: utf-8 -*-
 
3
'''
 
4
bandwidth-monitor - Network bandwidth monitor.
 
5
Copyright (c) 2006-2010 Kyle L. Huff (awn-bwm@curetheitch.com)
 
6
url: <http://www.curetheitch.com/projects/awn-bwm/>
 
7
Email: awn-bwm@curetheitch.com
 
8
 
 
9
    This program is free software: you can redistribute it and/or modify
 
10
    it under the terms of the GNU General Public License as published by
 
11
    the Free Software Foundation, either version 3 of the License, or
 
12
    (at your option) any later version.
 
13
 
 
14
    This program is distributed in the hope that it will be useful,
 
15
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
16
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 
17
    GNU General Public License for more details.
 
18
 
 
19
    You should have received a copy of the GNU General Public License
 
20
    along with this program. If not, see <http://www.gnu.org/licenses/gpl.txt>.
 
21
'''
 
22
 
 
23
import os
 
24
 
 
25
import gtk
 
26
from gtk import gdk
 
27
 
 
28
import awn
 
29
from awn import Dialog, cairo_rounded_rect, ROUND_ALL, OverlayText
 
30
from awn.extras import _
 
31
 
 
32
import cairo
 
33
import dbus
 
34
awn.check_dependencies(globals(), "gtop")
 
35
 
 
36
ICON_DIR = os.path.join(os.path.dirname(__file__), 'images')
 
37
 
 
38
 
 
39
class NetworkManager:
 
40
 
 
41
    def __init__(self):
 
42
        self.bus = dbus.SystemBus()
 
43
        self.nm_path = 'org.freedesktop.NetworkManager'
 
44
        self.nm_object = self.bus.get_object(self.nm_path, '/org/freedesktop/NetworkManager')
 
45
 
 
46
    def get_device_by_name(self, dev_name):
 
47
        try:
 
48
            for dev_opath in self.nm_object.GetDevices(dbus_interface=self.nm_path):
 
49
                device = self.bus.get_object(self.nm_path, dev_opath)
 
50
                if self.get_device_name(device) == dev_name:
 
51
                    return device
 
52
            return None
 
53
        except dbus.exceptions.DBusException:
 
54
            return None
 
55
 
 
56
    def get_devices(self):
 
57
        devices = []
 
58
        for dev_opath in self.nm_object.GetDevices(dbus_interface=self.nm_path):
 
59
            device = self.bus.get_object(self.nm_path, dev_opath)
 
60
            devices.append(device)
 
61
        return devices
 
62
 
 
63
    def get_device_name(self, device):
 
64
        return device.Get(self.nm_path + '.Device', 'Interface',
 
65
            dbus_interface='org.freedesktop.DBus.Properties').decode() if device else None
 
66
 
 
67
    def get_device_type(self, device):
 
68
        return device.Get(self.nm_path + '.Device', 'DeviceType',
 
69
            dbus_interface='org.freedesktop.DBus.Properties') if device else None
 
70
 
 
71
    def get_device_status(self, device):
 
72
        return device.Get(self.nm_path + '.Device', 'State',
 
73
            dbus_interface='org.freedesktop.DBus.Properties') if device else None
 
74
 
 
75
    def get_current_ssid(self, device):
 
76
        ap_path = device.Get(self.nm_path + '.Device.Wireless', 'ActiveAccessPoint', dbus_interface='org.freedesktop.DBus.Properties')
 
77
        ap = self.bus.get_object(self.nm_path, ap_path)
 
78
        ssid_byteArray = ap.Get(self.nm_path + '.AccessPoint', 'Ssid', dbus_interface='org.freedesktop.DBus.Properties')
 
79
        if ssid_byteArray:
 
80
            ssid = ''.join(chr(b) for b in ssid_byteArray)
 
81
        else:
 
82
            ssid = None
 
83
        return ssid
 
84
 
 
85
    def get_bluetooth_endpoint_name(self, device):
 
86
        return device.Get(self.nm_path + '.Device.Bluetooth', 'Name',
 
87
            dbus_interface='org.freedesktop.DBus.Properties').decode() if device else None
 
88
 
 
89
 
 
90
class InterfaceGraph(gtk.DrawingArea):
 
91
 
 
92
    def __init__(self, parent, iface, width, height, show_text=False):
 
93
        gtk.DrawingArea.__init__(self)
 
94
        self.__parent = parent
 
95
        self.interface = iface
 
96
        self.width = width
 
97
        self.height = height
 
98
        self.translated_x = 0
 
99
        self.translated_y = 0
 
100
        self.show_text = show_text
 
101
        self.connect('expose_event', self.expose)
 
102
        self.button_click_time = 0
 
103
        self.highlight = False
 
104
        self.set_events(gtk.gdk.BUTTON_PRESS_MASK |
 
105
                        gtk.gdk.BUTTON_RELEASE_MASK |
 
106
                        gtk.gdk.ENTER_NOTIFY_MASK |
 
107
                        gtk.gdk.LEAVE_NOTIFY_MASK)
 
108
        try:
 
109
            self.network_manager = NetworkManager()
 
110
        except Exception, e:
 
111
            self.network_manager = None
 
112
 
 
113
    def expose(self, widget, event):
 
114
        if not self.show_text and \
 
115
            self.__parent.interface_dialog.current_dialog == 'graph':
 
116
            widget.window.hide()
 
117
        self.set_size_request(int(self.width), int(self.height))
 
118
        context = widget.window.cairo_create()
 
119
        context.set_operator(cairo.OPERATOR_CLEAR)
 
120
        context.paint()
 
121
        context.set_operator(cairo.OPERATOR_OVER)
 
122
        self.draw_graph()
 
123
        return False
 
124
 
 
125
    def refresh(self, event=None):
 
126
        if not self.show_text and \
 
127
            self.__parent.interface_dialog.current_dialog == 'graph':
 
128
            return True
 
129
        self.draw_graph()
 
130
 
 
131
    def get_cairo_color(self, color):
 
132
        return color / 65535.0
 
133
 
 
134
    def draw_graph(self):
 
135
        if not self.window:
 
136
            return True
 
137
        self.set_size_request(int(self.width), int(self.height))
 
138
        context = self.window.cairo_create()
 
139
        context.translate(self.translated_x, self.translated_y)
 
140
        context.set_operator(cairo.OPERATOR_CLEAR)
 
141
        context.paint()
 
142
        context.set_operator(cairo.OPERATOR_OVER)
 
143
        iface = self.interface
 
144
        context.set_source_rgba(0, 0, 0, 0.85)
 
145
        if self.show_text:
 
146
            context.rectangle(0, 0, self.width, self.height + 20)
 
147
            context.fill()
 
148
        else:
 
149
            cairo_rounded_rect(context, -1, -1, self.width + 2, self.height + 2, 4, ROUND_ALL)
 
150
            context.fill()
 
151
        if self.show_text and not self.interface == self.__parent.iface:
 
152
            self.interface = self.__parent.iface
 
153
        if self.interface in self.__parent.netstats.ifaces:
 
154
            if self.show_text:
 
155
                line_width = 3
 
156
                icon_size = 0
 
157
                pixbuf = None
 
158
                self.interface = self.__parent.iface
 
159
                ''' if wireless, draw it '''
 
160
                if iface in self.__parent.netstats.ifaces:
 
161
                    if 'signal' in self.__parent.netstats.ifaces[iface]:
 
162
                        signal = abs(int(self.__parent.netstats.ifaces[iface]['signal']['strength'])) * 80 / 100
 
163
                        quality = int(self.__parent.netstats.ifaces[iface]['signal']['quality'])
 
164
                        noise = int(self.__parent.netstats.ifaces[iface]['signal']['noise'])
 
165
                        icon_size = 24
 
166
                        if quality == 0 or noise == -256:
 
167
                            icon_name = 'wireless-disconnected.png'
 
168
                        elif signal <= 40:
 
169
                            icon_name = 'wireless-full.png'
 
170
                        elif signal <= 60:
 
171
                            icon_name = 'wireless-high.png'
 
172
                        elif signal <= 90:
 
173
                            icon_name = 'wireless-medium.png'
 
174
                        else:
 
175
                            icon_name = 'wireless-low.png'
 
176
                        pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, icon_name), icon_size, icon_size)
 
177
                        signal = self.__parent.netstats.ifaces[iface]['signal']
 
178
                        ssid = None
 
179
                        self.__parent.draw_wireless(context, self.width, self.height, self.interface)
 
180
                        if self.network_manager:
 
181
                            nm_device = self.network_manager.get_device_by_name(iface)
 
182
                            nm_device_status = self.network_manager.get_device_status(nm_device)
 
183
                            if nm_device_status in [7, 8]:
 
184
                                ssid = self.network_manager.get_current_ssid(nm_device)
 
185
                                context.set_source_rgba(1, 1, 1)
 
186
                                context.set_font_size(18)
 
187
                                context.set_line_width(3)
 
188
                                context.move_to(6, 45)
 
189
                                context.set_source_rgba(0, 0, 0)
 
190
                                context.text_path('SSID: %s' % ssid)
 
191
                                context.stroke()
 
192
                                context.set_source_rgba(1, 1, 1)
 
193
                                context.move_to(6, 45)
 
194
                                context.show_text('SSID: %s' % ssid)
 
195
                                context.fill()
 
196
                    if not 'signal' in self.__parent.netstats.ifaces[iface] and \
 
197
                        not self.__parent.netstats.ifaces[iface]['status'] == 'V' and \
 
198
                        not gtop.NETLOAD_IF_FLAGS_LOOPBACK & self.__parent.netstats.ifaces[iface]['status']:
 
199
                        icon_size = 24
 
200
                        icon_name = 'ethernet.png'
 
201
                        try:
 
202
                            if os.access('/sys/class/net/%s/device/device/address' % iface, os.R_OK):
 
203
                                hw_addr = open('/sys/class/net/%s/device/address' % iface, 'r').read().strip()
 
204
                                ''' most likely a bluetooth connection, check with NM '''
 
205
                                if self.network_manager:
 
206
                                    nm_device = self.network_manager.get_device_by_name(hw_addr)
 
207
                                    nm_device_type = self.network_manager.get_device_type(nm_device)
 
208
                                    if nm_device_type == 5:
 
209
                                        ''' bluetooth '''
 
210
                                        icon_name = 'bluetooth.png'
 
211
                                        bt_endpoint = self.network_manager.get_bluetooth_endpoint_name(nm_device)
 
212
                                        context.set_source_rgba(1, 1, 1)
 
213
                                        context.set_font_size(18)
 
214
                                        context.set_line_width(3)
 
215
                                        context.move_to(6, 45)
 
216
                                        context.set_source_rgba(0, 0, 0)
 
217
                                        context.text_path(bt_endpoint)
 
218
                                        context.stroke()
 
219
                                        context.set_source_rgba(1, 1, 1)
 
220
                                        context.move_to(6, 45)
 
221
                                        context.show_text(bt_endpoint)
 
222
                                        context.fill()
 
223
                        except:
 
224
                            pass
 
225
                        pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, icon_name), icon_size, icon_size)
 
226
                    if not self.__parent.netstats.ifaces[iface]['status'] == 'V' and \
 
227
                        gtop.NETLOAD_IF_FLAGS_LOOPBACK & self.__parent.netstats.ifaces[iface]['status']:
 
228
                        icon_size = 24
 
229
                        pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'loopback.png'), icon_size, icon_size)
 
230
                    if iface == 'Multi Interface':
 
231
                        icon_size = 24
 
232
                        pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'multi.png'), icon_size, icon_size + 5)
 
233
                    if iface == 'Sum Interface':
 
234
                        icon_size = 24
 
235
                        pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'sum.png'), icon_size, icon_size)
 
236
                    if 'tun' in iface or 'tap' in iface:
 
237
                        icon_size = 24
 
238
                        pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'tun-tap.png'), icon_size, icon_size)
 
239
                    if pixbuf:
 
240
                        context.set_source_pixbuf(pixbuf, 4, 0)
 
241
                        context.paint()
 
242
                context.set_source_rgba(0.0, 1.0, 0.0, 1.0)
 
243
                context.set_line_width(0.2)
 
244
                ''' draw horizontal lines on the meter '''
 
245
                i = 50
 
246
                while i < self.height + 50:
 
247
                    context.move_to(0, i)
 
248
                    context.line_to(self.width, i)
 
249
                    i += 20
 
250
                context.stroke()
 
251
                context.set_source_rgba(1, 1, 1)
 
252
                context.select_font_face('Helvetica',
 
253
                        cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
 
254
                context.set_font_size(24.0)
 
255
                context.set_line_width(3)
 
256
                context.move_to(8 + icon_size, 20)
 
257
                context.set_source_rgba(0, 0, 0)
 
258
                context.text_path(self.__parent.iface)
 
259
                context.stroke()
 
260
                context.set_source_rgba(1, 1, 1)
 
261
                context.move_to(8 + icon_size, 20)
 
262
                context.show_text(self.__parent.iface)
 
263
                context.set_font_size(14.0)
 
264
                tx_label = 'TX: %s' % self.__parent.readable_speed_ps(
 
265
                    self.__parent.netstats.ifaces[self.interface]['tx_bytes'],
 
266
                        self.__parent.unit)
 
267
                rx_label = 'RX: %s' % self.__parent.readable_speed_ps(
 
268
                    self.__parent.netstats.ifaces[self.interface]['rx_bytes'],
 
269
                        self.__parent.unit)
 
270
                context.move_to(self.width - 100, 15)
 
271
                context.set_source_rgba(0, 0, 0)
 
272
                context.text_path(tx_label)
 
273
                context.stroke()
 
274
                context.move_to(self.width - 100, 15)
 
275
                context.set_source_rgba(1, 1, 1)
 
276
                context.show_text(tx_label)
 
277
                context.fill()
 
278
                context.move_to(self.width - 100, 30)
 
279
                context.set_source_rgba(0, 0, 0)
 
280
                context.text_path(rx_label)
 
281
                context.stroke()
 
282
                context.move_to(self.width - 100, 30)
 
283
                context.set_source_rgba(1, 1, 1)
 
284
                context.show_text(rx_label)
 
285
                context.fill()
 
286
            else:
 
287
                line_width = 2
 
288
                context.set_line_width(line_width)
 
289
                x, y = 0, 0
 
290
                h = self.height
 
291
                cairo_rounded_rect(context, 1, 1, self.width - 2, self.height - 2, 4, ROUND_ALL)
 
292
                pat = cairo.LinearGradient(0, self.height / 2 + 15, 0, 0)
 
293
                if self.__parent.netstats.ifaces[iface]['status'] == 'V' or \
 
294
                    gtop.NETLOAD_IF_FLAGS_RUNNING & \
 
295
                    self.__parent.netstats.ifaces[iface]['status']:
 
296
                    c1, c2, c3 = 0, 0, 0
 
297
                    c4, c5, c6 = 0, 1, 0
 
298
                else:
 
299
                    c1, c2, c3 = 0, 0, 0
 
300
                    c4, c5, c6 = 1, 0, 0
 
301
 
 
302
                pat.add_color_stop_rgba(0.1, c1, c2, c3, 0.85)
 
303
                pat.add_color_stop_rgba(1.0, c4, c5, c6, 0.85)
 
304
                count = 1
 
305
 
 
306
                context.set_source(pat)
 
307
                context.fill()
 
308
 
 
309
                pixbuf = None
 
310
                icon_size = 24 if self.highlight else 16
 
311
                if 'Multi' in iface:
 
312
                    icon_size = 28 if self.highlight else 20
 
313
                    pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'multi.png'), icon_size, icon_size)
 
314
                if 'Sum' in iface:
 
315
                    pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'sum.png'), icon_size, icon_size)
 
316
                if not self.__parent.netstats.ifaces[iface]['status'] == 'V' and \
 
317
                        gtop.NETLOAD_IF_FLAGS_LOOPBACK & self.__parent.netstats.ifaces[iface]['status']:
 
318
                    pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'loopback.png'), icon_size, icon_size)
 
319
                if 'signal' in self.__parent.netstats.ifaces[iface]:
 
320
                    signal = abs(int(self.__parent.netstats.ifaces[iface]['signal']['strength'])) * 80 / 100
 
321
                    quality = int(self.__parent.netstats.ifaces[iface]['signal']['quality'])
 
322
                    noise = int(self.__parent.netstats.ifaces[iface]['signal']['noise'])
 
323
                    if quality == 0 or noise == -256:
 
324
                        icon_name = 'wireless-disconnected.png'
 
325
                    elif signal <= 40:
 
326
                        icon_name = 'wireless-full.png'
 
327
                    elif signal <= 60:
 
328
                        icon_name = 'wireless-high.png'
 
329
                    elif signal <= 90:
 
330
                        icon_name = 'wireless-medium.png'
 
331
                    else:
 
332
                        icon_name = 'wireless-low.png'
 
333
                    pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, icon_name), icon_size, icon_size)
 
334
                if not 'signal' in self.__parent.netstats.ifaces[iface] and \
 
335
                    not self.__parent.netstats.ifaces[iface]['status'] == 'V' and \
 
336
                    not gtop.NETLOAD_IF_FLAGS_LOOPBACK & self.__parent.netstats.ifaces[iface]['status']:
 
337
                    pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'ethernet.png'), icon_size, icon_size)
 
338
                    if self.network_manager:
 
339
                        try:
 
340
                            if os.access('/sys/class/net/%s/device/device/address' % iface, os.R_OK):
 
341
                                hw_addr = open('/sys/class/net/%s/device/address' % iface, 'r').read().strip()
 
342
                                ''' most likely a bluetooth connection, check with NM '''
 
343
                                nm_device = self.network_manager.get_device_by_name(hw_addr)
 
344
                                nm_device_type = self.network_manager.get_device_type(nm_device)
 
345
                                if nm_device_type == 5:
 
346
                                    ''' bluetooth '''
 
347
                                    icon_size = 32 if self.highlight else 20
 
348
                                    pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'bluetooth.png'), icon_size, icon_size)
 
349
                        except:
 
350
                            pass
 
351
                if 'tun' in iface or 'tap' in iface:
 
352
                    pixbuf = gtk.gdk.pixbuf_new_from_file_at_size(os.path.join(ICON_DIR, 'tun-tap.png'), icon_size, icon_size)
 
353
                if pixbuf:
 
354
                    context.set_source_pixbuf(pixbuf, self.width - pixbuf.get_width() - 4, 4)
 
355
                    context.paint()
 
356
                context.select_font_face('Helvetica',
 
357
                        cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
 
358
                if not self.highlight:
 
359
                    context.set_font_size(12.0)
 
360
                    text_xpos = 0
 
361
                else:
 
362
                    context.set_font_size(14.0)
 
363
                    text_xpos = -4
 
364
                context.set_source_rgba(1, 1, 1)
 
365
 
 
366
                iface_name = self.interface.split(' ')[0]
 
367
                text_xpos = self.width / 3 - 20
 
368
                context.move_to(text_xpos, self.height - self.height / 2)
 
369
                context.show_text(iface_name)
 
370
                context.fill()
 
371
 
 
372
                def click_event(widget, event):
 
373
                    if abs(event.time - self.button_click_time) > 500:
 
374
                        self.button_click_time = event.time
 
375
                        self.__parent.change_iface(widget, self.interface)
 
376
                        self.__parent.interface_dialog.buttonArea.change_dialog(widget, event, 'graph')
 
377
                self.connect('button_release_event', click_event)
 
378
            context.set_font_size(12.0)
 
379
            multi = True if self.interface == 'Multi Interface' else False
 
380
            if multi:
 
381
                tmp_history = [1]
 
382
                for iface in self.__parent.netstats.ifaces:
 
383
                    if self.__parent.netstats.ifaces[iface]['multi_include']:
 
384
                        tmp_history.extend(
 
385
                            self.__parent.netstats.ifaces[iface]['rx_history'])
 
386
                        tmp_history.extend(
 
387
                            self.__parent.netstats.ifaces[iface]['tx_history'])
 
388
                tmp_history.sort()
 
389
                max_val = tmp_history[-1]
 
390
                ratio = max_val / 28 if max_val > self.__parent.ratio else 1
 
391
                for iface in self.__parent.netstats.ifaces:
 
392
                    if self.__parent.netstats.ifaces[iface]['multi_include']:
 
393
                        self.__parent.draw_meter(context, self.width, self.height, iface, multi=multi, line_width=line_width, ratio=ratio, border=True)
 
394
            else:
 
395
                self.__parent.draw_meter(context, self.width, self.height, self.interface, multi=multi, line_width=line_width, ratio=1, border=True)
 
396
            if not self.show_text:
 
397
                if self.highlight:
 
398
                    context.set_source_rgba(1, 1, 1, 1)
 
399
                    context.set_line_width(3)
 
400
                    cairo_rounded_rect(context, 1, 1, self.width - 2, self.height - 2, 6, ROUND_ALL)
 
401
                    context.stroke()
 
402
                else:
 
403
                    context.set_source_rgba(1, 1, 1, 1)
 
404
                    cairo_rounded_rect(context, 0, 0, self.width, self.height, 4, ROUND_ALL)
 
405
                    context.stroke()
 
406
        else:
 
407
            context.set_source_rgba(1, 1, 1)
 
408
            context.select_font_face('Helvetica',
 
409
                    cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD)
 
410
            context.set_font_size(18.0)
 
411
            device_error = _('No Device')
 
412
            device_error_message = _('Please select a valid device')
 
413
            context.move_to(self.width / 3.0, self.height / 2 - 7)
 
414
            context.show_text(device_error)
 
415
            context.move_to(self.width / 3.0, self.height / 2 + 10)
 
416
            context.show_text(device_error_message)
 
417
            context.fill()
 
418
        return True
 
419
 
 
420
 
 
421
class InterfaceDeatil:
 
422
 
 
423
    def __init__(self, parent):
 
424
        self.parent = parent
 
425
        self.applet = parent.applet
 
426
 
 
427
        self.interfaceDialog = None
 
428
        self.interfaceArea = None
 
429
        self.interfaceListArea = None
 
430
        self.interfaceOptionsArea = None
 
431
        self.buttonArea = None
 
432
        self.current_dialog = 'graph'
 
433
 
 
434
    def setup_interface_dialogs(self):
 
435
        if self.interfaceDialog is not None:
 
436
            del self.interfaceDialog
 
437
            self.applet.dialog.unregister('main')
 
438
        if self.interfaceArea is not None:
 
439
            del self.interfaceArea
 
440
        if self.interfaceListArea is not None:
 
441
            del self.interfaceListArea
 
442
        if self.buttonArea is not None:
 
443
            del self.buttonArea
 
444
        if self.interfaceOptionsArea:
 
445
            del self.interfaceOptionsArea
 
446
 
 
447
        self.interfaceDialog = self.InterfaceDialogWrapper(self.applet)
 
448
        self.applet.dialog.register('main', self.interfaceDialog)
 
449
 
 
450
        def leave_notify(widget, event, self):
 
451
            #return True
 
452
            if not hasattr(self.interfaceOptionsArea, 'graph_selection') or \
 
453
                not self.interfaceOptionsArea.graph_selection.get_property('popup-shown'):
 
454
                self.parent.interface_dialog.buttonArea.change_dialog(widget, event, 'graph')
 
455
        self.interfaceDialog.foe_id = self.interfaceDialog.connect('focus-out-event', leave_notify, self)
 
456
        self.interfaceArea = InterfaceGraph(self.parent, self.parent.iface, 450, 170, True)
 
457
 
 
458
        self.buttonArea = InterfaceControls(self.parent)
 
459
        self.interfaceListArea = InterfaceSelectionList(self.parent)
 
460
        self.interfaceListArea.draw_interface_list()
 
461
 
 
462
        self.interfaceOptionsArea = InterfaceOptionsDialog(self.parent)
 
463
 
 
464
        self.interfaceArea.set_size_request(450, 170)
 
465
        self.interfaceListArea.set_size_request(450, 190)
 
466
        self.buttonArea.set_size_request(450, 210)
 
467
 
 
468
        box = gtk.Fixed()
 
469
        box.put(self.buttonArea, 0, 0)
 
470
        box.put(self.interfaceListArea, 10, 15)
 
471
        box.put(self.interfaceArea, 10, 0)
 
472
        box.put(self.interfaceOptionsArea, 10, 0)
 
473
 
 
474
        box.show_all()
 
475
        self.interfaceDialog.add(box)
 
476
 
 
477
    def do_current(self):
 
478
        self.interfaceListArea.hide()
 
479
        self.interfaceArea.hide()
 
480
        self.interfaceOptionsArea.hide()
 
481
        if self.current_dialog == 'graph':
 
482
            self.interfaceArea.refresh()
 
483
            self.interfaceArea.show()
 
484
        if self.current_dialog == 'list':
 
485
            self.interfaceListArea.refresh()
 
486
            self.interfaceListArea.show_all()
 
487
        if self.current_dialog == 'options':
 
488
            self.interfaceOptionsArea.show_all()
 
489
 
 
490
    class InterfaceDialogWrapper(Dialog):
 
491
 
 
492
        def __init__(self, applet):
 
493
            Dialog.__init__(self, applet)
 
494
            self.__parent = self
 
495
            self.applet = applet
 
496
            self.connect('expose-event', self.expose_event_cb)
 
497
 
 
498
        def expose_event_cb(self, widget, event=None):
 
499
            context = widget.window.cairo_create()
 
500
 
 
501
            context.set_operator(cairo.OPERATOR_CLEAR)
 
502
            context.paint()
 
503
            context.set_operator(cairo.OPERATOR_OVER)
 
504
 
 
505
            for child in self.get_children():
 
506
                self.propagate_expose(child, event)
 
507
 
 
508
            return True
 
509
 
 
510
 
 
511
class InterfaceControls(gtk.Fixed):
 
512
 
 
513
    def __init__(self, parent_applet):
 
514
        gtk.Fixed.__init__(self)
 
515
        self.__parent = parent_applet
 
516
        self.width, self.height = 450, 200
 
517
        self.connect('expose_event', self.expose_event_cb)
 
518
 
 
519
    def change_dialog(self, widget, event, force=None):
 
520
        self.__parent.interface_dialog.interfaceArea.hide()
 
521
        self.__parent.interface_dialog.interfaceListArea.hide()
 
522
        self.__parent.interface_dialog.interfaceOptionsArea.hide()
 
523
        if self.__parent.interface_dialog.current_dialog == force:
 
524
            self.__parent.interface_dialog.current_dialog = 'graph'
 
525
        else:
 
526
            self.__parent.interface_dialog.current_dialog = force if \
 
527
                force else self.__parent.interface_dialog.current_dialog
 
528
        if self.__parent.interface_dialog.current_dialog == 'list':
 
529
            self.__parent.interface_dialog.current_dialog = 'list'
 
530
            self.__parent.interface_dialog.interfaceListArea.rebuild()
 
531
            self.__parent.interface_dialog.interfaceListArea.refresh()
 
532
            self.__parent.interface_dialog.interfaceListArea.show_all()
 
533
            self.iface_options_btn.set_label(_('Options/Info'))
 
534
            self.iface_options_btn.hide()
 
535
            self.iface_list_btn.set_label(_('Back to Graph'))
 
536
        elif self.__parent.interface_dialog.current_dialog == 'options':
 
537
            self.iface_options_btn.parent.move(self.iface_options_btn, self.width - 110, self.height - 25)
 
538
            self.iface_options_btn.set_label(_('Back to Graph'))
 
539
            self.iface_list_btn.set_label(_('Interfaces'))
 
540
            self.__parent.interface_dialog.interfaceOptionsArea.show_all()
 
541
        else:
 
542
            self.iface_list_btn.set_label(_('Interfaces'))
 
543
            self.iface_options_btn.set_label(_('Options/Info'))
 
544
            self.iface_options_btn.show()
 
545
            self.__parent.interface_dialog.interfaceArea.refresh()
 
546
            self.__parent.interface_dialog.interfaceArea.show_all()
 
547
 
 
548
    def expose_event_cb(self, widget, event=None):
 
549
        context = widget.window.cairo_create()
 
550
        context.translate(25, 10)
 
551
        context.set_operator(cairo.OPERATOR_CLEAR)
 
552
        context.paint()
 
553
        context.set_operator(cairo.OPERATOR_OVER)
 
554
        context.set_source_rgba(0, 0, 0, 0.85)
 
555
        cairo_rounded_rect(context, 0, 0, self.width, self.height + 12, 4, ROUND_ALL)
 
556
        context.fill()
 
557
        context.set_line_width(1)
 
558
        context.set_source_rgba(0, 0, 0, 0.55)
 
559
        cairo_rounded_rect(context, 0, 0, self.width, self.height + 12, 4, ROUND_ALL)
 
560
        context.stroke()
 
561
 
 
562
        if not hasattr(self, 'iface_list_btn'):
 
563
            self.iface_list_btn = gtk.Button(_('Interfaces'))
 
564
            self.iface_list_btn.connect('button_press_event', self.change_dialog, 'list')
 
565
            self.parent.put(self.iface_list_btn, 20, self.height - 25)
 
566
 
 
567
        if not hasattr(self, 'change_unit_btn'):
 
568
            self.change_unit_btn = gtk.Button(_('Change Unit'))
 
569
            self.change_unit_btn.connect('clicked', self.__parent.call_change_unit)
 
570
            self.parent.put(self.change_unit_btn, 180, self.height - 25)
 
571
 
 
572
        if not hasattr(self, 'iface_options_btn'):
 
573
            self.iface_options_btn = gtk.Button(_('Options/Info'))
 
574
            self.iface_options_btn.connect('button_press_event', self.change_dialog, 'options')
 
575
            self.parent.put(self.iface_options_btn, self.width - 98, self.height - 25)
 
576
 
 
577
        if not hasattr(self, 'initted'):
 
578
            self.iface_list_btn.show()
 
579
            self.change_unit_btn.show()
 
580
            self.iface_options_btn.show()
 
581
            self.initted = True
 
582
 
 
583
        return True
 
584
 
 
585
 
 
586
class InterfaceOptionsDialog(gtk.Fixed):
 
587
 
 
588
    def __init__(self, parent_applet):
 
589
        gtk.Fixed.__init__(self)
 
590
        self.__parent = parent_applet
 
591
        self.width, self.height = 450, 200
 
592
        self.connect('expose_event', self.expose_event_cb)
 
593
        self.iface = None
 
594
 
 
595
    def refresh(self):
 
596
        for child in self.get_children():
 
597
            self.remove(child)
 
598
            del child
 
599
        self.rebuild()
 
600
 
 
601
    def rebuild(self):
 
602
        self.iface = self.__parent.iface
 
603
        ifaces = self.__parent.netstats.ifaces
 
604
        iface = self.__parent.iface
 
605
 
 
606
        def keep_open(widget, event):
 
607
            if hasattr(self, 'graph_selection'):
 
608
                return True if self.graph_selection.get_property('popup-shown') else False
 
609
        self.__parent.interface_dialog.interfaceDialog.connect('focus_out_event', keep_open)
 
610
 
 
611
        if iface in ifaces:
 
612
            fields = [('status', _('Status')), ('address', _('IP Address')), ('subnet', _('Subnet Mask'))]
 
613
            y_pos = 10
 
614
            for field in fields:
 
615
                if field[0] == 'status':
 
616
                    lbl_text = '%s: ' % (field[1])
 
617
                    if ifaces[iface]['status'] == 'V' or \
 
618
                    gtop.NETLOAD_IF_FLAGS_UP & ifaces[iface]['status']:
 
619
                        lbl_text += 'UP'
 
620
                    if ifaces[iface]['status'] == 'V' or \
 
621
                    gtop.NETLOAD_IF_FLAGS_RUNNING & ifaces[iface]['status']:
 
622
                        lbl_text += ', RUNNING'
 
623
                else:
 
624
                    lbl_text = '%s: %s' % (field[1], ifaces[iface][field[0]])
 
625
                lbl = gtk.Label()
 
626
                lbl.set_markup("<span color='white'>%s</span>" % lbl_text)
 
627
                lbl.show()
 
628
                self.put(lbl, 12, y_pos)
 
629
                y_pos += 20
 
630
            if iface == 'Sum Interface':
 
631
                members = ''
 
632
                for interface in sorted(ifaces):
 
633
                    if ifaces[interface]['sum_include']:
 
634
                        if members == '':
 
635
                            members += ' %s' % (interface)
 
636
                        else:
 
637
                            members += ', %s' % (interface)
 
638
                if members == '':
 
639
                    members = ' None'
 
640
                members_lbl = gtk.Label()
 
641
                members_lbl.set_size_request(450, 50)
 
642
                members_lbl.set_line_wrap(True)
 
643
                members_lbl.set_markup("<span color='white'>Members:%s</span>" % members)
 
644
                self.put(members_lbl, 12, y_pos)
 
645
                members_lbl.show()
 
646
                y_pos += 20
 
647
            if iface == 'Multi Interface':
 
648
                members = ''
 
649
                for interface in sorted(ifaces):
 
650
                    if ifaces[interface]['multi_include']:
 
651
                        if members == '':
 
652
                            members += ' %s' % (interface)
 
653
                        else:
 
654
                            members += ', %s' % (interface)
 
655
                if members == '':
 
656
                    members = ' None'
 
657
                members_lbl = gtk.Label()
 
658
                members_lbl.set_size_request(450, 50)
 
659
                members_lbl.set_line_wrap(True)
 
660
                members_lbl.set_markup("<span color='white'>Members:%s</span>" % members)
 
661
                self.put(members_lbl, 12, y_pos)
 
662
                members_lbl.show()
 
663
                y_pos += 20
 
664
            if 'signal' in ifaces[iface]:
 
665
                self.graph_selection = gtk.combo_box_new_text()
 
666
                slist = ['Area', 'Area/Bar', 'Bar', 'Fan', 'Fan/Bar']
 
667
                for listitem in enumerate(slist):
 
668
                    self.graph_selection.append_text(listitem[1])
 
669
                    if listitem[1].lower().replace('/', '_') == \
 
670
                        ifaces[iface]['graph_type']:
 
671
                        selected_item = listitem[0]
 
672
                self.graph_selection.set_active(selected_item)
 
673
 
 
674
                def change_graph(widget):
 
675
                    model = widget.get_model()
 
676
                    index = widget.get_active()
 
677
                    graph_type = model[index][0].lower().replace('/', '_')
 
678
                    self.__parent.netstats.ifaces[iface]['graph_type'] = graph_type
 
679
                    prefs = self.__parent.applet.settings['wireless_signal_graph_type']
 
680
                    if not prefs:
 
681
                        prefs = ['%s|fan' % (iface)]
 
682
                    if not iface in prefs.__str__():
 
683
                        prefs.append('%s|fan' % (iface))
 
684
                    for i, device_pref in enumerate(prefs):
 
685
                        dpv = device_pref.split('|')
 
686
                        if dpv[0] == iface:
 
687
                            dpv[1] = graph_type
 
688
                            prefs[i] = '|'.join(dpv)
 
689
                    self.__parent.applet.settings['wireless_signal_graph_type'] = prefs
 
690
                self.graph_selection.connect('changed', change_graph)
 
691
                graph_lbl = gtk.Label()
 
692
                graph_lbl.set_markup("<span color='white'>%s</span>" % (_('Wireless graph type')))
 
693
                self.put(graph_lbl, 12, y_pos + 4)
 
694
                graph_lbl.show()
 
695
                self.put(self.graph_selection, 160, y_pos)
 
696
                self.graph_selection.show()
 
697
 
 
698
    def expose_event_cb(self, widget, event):
 
699
        if not len(self.get_children()) or not \
 
700
            self.iface == self.__parent.iface or \
 
701
            self.__parent.netstats.regenerate:
 
702
            for child in self.get_children():
 
703
                self.remove(child)
 
704
                del child
 
705
            self.rebuild()
 
706
 
 
707
 
 
708
class InterfaceSelectionList(gtk.Fixed):
 
709
 
 
710
    def __init__(self, parent_applet):
 
711
        gtk.Fixed.__init__(self)
 
712
        self.__parent = parent_applet
 
713
        self.width = 450
 
714
        self.height = 160
 
715
        self.setup_complete = False
 
716
 
 
717
    def refresh(self):
 
718
        for child in self.get_children():
 
719
            child.refresh()
 
720
 
 
721
    def rebuild(self):
 
722
        for child in self.get_children():
 
723
            self.remove(child)
 
724
            del child
 
725
        self.draw_interface_list()
 
726
        self.refresh()
 
727
 
 
728
    def draw_interface_list(self):
 
729
        if self.setup_complete and \
 
730
            not self.__parent.interface_dialog.current_dialog == 'list':
 
731
            return
 
732
        self.setup_complete = True
 
733
        ifaces = self.__parent.netstats.ifaces
 
734
        if len(self.__parent.netstats.ifaces) > 10:
 
735
            self.mct_height, mct_height = 24, 24
 
736
 
 
737
            n = int(len(ifaces) / 5.1)
 
738
            ypos_calculation = int(30 * n)
 
739
            ypos_spacing = int(30 / n) if n > 3 else 30
 
740
        else:
 
741
            self.mct_height, mct_height = 42, 42
 
742
            ypos_calculation = 58
 
743
            ypos_spacing = 10
 
744
        self.mct_width, mct_width = 72, 72
 
745
 
 
746
        spacing = (self.width - (48 * 2)) / (self.width / (48 * 2))
 
747
        xpos, ypos = 13, int(75 - ypos_calculation)
 
748
 
 
749
        if ypos < -60:
 
750
            ypos = -10
 
751
        elif ypos < 0:
 
752
            ypos = -5
 
753
        for iface in sorted(self.__parent.netstats.ifaces):
 
754
            self.__parent.netstats.ifaces[iface]['in_list'] = True
 
755
            graph = InterfaceGraph(self.__parent, iface, mct_width, mct_height)
 
756
 
 
757
            def hover_action(widget, event, xpos, ypos):
 
758
                widget.window.set_cursor(gtk.gdk.Cursor(gtk.gdk.HAND2))
 
759
                widget.highlight = True
 
760
                widget.height = 64
 
761
                widget.width = widget.height * 1.5
 
762
                widget.refresh()
 
763
                widget.window.raise_()
 
764
                self.move(widget, xpos - 12, ypos + 1 - widget.height / 3)
 
765
            graph.connect('enter_notify_event', hover_action, xpos, ypos)
 
766
 
 
767
            def leave_action(widget, event, xpos, ypos):
 
768
                widget.window.set_cursor(None)
 
769
                widget.highlight = False
 
770
                widget.height = self.mct_height
 
771
                widget.width = self.mct_width
 
772
                widget.refresh()
 
773
                self.move(widget, xpos, ypos)
 
774
            graph.connect('leave_notify_event', leave_action, xpos, ypos)
 
775
 
 
776
            self.put(graph, xpos, ypos)
 
777
            xpos += spacing
 
778
            if xpos > self.width:
 
779
                xpos = 13
 
780
                ypos += (mct_height * 2) - int(30 / ypos_spacing) * 4
 
781
 
 
782
    def expose_event_cb(self, widget, event=None):
 
783
        self.refresh()
 
784
        return True