fix bluescreen when pressing exit in alternative selection
[enigma2.git] / lib / python / Plugins / Extensions / ZappingAlternatives / plugin.py
1 from enigma import *
2 from Screens.Screen import Screen
3 from Screens.MessageBox import MessageBox
4 from Components.ActionMap import ActionMap
5 from Components.Label import Label
6 from Components.Input import Input
7 from Components.GUIComponent import *
8 from Components.Pixmap import Pixmap
9 from Components.MenuList import MenuList
10 from Components.FileList import FileEntryComponent, FileList
11 from Navigation import Navigation
12 import NavigationInstance
13 from Screens.ChannelSelection import SimpleChannelSelection
14 from ServiceReference import ServiceReference
15 from Plugins.Plugin import PluginDescriptor
16 from Tools.Directories import resolveFilename, SCOPE_CONFIG
17 import xml.dom.minidom
18 from Tools.XMLTools import elementsWithTag
19
20 import os
21
22 alternatives = {}
23
24 def addAlternative(service1, service2):
25         if not alternatives.has_key(service1):
26                 alternatives[service1] = []
27         alternatives[service1].append(service2)
28         if not alternatives.has_key(service2):
29                 alternatives[service2] = []
30         alternatives[service2].append(service1)
31
32 def removeAlternative(service1, service2):
33         alternatives[service1].remove(service2)
34         alternatives[service2].remove(service1)
35         if len(alternatives[service1]) == 0:
36                 del alternatives[service1]
37         if len(alternatives[service2]) == 0:
38                 del alternatives[service2]
39                 
40 def loadAlternatives():
41         doc = xml.dom.minidom.parse(resolveFilename(SCOPE_CONFIG, "alternatives.xml"))
42         
43         root = doc.childNodes[0]
44         for service in elementsWithTag(root.childNodes, 'service'):
45                 newService = str(service.getAttribute('ref'))
46                 for alternative in elementsWithTag(service.childNodes, 'alternative'):
47                         newAlternative = str(alternative.getAttribute('ref'))
48                         addAlternative(newService, newAlternative)
49
50 def sortKey(x):
51         return str.lower(ServiceReference(x).getServiceName().strip())
52                         
53 class AlternativeZapping(Screen):
54         skin = """
55                 <screen position="100,100" size="560,400" title="Services alternatives setup..." >
56                         <widget name="red" position="0,0" size="140,40" backgroundColor="red" halign="center" valign="center" font="Regular;21" />
57                         <widget name="green" position="140,0" size="140,40" backgroundColor="green" halign="center" valign="center" font="Regular;21" />
58                         <widget name="yellow" position="280,0" size="140,40" backgroundColor="yellow" halign="center" valign="center" font="Regular;21" />
59                         <widget name="blue" position="420,0" size="140,40" backgroundColor="blue" halign="center" valign="center" font="Regular;21" />
60                         <widget name="serviceslist" position="0,40" size="280,360" scrollbarMode="showOnDemand" />
61                         <widget name="alternativeslist" position="280,40" size="280,360" selectionDisabled="1" scrollbarMode="showOnDemand" />
62                 </screen>"""
63         def __init__(self, session):
64                 self.skin = AlternativeZapping.skin
65                 Screen.__init__(self, session)
66
67                 self.filename = resolveFilename(SCOPE_CONFIG, "alternatives.xml")
68                 
69                 self.red = Label("")
70                 self["red"] = self.red
71                 self.green = Label(_("Add service"))
72                 self["green"] = self.green
73                 self.yellow = Label("")
74                 self["yellow"] = self.yellow
75                 self.blue = Label("")
76                 self["blue"] = self.blue
77                 
78                 self.alternatives = {}
79                 
80                 self.serviceslist = []
81                 self.alternativeslist = []
82                 
83                 try:
84                         self.loadAlternatives()
85                 except:
86                         pass
87                 self["serviceslist"] = MenuList(self.serviceslist)
88                 self["alternativeslist"] = MenuList(self.alternativeslist)
89
90                 self.onShown.append(self.updateServices)
91                 self.onShown.append(self.updateAlternatives)
92
93                 self["actions"] = ActionMap(["DirectionActions", "OkCancelActions", "ColorActions"],
94                 {
95                         "ok": self.go,
96                         "cancel": self.go,
97                         "up": self.up,
98                         "down": self.down,
99                         "left": self.left,
100                         "right": self.right,
101                         "red": self.redKey,
102                         "green": self.greenKey,
103                         "yellow": self.yellowKey,
104                         "blue": self.blueKey,
105                 }, -1)
106                 
107         def saveAlternatives(self):
108                 doc = xml.dom.minidom.Document()
109                 root_element = doc.createElement('alternatives')
110                 doc.appendChild(root_element)
111                 root_element.appendChild(doc.createTextNode("\n"))
112                 
113                 for alternative in self.alternatives.keys():
114                         t = doc.createTextNode("\t")
115                         root_element.appendChild(t)
116                         t = doc.createElement('service')
117                         t.setAttribute("ref", alternative)
118                         root_element.appendChild(t)
119                         t.appendChild(doc.createTextNode("\n"))
120                         for x in self.alternatives[alternative]:
121                                 t.appendChild(doc.createTextNode("\t\t"))
122                                 l = doc.createElement('alternative')
123                                 l.setAttribute("ref", str(x))
124                                 t.appendChild(l)
125                                 t.appendChild(doc.createTextNode("\n"))
126                         t.appendChild(doc.createTextNode("\t"))
127                         root_element.appendChild(t)
128                         t = doc.createTextNode("\n")
129                         root_element.appendChild(t)
130                 file = open(self.filename, "w")
131                 doc.writexml(file)
132                 file.write("\n")
133                 file.close()
134         
135         def loadAlternatives(self):
136                 self.alternatives = {}
137                 alternatives = {}
138                 doc = xml.dom.minidom.parse(self.filename)
139                 
140                 root = doc.childNodes[0]
141                 for service in elementsWithTag(root.childNodes, 'service'):
142                         newService = str(service.getAttribute('ref'))
143                         if not self.alternatives.has_key(newService):
144                                 self.alternatives[newService] = []
145                         for alternative in elementsWithTag(service.childNodes, 'alternative'):
146                                 newAlternative = str(alternative.getAttribute('ref'))
147                                 self.alternatives[newService].append(newAlternative)
148                                 addAlternative(newService, newAlternative)
149                 
150         def go(self):
151                 self.saveAlternatives()
152                 self.close()
153         
154         def up(self):
155                 self["serviceslist"].instance.moveSelection(self["serviceslist"].instance.moveUp)
156                 self.updateAlternatives()
157                 
158         def down(self):
159                 self["serviceslist"].instance.moveSelection(self["serviceslist"].instance.moveDown)
160                 self.updateAlternatives()
161         
162         def left(self):
163                 pass
164         
165         def right(self):
166                 pass
167         
168         def redKey(self):
169                 for x in self.alternatives[self["serviceslist"].getCurrent()[1]]:
170                         removeAlternative(self["serviceslist"].getCurrent()[1], x)
171                 if len(self.serviceslist) > 0:
172                         del self.alternatives[self["serviceslist"].getCurrent()[1]]
173                 self.updateServices()
174                 self.updateAlternatives()
175         
176         def finishedAlternativeSelection(self, *args):
177                 if len(args):
178                         self.alternatives[self["serviceslist"].getCurrent()[1]].append(str(ServiceReference(args)))
179                         addAlternative(self["serviceslist"].getCurrent()[1], str(ServiceReference(args)))
180                         self.updateAlternatives()
181         
182         def updateServices(self):
183                 self.serviceslist = []
184                 keys = self.alternatives.keys()
185                 keys.sort(key = sortKey)
186                 for x in keys:
187                         self.serviceslist.append((ServiceReference(x).getServiceName(), x))
188                         
189                 self["serviceslist"].setList(self.serviceslist)
190                 if len(self.serviceslist) > 0:
191                         self.yellow.setText(_("Add alternative"))
192                         self.red.setText(_("Remove service"))
193                 else:
194                         self.yellow.setText("")
195                         self.red.setText("")
196         
197         def selectService(self, ref):
198                 count = 0
199                 for x in self["serviceslist"].list:
200                         if x[1] == ref:
201                                 self["serviceslist"].instance.moveSelectionTo(count)
202                                 return
203                         count += 1
204                         
205                         
206         def updateAlternatives(self):
207                 self.alternativeslist = []
208         
209                 if len(self.serviceslist) > 0:
210                         alternativelist = self.alternatives[self["serviceslist"].getCurrent()[1]]
211
212                         for x in alternativelist:
213                                 self.alternativeslist.append((ServiceReference(x).getServiceName(), x))
214                         
215                 self["alternativeslist"].setList(self.alternativeslist)
216                         
217         def greenKey(self):
218                 self.session.openWithCallback(self.finishedChannelSelection, SimpleChannelSelection, _("Select reference service"))
219
220         def finishedChannelSelection(self, *args):
221                 if len(args):
222                         serviceString = str(ServiceReference(args[0]))
223                         if not self.alternatives.has_key(serviceString):
224                                 self.alternatives[serviceString] = []
225                         self.updateServices()
226                         self.selectService(serviceString)
227                         self.updateAlternatives()
228                 
229         def yellowKey(self):
230                 if len(self.serviceslist) > 0:
231                         self.session.openWithCallback(self.finishedAlternativeSelection, SimpleChannelSelection, _("Select alternative service"))
232         
233         def blueKey(self):
234                 pass
235
236
237 oldPlayService = None
238
239 from Components.PerServiceDisplay import PerServiceDisplay
240
241 class ServiceChanged(PerServiceDisplay):
242         def __init__(self, navcore):
243                 PerServiceDisplay.__init__(self, navcore,
244                         {
245                                 iPlayableService.evTuneFailed: self.tuneFailed,
246                                 iPlayableService.evStart: self.start
247                         })
248                 
249                 self.lastPlayAction = None
250                 self.nextPlayTry = 0
251
252         def start(self):
253 #               print "+++++++++++++++++++++++++++++++++++++++++++++++++Start", self.lastPlayAction
254                 if self.lastPlayAction is not None:
255                         self.lastPlayAction = None
256
257         def tuneFailed(self):
258 #               print "+++++++++++++++++++++++++++++++++++++++++++++++++Tuning failed!", self.lastPlayAction
259                 ref = self.lastPlayAction
260 #               print "Ref:", ref
261 #               print "Alternatives: failed to play service"
262                 if ref is not None:
263                         if alternatives.has_key(ref):
264 #                                       print "Alternatives: trying alternatives"
265                                         if len(alternatives[ref]) > self.nextPlayTry:
266 #                                               print "Alternatives: trying alternative", alternatives[ref][self.nextPlayTry]
267                                                 if oldPlayService(ServiceReference(alternatives[ref][self.nextPlayTry]).ref) == 0:
268                                                                 self.nextPlayTry += 1
269 #                                                               print "Alternatives: Alternative found!"
270                                                 else:
271                                                                 self.nextPlayTry += 1
272 #                                                               print "Alternatives: Alternative doesn't play either"
273                                                                 self.tuneFailed()
274                                         else:
275                                                 self.lastPlayAction = None
276
277                                         #print "Alternatives: No playable alternative found!"
278
279 servicechanged = None
280
281 def playService(self, ref, **kwargs):
282         #print "--------------------Alternatives: trying to play service", str(ServiceReference(ref))
283         if ref is not None:
284                 servicechanged.lastPlayAction = str(ServiceReference(ref))
285         servicechanged.nextPlayTry = 0
286         result = oldPlayService(ref, **kwargs)
287         return result
288
289 def sessionstart(reason, session, **kwargs):
290         if reason == 0:
291                 try:
292                         loadAlternatives()
293                 except: # FIXME, THIS IS ILLEGAL CODE AND WILL BE PROSECUTED!
294                         pass
295                 
296                 # attach to this sessions navigation instance.
297                 global oldPlayService, servicechanged
298                 oldPlayService = session.nav.playService
299                 session.nav.playService = type(session.nav.playService)(playService, NavigationInstance, Navigation)
300                 servicechanged = ServiceChanged(session.nav)
301
302 def AlternativeZappingSetup(session, **kwargs):
303         session.open(AlternativeZapping)
304
305 def Plugins(**kwargs):
306         return [PluginDescriptor(where = PluginDescriptor.WHERE_SESSIONSTART, fnc = sessionstart),
307                         PluginDescriptor(name="Alternative services setup" , description="Defines alternatives for services.", where = PluginDescriptor.WHERE_PLUGINMENU, fnc=AlternativeZappingSetup)]