1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
from BitTorrent.platform import bttime
class StatusLight(object):
initial_state = 'stopped'
states = {
# state : (stock icon name, tool tip),
'stopped' : ('bt-status-stopped',
_("Paused")),
'empty' : ('bt-status-stopped',
_("No torrents")),
'starting' : ('bt-status-starting',
_("Starting download")),
'pre-natted': ('bt-status-pre-natted',
_("Starting download")),
'running' : ('bt-status-running',
_("Running normally")),
'natted' : ('bt-status-natted',
_("Downloads may be slow:\nProbably firewalled/NATted")),
'broken' : ('bt-status-broken',
_("Check network connection")),
}
messages = {
# message : default new state,
'stop' : 'stopped' ,
'empty' : 'empty' ,
'start' : 'starting' ,
'seen_peers' : 'pre-natted',
'seen_remote_peers' : 'running' ,
'broken' : 'broken' ,
}
transitions = {
# state : { message : custom new state, },
'pre-natted' : { 'start' : 'pre-natted',
'seen_peers' : 'pre-natted',},
'running' : { 'start' : 'running' ,
'seen_peers' : 'running' ,},
'natted' : { 'start' : 'natted' ,
'seen_peers' : 'natted' ,},
'broken' : { 'start' : 'broken' ,},
#TODO: add broken transitions
}
time_to_nat = 60 * 5 # 5 minutes
def __init__(self):
self.mystate = self.initial_state
self.start_time = None
def send_message(self, message):
if message not in self.messages.keys():
#print 'bad message', message
return
new_state = self.messages[message]
if self.transitions.has_key(self.mystate):
if self.transitions[self.mystate].has_key(message):
new_state = self.transitions[self.mystate][message]
# special pre-natted timeout logic
if new_state == 'pre-natted':
if (self.mystate == 'pre-natted' and
bttime() - self.start_time > self.time_to_nat):
# go to natted state after a while
new_state = 'natted'
elif self.mystate != 'pre-natted':
# start pre-natted timer
self.start_time = bttime()
if new_state != self.mystate:
#print 'changing state from', self.mystate, 'to', new_state
self.mystate = new_state
self.change_state()
def change_state(self):
pass
import gtk
class GtkStatusLight(gtk.EventBox, StatusLight):
def __init__(self, main):
gtk.EventBox.__init__(self)
StatusLight.__init__(self)
self.main = main
self.image = None
self.images = {}
for k,(s,t) in self.states.items():
i = gtk.Image()
i.set_from_stock(s, gtk.ICON_SIZE_LARGE_TOOLBAR)
i.show()
self.images[k] = i
self.set_size_request(24,24)
self.main.tooltips.set_tip(self, 'tooltip')
self.send_message('stop')
def change_state(self):
state = self.mystate
assert self.states.has_key(state)
if self.image is not None:
self.remove(self.image)
self.image = self.images[state]
self.add(self.image)
stock, tooltip = self.states[state]
self.main.tooltips.set_tip(self, tooltip)
|