9cbb42210dc3ce4e0adcf2f26d4b4f6b4698e2b0
[vuplus_dvbapp] / lib / python / Screens / ChannelSelection.py
1 from Screen import Screen
2 from Components.Button import Button
3 from Components.ServiceList import ServiceList
4 from Components.ActionMap import NumberActionMap, ActionMap
5 from Components.MenuList import MenuList
6 from Components.ServiceEventTracker import ServiceEventTracker
7 from EpgSelection import EPGSelection
8 from enigma import eServiceReference, eEPGCache, eServiceCenter, eTimer, eDVBDB, iPlayableService, iServiceInformation
9 from Components.config import config, ConfigSubsection, ConfigText
10 from Screens.FixedMenu import FixedMenu
11 from Tools.NumericalTextInput import NumericalTextInput
12 from Components.NimManager import nimmanager
13 from Components.Sources.Clock import Clock
14 from Components.Input import Input
15 from Components.ParentalControl import parentalControl
16 from Screens.InputBox import InputBox, PinInput
17 from Screens.MessageBox import MessageBox
18 from ServiceReference import ServiceReference
19 from Tools.BoundFunction import boundFunction
20 from re import *
21 from os import remove
22
23 FLAG_SERVICE_NEW_FOUND = 64 #define in lib/dvb/idvb.h as dxNewFound = 64
24
25 import xml.dom.minidom
26
27 class BouquetSelector(Screen):
28         def __init__(self, session, bouquets, selectedFunc, enableWrapAround=False):
29                 Screen.__init__(self, session)
30
31                 self.selectedFunc=selectedFunc
32
33                 self["actions"] = ActionMap(["OkCancelActions"],
34                         {
35                                 "ok": self.okbuttonClick,
36                                 "cancel": self.cancelClick
37                         })
38                 entrys = [ ]
39                 for x in bouquets:
40                         entrys.append((x[0], x[1]))
41                 self["menu"] = MenuList(entrys, enableWrapAround)
42
43         def getCurrent(self):
44                 cur = self["menu"].getCurrent()
45                 return cur and cur[1]
46
47         def okbuttonClick(self):
48                 self.selectedFunc(self.getCurrent())
49
50         def up(self):
51                 self["menu"].up()
52
53         def down(self):
54                 self["menu"].down()
55
56         def cancelClick(self):
57                 self.close(False)
58
59 # csel.bouquet_mark_edit values
60 OFF = 0
61 EDIT_BOUQUET = 1
62 EDIT_ALTERNATIVES = 2
63
64 class ChannelContextMenu(Screen):
65         def __init__(self, session, csel):
66                 Screen.__init__(self, session)
67                 self.csel = csel
68                 self.bsel = None
69
70                 self["actions"] = ActionMap(["OkCancelActions"],
71                         {
72                                 "ok": self.okbuttonClick,
73                                 "cancel": self.cancelClick
74                         })
75                 menu = [ ]
76
77                 current_root = csel.getRoot()
78                 current_sel_path = csel.getCurrentSelection().getPath()
79                 current_sel_flags = csel.getCurrentSelection().flags
80                 inBouquetRootList = current_root and current_root.getPath().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
81                 inBouquet = csel.getMutableList() is not None
82                 haveBouquets = config.usage.multibouquet.value
83
84                 if csel.bouquet_mark_edit == OFF and not csel.movemode:
85                         if not inBouquetRootList:
86                                 isPlayable = not (current_sel_flags & (eServiceReference.isMarker|eServiceReference.isDirectory))
87                                 if isPlayable:
88                                         if config.ParentalControl.configured.value:
89                                                 if parentalControl.getProtectionLevel(csel.getCurrentSelection().toCompareString()) == -1:
90                                                         menu.append((_("add to parental protection"), boundFunction(self.addParentalProtection, csel.getCurrentSelection())))
91                                                 else:
92                                                         menu.append((_("remove from parental protection"), boundFunction(self.removeParentalProtection, csel.getCurrentSelection())))
93                                         if haveBouquets:
94                                                 menu.append((_("add service to bouquet"), self.addServiceToBouquetSelected))
95                                         else:
96                                                 menu.append((_("add service to favourites"), self.addServiceToBouquetSelected))
97                                 else:
98                                         if haveBouquets:
99                                                 if not inBouquet and current_sel_path.find("PROVIDERS") == -1:
100                                                         menu.append((_("copy to bouquets"), self.copyCurrentToBouquetList))
101                                         if current_sel_path.find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
102                                                 menu.append((_("remove all new found flags"), self.removeAllNewFoundFlags))
103                                 if inBouquet:
104                                         menu.append((_("remove entry"), self.removeCurrentService))
105                                 if current_root is not None and current_root.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
106                                         menu.append((_("remove new found flag"), self.removeNewFoundFlag))
107                         else:
108                                         menu.append((_("add bouquet"), self.showBouquetInputBox))
109                                         menu.append((_("remove entry"), self.removeBouquet))
110
111                 if inBouquet: # current list is editable?
112                         if csel.bouquet_mark_edit == OFF:
113                                 if not csel.movemode:
114                                         menu.append((_("enable move mode"), self.toggleMoveMode))
115                                         if not inBouquetRootList and not current_root.flags & eServiceReference.isGroup:
116                                                 menu.append((_("add marker"), self.showMarkerInputBox))
117                                                 if haveBouquets:
118                                                         menu.append((_("enable bouquet edit"), self.bouquetMarkStart))
119                                                 else:
120                                                         menu.append((_("enable favourite edit"), self.bouquetMarkStart))
121                                                 if current_sel_flags & eServiceReference.isGroup:
122                                                         menu.append((_("edit alternatives"), self.editAlternativeServices))
123                                                         menu.append((_("show alternatives"), self.showAlternativeServices))
124                                                         menu.append((_("remove all alternatives"), self.removeAlternativeServices))
125                                                 else:
126                                                         menu.append((_("add alternatives"), self.addAlternativeServices))
127                                 else:
128                                         menu.append((_("disable move mode"), self.toggleMoveMode))
129                         else:
130                                 if csel.bouquet_mark_edit == EDIT_BOUQUET:
131                                         if haveBouquets:
132                                                 menu.append((_("end bouquet edit"), self.bouquetMarkEnd))
133                                                 menu.append((_("abort bouquet edit"), self.bouquetMarkAbort))
134                                         else:
135                                                 menu.append((_("end favourites edit"), self.bouquetMarkEnd))
136                                                 menu.append((_("abort favourites edit"), self.bouquetMarkAbort))
137                                 else:
138                                                 menu.append((_("end alternatives edit"), self.bouquetMarkEnd))
139                                                 menu.append((_("abort alternatives edit"), self.bouquetMarkAbort))
140
141                 menu.append((_("back"), self.cancelClick))
142                 self["menu"] = MenuList(menu)
143
144         def okbuttonClick(self):
145                 self["menu"].getCurrent()[1]()
146
147         def cancelClick(self):
148                 self.close(False)
149                 
150         def showBouquetInputBox(self):
151                 self.session.openWithCallback(self.bouquetInputCallback, InputBox, title=_("Please enter a name for the new bouquet"), text="bouquetname", maxSize=False, type=Input.TEXT)
152
153         def bouquetInputCallback(self, bouquet):
154                 if bouquet is not None:
155                         self.csel.addBouquet(bouquet, None)
156                 self.close()
157
158         def addParentalProtection(self, service):
159                 parentalControl.protectService(service.toCompareString())
160                 self.close()
161
162         def removeParentalProtection(self, service):
163                 self.session.openWithCallback(boundFunction(self.pinEntered, service.toCompareString()), PinInput, pinList = [config.ParentalControl.servicepin[0].value], triesEntry = config.ParentalControl.retries.servicepin, title = _("Enter the service pin"), windowTitle = _("Change pin code"))
164
165         def pinEntered(self, service, result):
166                 if result:
167                         parentalControl.unProtectService(service)
168                         self.close()
169                 else:
170                         self.session.openWithCallback(self.close, MessageBox, _("The pin code you entered is wrong."), MessageBox.TYPE_ERROR)
171
172         def addServiceToBouquetSelected(self):
173                 bouquets = self.csel.getBouquetList()
174                 if bouquets is None:
175                         cnt = 0
176                 else:
177                         cnt = len(bouquets)
178                 if cnt > 1: # show bouquet list
179                         self.bsel = self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.addCurrentServiceToBouquet)
180                 elif cnt == 1: # add to only one existing bouquet
181                         self.addCurrentServiceToBouquet(bouquets[0][1])
182
183         def bouquetSelClosed(self, recursive):
184                 self.bsel = None
185                 if recursive:
186                         self.close(False)
187
188         def copyCurrentToBouquetList(self):
189                 self.csel.copyCurrentToBouquetList()
190                 self.close()
191
192         def removeBouquet(self):
193                 self.csel.removeBouquet()
194                 self.close()
195
196         def showMarkerInputBox(self):
197                 self.session.openWithCallback(self.markerInputCallback, InputBox, title=_("Please enter a name for the new marker"), text="markername", maxSize=False, type=Input.TEXT)
198
199         def markerInputCallback(self, marker):
200                 if marker is not None:
201                         self.csel.addMarker(marker)
202                 self.close()
203
204         def addCurrentServiceToBouquet(self, dest):
205                 self.csel.addServiceToBouquet(dest)
206                 if self.bsel is not None:
207                         self.bsel.close(True)
208                 else:
209                         self.close(True) # close bouquet selection
210
211         def removeCurrentService(self):
212                 self.csel.removeCurrentService()
213                 self.close()
214
215         def toggleMoveMode(self):
216                 self.csel.toggleMoveMode()
217                 self.close()
218
219         def bouquetMarkStart(self):
220                 self.csel.startMarkedEdit(EDIT_BOUQUET)
221                 self.close()
222
223         def bouquetMarkEnd(self):
224                 self.csel.endMarkedEdit(abort=False)
225                 self.close()
226
227         def bouquetMarkAbort(self):
228                 self.csel.endMarkedEdit(abort=True)
229                 self.close()
230
231         def removeNewFoundFlag(self):
232                 eDVBDB.getInstance().removeFlag(self.csel.getCurrentSelection(), FLAG_SERVICE_NEW_FOUND)
233                 self.close()
234
235         def removeAllNewFoundFlags(self):
236                 curpath = self.csel.getCurrentSelection().getPath()
237                 idx = curpath.find("satellitePosition == ")
238                 if idx != -1:
239                         tmp = curpath[idx+21:]
240                         idx = tmp.find(')')
241                         if idx != -1:
242                                 satpos = int(tmp[:idx])
243                                 eDVBDB.getInstance().removeFlags(FLAG_SERVICE_NEW_FOUND, -1, -1, -1, satpos)
244                 self.close()
245
246         def editAlternativeServices(self):
247                 self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
248                 self.close()
249
250         def showAlternativeServices(self):
251                 self.csel.enterPath(self.csel.getCurrentSelection())
252                 self.close()
253
254         def removeAlternativeServices(self):
255                 self.csel.removeAlternativeServices()
256                 self.close()
257
258         def addAlternativeServices(self):
259                 self.csel.addAlternativeServices()
260                 self.csel.startMarkedEdit(EDIT_ALTERNATIVES)
261                 self.close()
262
263 class ChannelSelectionEPG:
264         def __init__(self):
265                 self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
266                         {
267                                 "showEPGList": self.showEPGList,
268                         })
269
270         def showEPGList(self):
271                 ref=self.getCurrentSelection()
272                 ptr=eEPGCache.getInstance()
273                 if ptr.startTimeQuery(ref) != -1:
274                         self.session.open(EPGSelection, ref)
275                 else:
276                         print 'no epg for service', ref.toString()
277
278 class ChannelSelectionEdit:
279         def __init__(self):
280                 self.entry_marked = False
281                 self.movemode = False
282                 self.bouquet_mark_edit = OFF
283                 self.mutableList = None
284                 self.__marked = [ ]
285                 self.saved_title = None
286                 self.saved_root = None
287
288                 class ChannelSelectionEditActionMap(ActionMap):
289                         def __init__(self, csel, contexts = [ ], actions = { }, prio=0):
290                                 ActionMap.__init__(self, contexts, actions, prio)
291                                 self.csel = csel
292
293                         def action(self, contexts, action):
294                                 if action == "cancel":
295                                         self.csel.handleEditCancel()
296                                         return 0 # fall-trough
297                                 elif action == "ok":
298                                         return 0 # fall-trough
299                                 else:
300                                         return ActionMap.action(self, contexts, action)
301
302                 self["ChannelSelectEditActions"] = ChannelSelectionEditActionMap(self, ["ChannelSelectEditActions", "OkCancelActions"],
303                         {
304                                 "contextMenu": self.doContext,
305                         })
306
307         def getMutableList(self, root=eServiceReference()):
308                 if not self.mutableList is None:
309                         return self.mutableList
310                 serviceHandler = eServiceCenter.getInstance()
311                 if not root.valid():
312                         root=self.getRoot()
313                 list = root and serviceHandler.list(root)
314                 if list is not None:
315                         return list.startEdit()
316                 return None
317
318         def buildBouquetID(self, str):
319                 tmp = str.lower()
320                 name = ''
321                 for c in tmp:
322                         if (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9'):
323                                 name += c
324                         else:
325                                 name += '_'
326                 return name
327
328         def addMarker(self, name):
329                 current = self.servicelist.getCurrent()
330                 mutableList = self.getMutableList()
331                 cnt = 0
332                 while mutableList:
333                         str = '1:64:%d:0:0:0:0:0:0:0::%s'%(cnt, name)
334                         ref = eServiceReference(str)
335                         if current and current.valid():
336                                 if not mutableList.addService(ref, current):
337                                         self.servicelist.addService(ref, True)
338                                         mutableList.flushChanges()
339                                         break
340                         elif not mutableList.addService(ref):
341                                 self.servicelist.addService(ref, True)
342                                 mutableList.flushChanges()
343                                 break
344                         cnt+=1
345
346         def addAlternativeServices(self):
347                 cur_service = ServiceReference(self.getCurrentSelection())
348                 cur_root = ServiceReference(self.getRoot())
349                 mutableBouquet = cur_root.list().startEdit()
350                 if mutableBouquet:
351                         name = cur_service.getServiceName()
352                         print "NAME", name
353                         if self.mode == MODE_TV:
354                                 str = '1:134:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET \"alternatives.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(name))
355                         else:
356                                 str = '1:134:2:0:0:0:0:0:0:0:(type == 2) FROM BOUQUET \"alternatives.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(name))
357                         new_ref = ServiceReference(str)
358                         if not mutableBouquet.addService(new_ref.ref, cur_service.ref):
359                                 mutableBouquet.removeService(cur_service.ref)
360                                 mutableBouquet.flushChanges()
361                                 eDVBDB.getInstance().reloadBouquets()
362                                 mutableAlternatives = new_ref.list().startEdit()
363                                 if mutableAlternatives:
364                                         mutableAlternatives.setListName(name)
365                                         if mutableAlternatives.addService(cur_service.ref):
366                                                 print "add", cur_service.toString(), "to new alternatives failed"
367                                         mutableAlternatives.flushChanges()
368                                         self.servicelist.addService(new_ref.ref, True)
369                                         self.servicelist.removeCurrent()
370                                         self.servicelist.moveUp()
371                                 else:
372                                         print "get mutable list for new created alternatives failed"
373                         else:
374                                 print "add", str, "to", cur_root.getServiceName(), "failed"
375                 else:
376                         print "bouquetlist is not editable"
377
378         def addBouquet(self, bName, services):
379                 serviceHandler = eServiceCenter.getInstance()
380                 mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
381                 if mutableBouquetList:
382                         if self.mode == MODE_TV:
383                                 bName += " (TV)"
384                                 str = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(bName))
385                         else:
386                                 bName += " (Radio)"
387                                 str = '1:7:2:0:0:0:0:0:0:0:(type == 2) FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(bName))
388                         new_bouquet_ref = eServiceReference(str)
389                         if not mutableBouquetList.addService(new_bouquet_ref):
390                                 mutableBouquetList.flushChanges()
391                                 eDVBDB.getInstance().reloadBouquets()
392                                 mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
393                                 if mutableBouquet:
394                                         mutableBouquet.setListName(bName)
395                                         if services is not None:
396                                                 for service in services:
397                                                         if mutableBouquet.addService(service):
398                                                                 print "add", service.toString(), "to new bouquet failed"
399                                         mutableBouquet.flushChanges()
400                                 else:
401                                         print "get mutable list for new created bouquet failed"
402                                 # do some voodoo to check if current_root is equal to bouquet_root
403                                 cur_root = self.getRoot();
404                                 str1 = cur_root.toString()
405                                 pos1 = str1.find("FROM BOUQUET")
406                                 pos2 = self.bouquet_rootstr.find("FROM BOUQUET")
407                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == self.bouquet_rootstr[pos2:]:
408                                         self.servicelist.addService(new_bouquet_ref)
409                         else:
410                                 print "add", str, "to bouquets failed"
411                 else:
412                         print "bouquetlist is not editable"
413
414         def copyCurrentToBouquetList(self):
415                 provider = ServiceReference(self.getCurrentSelection())
416                 providerName = provider.getServiceName()
417                 serviceHandler = eServiceCenter.getInstance()
418                 services = serviceHandler.list(provider.ref)
419                 self.addBouquet(providerName, services and services.getContent('R', True))
420
421         def removeAlternativeServices(self):
422                 cur_service = ServiceReference(self.getCurrentSelection())
423                 cur_root = ServiceReference(self.getRoot())
424                 list = cur_service.list()
425                 first_in_alternative = list and list.getNext()
426                 if first_in_alternative:
427                         edit_root = cur_root.list().startEdit()
428                         if edit_root:
429                                 if not edit_root.addService(first_in_alternative, cur_service.ref):
430                                         self.servicelist.addService(first_in_alternative, True)
431                                 else:
432                                         print "couldn't add first alternative service to current root"
433                         else:
434                                 print "couldn't edit current root!!"
435                 else:
436                         print "remove empty alternative list !!"
437                 self.removeBouquet()
438                 self.servicelist.moveUp()
439
440         def removeBouquet(self):
441                 refstr = self.getCurrentSelection().toString()
442                 print "removeBouquet", refstr
443                 self.bouquetNumOffsetCache = { }
444                 pos = refstr.find('FROM BOUQUET "')
445                 filename = None
446                 if pos != -1:
447                         refstr = refstr[pos+14:]
448                         pos = refstr.find('"')
449                         if pos != -1:
450                                 filename = '/etc/enigma2/' + refstr[:pos] # FIXMEEE !!! HARDCODED /etc/enigma2
451                 self.removeCurrentService()
452                 try:
453                         if filename is not None:
454                                 remove(filename)
455                 except OSError:
456                         print "error during remove of", filename
457
458 #  multiple marked entry stuff ( edit mode, later multiepg selection )
459         def startMarkedEdit(self, type):
460                 self.savedPath = self.servicePath[:]
461                 if type == EDIT_ALTERNATIVES:
462                         self.enterPath(self.getCurrentSelection())
463                 self.mutableList = self.getMutableList()
464                 # add all services from the current list to internal marked set in listboxservicecontent
465                 self.clearMarks() # this clears the internal marked set in the listboxservicecontent
466                 self.saved_title = self.instance.getTitle()
467                 pos = self.saved_title.find(')')
468                 new_title = self.saved_title[:pos+1]
469                 if type == EDIT_ALTERNATIVES:
470                         self.bouquet_mark_edit = EDIT_ALTERNATIVES
471                         new_title += ' ' + _("[alternative edit]")
472                 else:
473                         self.bouquet_mark_edit = EDIT_BOUQUET
474                         if config.usage.multibouquet.value:
475                                 new_title += ' ' + _("[bouquet edit]")
476                         else:
477                                 new_title += ' ' + _("[favourite edit]")
478                 self.setTitle(new_title)
479                 self.__marked = self.servicelist.getRootServices()
480                 for x in self.__marked:
481                         self.servicelist.addMarked(eServiceReference(x))
482                 self.showAllServices()
483
484         def endMarkedEdit(self, abort):
485                 if not abort and self.mutableList is not None:
486                         self.bouquetNumOffsetCache = { }
487                         new_marked = set(self.servicelist.getMarked())
488                         old_marked = set(self.__marked)
489                         removed = old_marked - new_marked
490                         added = new_marked - old_marked
491                         changed = False
492                         for x in removed:
493                                 changed = True
494                                 self.mutableList.removeService(eServiceReference(x))
495                         for x in added:
496                                 changed = True
497                                 self.mutableList.addService(eServiceReference(x))
498                         if changed:
499                                 self.mutableList.flushChanges()
500                 self.__marked = []
501                 self.clearMarks()
502                 self.bouquet_mark_edit = OFF
503                 self.mutableList = None
504                 self.setTitle(self.saved_title)
505                 self.saved_title = None
506                 # self.servicePath is just a reference to servicePathTv or Radio...
507                 # so we never ever do use the asignment operator in self.servicePath
508                 del self.servicePath[:] # remove all elements
509                 self.servicePath += self.savedPath # add saved elements
510                 del self.savedPath
511                 self.setRoot(self.servicePath[len(self.servicePath)-1])
512
513         def clearMarks(self):
514                 self.servicelist.clearMarks()
515
516         def doMark(self):
517                 ref = self.servicelist.getCurrent()
518                 if self.servicelist.isMarked(ref):
519                         self.servicelist.removeMarked(ref)
520                 else:
521                         self.servicelist.addMarked(ref)
522
523         def removeCurrentService(self):
524                 ref = self.servicelist.getCurrent()
525                 mutableList = self.getMutableList()
526                 if ref.valid() and mutableList is not None:
527                         if not mutableList.removeService(ref):
528                                 self.bouquetNumOffsetCache = { }
529                                 mutableList.flushChanges() #FIXME dont flush on each single removed service
530                                 self.servicelist.removeCurrent()
531
532         def addServiceToBouquet(self, dest, service=None):
533                 mutableList = self.getMutableList(dest)
534                 if not mutableList is None:
535                         if service is None: #use current selected service
536                                 service = self.servicelist.getCurrent()
537                         if not mutableList.addService(service):
538                                 self.bouquetNumOffsetCache = { }
539                                 mutableList.flushChanges()
540                                 # do some voodoo to check if current_root is equal to dest
541                                 cur_root = self.getRoot();
542                                 str1 = cur_root.toString()
543                                 str2 = dest.toString()
544                                 pos1 = str1.find("FROM BOUQUET")
545                                 pos2 = str2.find("FROM BOUQUET")
546                                 if pos1 != -1 and pos2 != -1 and str1[pos1:] == str2[pos2:]:
547                                         self.servicelist.addService(service)
548
549         def toggleMoveMode(self):
550                 if self.movemode:
551                         if self.entry_marked:
552                                 self.toggleMoveMarked() # unmark current entry
553                         self.movemode = False
554                         self.pathChangeDisabled = False # re-enable path change
555                         self.mutableList.flushChanges() # FIXME add check if changes was made
556                         self.mutableList = None
557                         self.setTitle(self.saved_title)
558                         self.saved_title = None
559                         if self.getRoot() == self.bouquet_root:
560                                 self.bouquetNumOffsetCache = { }
561                 else:
562                         self.mutableList = self.getMutableList()
563                         self.movemode = True
564                         self.pathChangeDisabled = True # no path change allowed in movemode
565                         self.saved_title = self.instance.getTitle()
566                         new_title = self.saved_title
567                         pos = self.saved_title.find(')')
568                         new_title = self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]
569                         self.setTitle(new_title);
570
571         def handleEditCancel(self):
572                 if self.movemode: #movemode active?
573                         self.channelSelected() # unmark
574                         self.toggleMoveMode() # disable move mode
575                 elif self.bouquet_mark_edit != OFF:
576                         self.endMarkedEdit(True) # abort edit mode
577
578         def toggleMoveMarked(self):
579                 if self.entry_marked:
580                         self.servicelist.setCurrentMarked(False)
581                         self.entry_marked = False
582                 else:
583                         self.servicelist.setCurrentMarked(True)
584                         self.entry_marked = True
585
586         def doContext(self):
587                 self.session.open(ChannelContextMenu, self)
588
589 MODE_TV = 0
590 MODE_RADIO = 1
591
592 # this makes it much simple to implement a selectable radio or tv mode :)
593 service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17) || (type == 195) || (type == 25)'
594 service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2)'
595
596 class ChannelSelectionBase(Screen):
597         def __init__(self, session):
598                 Screen.__init__(self, session)
599
600                 self["key_red"] = Button(_("All"))
601                 self["key_green"] = Button(_("Satellites"))
602                 self["key_yellow"] = Button(_("Provider"))
603                 self["key_blue"] = Button(_("Favourites"))
604
605                 self["list"] = ServiceList()
606                 self.servicelist = self["list"]
607
608                 self.numericalTextInput = NumericalTextInput()
609                 self.numericalTextInput.setUseableChars(u'1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ')
610
611                 self.servicePathTV = [ ]
612                 self.servicePathRadio = [ ]
613                 self.servicePath = [ ]
614
615                 self.mode = MODE_TV
616
617                 self.pathChangeDisabled = False
618
619                 self.bouquetNumOffsetCache = { }
620
621                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions"],
622                         {
623                                 "showFavourites": self.showFavourites,
624                                 "showAllServices": self.showAllServices,
625                                 "showProviders": self.showProviders,
626                                 "showSatellites": self.showSatellites,
627                                 "nextBouquet": self.nextBouquet,
628                                 "prevBouquet": self.prevBouquet,
629                                 "nextMarker": self.nextMarker,
630                                 "prevMarker": self.prevMarker,
631                                 "1": self.keyNumberGlobal,
632                                 "2": self.keyNumberGlobal,
633                                 "3": self.keyNumberGlobal,
634                                 "4": self.keyNumberGlobal,
635                                 "5": self.keyNumberGlobal,
636                                 "6": self.keyNumberGlobal,
637                                 "7": self.keyNumberGlobal,
638                                 "8": self.keyNumberGlobal,
639                                 "9": self.keyNumberGlobal,
640                                 "0": self.keyNumber0
641                         })
642                 self.recallBouquetMode()
643
644         def appendDVBTypes(self, ref):
645                 path = ref.getPath()
646                 pos = path.find(' FROM BOUQUET')
647                 if pos != -1:
648                         return eServiceReference(self.service_types + path[pos:])
649                 return ref
650
651         def getBouquetNumOffset(self, bouquet):
652                 if not config.usage.multibouquet.value:
653                         return 0
654                 bouquet = self.appendDVBTypes(bouquet)
655                 str = bouquet.toString()
656                 offsetCount = 0
657                 if not self.bouquetNumOffsetCache.has_key(str):
658                         serviceHandler = eServiceCenter.getInstance()
659                         bouquetlist = serviceHandler.list(self.bouquet_root)
660                         if not bouquetlist is None:
661                                 while True:
662                                         bouquetIterator = self.appendDVBTypes(bouquetlist.getNext())
663                                         if not bouquetIterator.valid(): #end of list
664                                                 break
665                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
666                                         if not (bouquetIterator.flags & eServiceReference.isDirectory):
667                                                 continue
668                                         servicelist = serviceHandler.list(bouquetIterator)
669                                         if not servicelist is None:
670                                                 while True:
671                                                         serviceIterator = servicelist.getNext()
672                                                         if not serviceIterator.valid(): #check if end of list
673                                                                 break
674                                                         playable = not (serviceIterator.flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
675                                                         if playable:
676                                                                 offsetCount += 1
677                 return self.bouquetNumOffsetCache.get(str, offsetCount)
678
679         def recallBouquetMode(self):
680                 if self.mode == MODE_TV:
681                         self.service_types = service_types_tv
682                         if config.usage.multibouquet.value:
683                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
684                         else:
685                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
686                 else:
687                         self.service_types = service_types_radio
688                         if config.usage.multibouquet.value:
689                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
690                         else:
691                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
692                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
693
694         def setTvMode(self):
695                 self.mode = MODE_TV
696                 self.servicePath = self.servicePathTV
697                 self.recallBouquetMode()
698                 title = self.instance.getTitle()
699                 pos = title.find(" (")
700                 if pos != -1:
701                         title = title[:pos]
702                 title += " (TV)"
703                 self.setTitle(title)
704
705         def setRadioMode(self):
706                 self.mode = MODE_RADIO
707                 self.servicePath = self.servicePathRadio
708                 self.recallBouquetMode()
709                 title = self.instance.getTitle()
710                 pos = title.find(" (")
711                 if pos != -1:
712                         title = title[:pos]
713                 title += " (Radio)"
714                 self.setTitle(title)
715
716         def setRoot(self, root, justSet=False):
717                 path = root.getPath()
718                 inBouquetRootList = path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
719                 pos = path.find(' FROM BOUQUET')
720                 isBouquet = (pos != -1) and (root.flags & eServiceReference.isDirectory)
721                 if not inBouquetRootList and isBouquet:
722                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
723                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
724                         refstr = self.service_types + path[pos:]
725                         root = eServiceReference(refstr)
726                 else:
727                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
728                 self.servicelist.setRoot(root, justSet)
729                 self.buildTitleString()
730
731         def removeModeStr(self, str):
732                 if self.mode == MODE_TV:
733                         pos = str.find(' (TV)')
734                 else:
735                         pos = str.find(' (Radio)')
736                 if pos != -1:
737                         return str[:pos]
738                 return str
739
740         def getServiceName(self, ref):
741                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
742                 if not len(str):
743                         pathstr = ref.getPath()
744                         if pathstr.find('FROM PROVIDERS') != -1:
745                                 return _("Provider")
746                         if pathstr.find('FROM SATELLITES') != -1:
747                                 return _("Satellites")
748                         if pathstr.find(') ORDER BY name') != -1:
749                                 return _("All")
750                 return str
751
752         def buildTitleString(self):
753                 titleStr = self.instance.getTitle()
754                 pos = titleStr.find(']')
755                 if pos == -1:
756                         pos = titleStr.find(')')
757                 if pos != -1:
758                         titleStr = titleStr[:pos+1]
759                         Len = len(self.servicePath)
760                         if Len > 0:
761                                 base_ref = self.servicePath[0]
762                                 if Len > 1:
763                                         end_ref = self.servicePath[Len-1]
764                                 else:
765                                         end_ref = None
766                                 nameStr = self.getServiceName(base_ref)
767                                 titleStr += ' ' + nameStr
768                                 if end_ref is not None:
769                                         if Len > 2:
770                                                 titleStr += '/../'
771                                         else:
772                                                 titleStr += '/'
773                                         nameStr = self.getServiceName(end_ref)
774                                         titleStr += nameStr
775                                 self.setTitle(titleStr)
776
777         def moveUp(self):
778                 self.servicelist.moveUp()
779
780         def moveDown(self):
781                 self.servicelist.moveDown()
782
783         def clearPath(self):
784                 del self.servicePath[:]
785
786         def enterPath(self, ref, justSet=False):
787                 self.servicePath.append(ref)
788                 self.setRoot(ref, justSet)
789
790         def pathUp(self, justSet=False):
791                 prev = self.servicePath.pop()
792                 length = len(self.servicePath)
793                 if length:
794                         current = self.servicePath[length-1]
795                         self.setRoot(current, justSet)
796                         if not justSet:
797                                 self.setCurrentSelection(prev)
798                 return prev
799
800         def isBasePathEqual(self, ref):
801                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
802                         return True
803                 return False
804
805         def isPrevPathEqual(self, ref):
806                 length = len(self.servicePath)
807                 if length > 1 and self.servicePath[length-2] == ref:
808                         return True
809                 return False
810
811         def preEnterPath(self, refstr):
812                 return False
813
814         def showAllServices(self):
815                 if not self.pathChangeDisabled:
816                         refstr = '%s ORDER BY name'%(self.service_types)
817                         if not self.preEnterPath(refstr):
818                                 ref = eServiceReference(refstr)
819                                 currentRoot = self.getRoot()
820                                 if currentRoot is None or currentRoot != ref:
821                                         self.clearPath()
822                                         self.enterPath(ref)
823
824         def showSatellites(self):
825                 if not self.pathChangeDisabled:
826                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
827                         if not self.preEnterPath(refstr):
828                                 ref = eServiceReference(refstr)
829                                 justSet=False
830                                 prev = None
831
832                                 if self.isBasePathEqual(ref):
833                                         if self.isPrevPathEqual(ref):
834                                                 justSet=True
835                                         prev = self.pathUp(justSet)
836                                 else:
837                                         currentRoot = self.getRoot()
838                                         if currentRoot is None or currentRoot != ref:
839                                                 justSet=True
840                                                 self.clearPath()
841                                                 self.enterPath(ref, True)
842                                 if justSet:
843                                         serviceHandler = eServiceCenter.getInstance()
844                                         servicelist = serviceHandler.list(ref)
845                                         if not servicelist is None:
846                                                 while True:
847                                                         service = servicelist.getNext()
848                                                         if not service.valid(): #check if end of list
849                                                                 break
850                                                         orbpos = service.getUnsignedData(4) >> 16
851                                                         if service.getPath().find("FROM PROVIDER") != -1:
852                                                                 service_name = _("Providers")
853                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
854                                                                 service_name = _("New")
855                                                         else:
856                                                                 service_name = _("Services")
857                                                         try:
858                                                                 service_name += str(' - %s'%(nimmanager.getSatDescription(orbpos)))
859                                                                 service.setName(service_name) # why we need this cast?
860                                                         except:
861                                                                 if orbpos == 0xFFFF: #Cable
862                                                                         n = ("%s (%s)") % (service_name, _("Cable"))
863                                                                 elif orbpos == 0xEEEE: #Terrestrial
864                                                                         n = ("%s (%s)") % (service_name, _("Terrestrial"))
865                                                                 else:
866                                                                         if orbpos > 1800: # west
867                                                                                 orbpos = 3600 - orbpos
868                                                                                 h = _("W")
869                                                                         else:
870                                                                                 h = _("E")
871                                                                         n = ("%s (%d.%d" + h + ")") % (service_name, orbpos / 10, orbpos % 10)
872                                                                 service.setName(n)
873                                                         self.servicelist.addService(service)
874                                                 self.servicelist.finishFill()
875                                                 if prev is not None:
876                                                         self.setCurrentSelection(prev)
877
878         def showProviders(self):
879                 if not self.pathChangeDisabled:
880                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
881                         if not self.preEnterPath(refstr):
882                                 ref = eServiceReference(refstr)
883                                 if self.isBasePathEqual(ref):
884                                         self.pathUp()
885                                 else:
886                                         currentRoot = self.getRoot()
887                                         if currentRoot is None or currentRoot != ref:
888                                                 self.clearPath()
889                                                 self.enterPath(ref)
890
891         def changeBouquet(self, direction):
892                 if not self.pathChangeDisabled:
893                         if len(self.servicePath) > 1:
894                                 #when enter satellite root list we must do some magic stuff..
895                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
896                                 if self.isBasePathEqual(ref):
897                                         self.showSatellites()
898                                 else:
899                                         self.pathUp()
900                                 if direction < 0:
901                                         self.moveUp()
902                                 else:
903                                         self.moveDown()
904                                 ref = self.getCurrentSelection()
905                                 self.enterPath(ref)
906
907         def inBouquet(self):
908                 return self.isBasePathEqual(self.bouquet_root)
909
910         def atBegin(self):
911                 return self.servicelist.atBegin()
912
913         def atEnd(self):
914                 return self.servicelist.atEnd()
915
916         def nextBouquet(self):
917                 self.changeBouquet(+1)
918
919         def prevBouquet(self):
920                 self.changeBouquet(-1)
921
922         def showFavourites(self):
923                 if not self.pathChangeDisabled:
924                         if not self.preEnterPath(self.bouquet_rootstr):
925                                 if self.isBasePathEqual(self.bouquet_root):
926                                         self.pathUp()
927                                 else:
928                                         currentRoot = self.getRoot()
929                                         if currentRoot is None or currentRoot != self.bouquet_root:
930                                                 self.clearPath()
931                                                 self.enterPath(self.bouquet_root)
932
933         def keyNumberGlobal(self, number):
934                 unichar = self.numericalTextInput.getKey(number)
935                 charstr = unichar.encode("utf-8")
936                 if len(charstr) == 1:
937                         self.servicelist.moveToChar(charstr[0])
938
939         def getRoot(self):
940                 return self.servicelist.getRoot()
941
942         def getCurrentSelection(self):
943                 return self.servicelist.getCurrent()
944
945         def setCurrentSelection(self, service):
946                 servicepath = service.getPath()
947                 pos = servicepath.find(" FROM BOUQUET")
948                 if pos != -1:
949                         if self.mode == MODE_TV:
950                                 servicepath = '(type == 1)' + servicepath[pos:]
951                         else:
952                                 servicepath = '(type == 2)' + servicepath[pos:]
953                         service.setPath(servicepath)
954                 self.servicelist.setCurrent(service)
955
956         def getBouquetList(self):
957                 bouquets = [ ]
958                 serviceHandler = eServiceCenter.getInstance()
959                 if config.usage.multibouquet.value:
960                         list = serviceHandler.list(self.bouquet_root)
961                         if list:
962                                 while True:
963                                         s = list.getNext()
964                                         if not s.valid():
965                                                 break
966                                         if s.flags & eServiceReference.isDirectory:
967                                                 info = serviceHandler.info(s)
968                                                 if info:
969                                                         bouquets.append((info.getName(s), s))
970                                 return bouquets
971                 else:
972                         info = serviceHandler.info(self.bouquet_root)
973                         if info:
974                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
975                         return bouquets
976                 return None
977
978         def keyNumber0(self, num):
979                 if len(self.servicePath) > 1:
980                         self.keyGoUp()
981                 else:
982                         self.keyNumberGlobal(num)
983
984         def keyGoUp(self):
985                 if len(self.servicePath) > 1:
986                         if self.isBasePathEqual(self.bouquet_root):
987                                 self.showFavourites()
988                         else:
989                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
990                                 if self.isBasePathEqual(ref):
991                                         self.showSatellites()
992                                 else:
993                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
994                                         if self.isBasePathEqual(ref):
995                                                 self.showProviders()
996                                         else:
997                                                 self.showAllServices()
998
999         def nextMarker(self):
1000                 self.servicelist.moveToNextMarker()
1001
1002         def prevMarker(self):
1003                 self.servicelist.moveToPrevMarker()
1004
1005 HISTORYSIZE = 20
1006
1007 #config for lastservice
1008 config.tv = ConfigSubsection()
1009 config.tv.lastservice = ConfigText()
1010 config.tv.lastroot = ConfigText()
1011 config.radio = ConfigSubsection()
1012 config.radio.lastservice = ConfigText()
1013 config.radio.lastroot = ConfigText()
1014 config.servicelist = ConfigSubsection()
1015 config.servicelist.lastmode = ConfigText(default = "tv")
1016
1017 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
1018         def __init__(self, session):
1019                 ChannelSelectionBase.__init__(self,session)
1020                 ChannelSelectionEdit.__init__(self)
1021                 ChannelSelectionEPG.__init__(self)
1022
1023                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1024                         {
1025                                 "cancel": self.cancel,
1026                                 "ok": self.channelSelected,
1027                                 "keyRadio": self.setModeRadio,
1028                                 "keyTV": self.setModeTv,
1029                         })
1030
1031                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1032                         {
1033                                 iPlayableService.evStart: self.__evServiceStart,
1034                                 iPlayableService.evEnd: self.__evServiceEnd
1035                         })
1036
1037                 self.lastChannelRootTimer = eTimer()
1038                 self.lastChannelRootTimer.timeout.get().append(self.__onCreate)
1039                 self.lastChannelRootTimer.start(100,True)
1040
1041                 self.history_tv = [ ]
1042                 self.history_radio = [ ]
1043                 self.history = self.history_tv
1044                 self.history_pos = 0
1045
1046                 self.lastservice = config.tv.lastservice
1047                 self.lastroot = config.tv.lastroot
1048                 self.revertMode = None
1049                 config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
1050
1051         def multibouquet_config_changed(self, val):
1052                 self.recallBouquetMode()
1053
1054         def __evServiceStart(self):
1055                 service = self.session.nav.getCurrentService()
1056                 if service:
1057                         info = service.info()
1058                         if info:
1059                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1060                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1061
1062         def __evServiceEnd(self):
1063                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1064
1065         def setMode(self):
1066                 self.restoreRoot()
1067                 lastservice=eServiceReference(self.lastservice.value)
1068                 if lastservice.valid():
1069                         self.setCurrentSelection(lastservice)
1070
1071         def setModeTv(self):
1072                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
1073                         self.revertMode = MODE_RADIO
1074                 self.history = self.history_tv
1075                 self.lastservice = config.tv.lastservice
1076                 self.lastroot = config.tv.lastroot
1077                 config.servicelist.lastmode.value = "tv"
1078                 self.setTvMode()
1079                 self.setMode()
1080
1081         def setModeRadio(self):
1082                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
1083                         self.revertMode = MODE_TV
1084                 if config.usage.e1like_radio_mode.value:
1085                         self.history = self.history_radio
1086                         self.lastservice = config.radio.lastservice
1087                         self.lastroot = config.radio.lastroot
1088                         config.servicelist.lastmode.value = "radio"
1089                         self.setRadioMode()
1090                         self.setMode()
1091
1092         def __onCreate(self):
1093                 if config.usage.e1like_radio_mode.value:
1094                         if config.servicelist.lastmode.value == "tv":
1095                                 self.setModeTv()
1096                         else:
1097                                 self.setModeRadio()
1098                 else:
1099                         self.setModeTv()
1100                 lastservice=eServiceReference(self.lastservice.value)
1101                 if lastservice.valid():
1102                         self.zap()
1103
1104         def channelSelected(self):
1105                 ref = self.getCurrentSelection()
1106                 if self.movemode:
1107                         self.toggleMoveMarked()
1108                 elif (ref.flags & 7) == 7:
1109                         self.enterPath(ref)
1110                 elif self.bouquet_mark_edit != OFF:
1111                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1112                                 self.doMark()
1113                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1114                         if not (self.getRoot().flags & eServiceReference.isGroup):
1115                                 self.zap()
1116                                 self.close(ref)
1117
1118         #called from infoBar and channelSelected
1119         def zap(self):
1120                 self.revertMode=None
1121                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1122                 nref = self.getCurrentSelection()
1123                 if ref is None or ref != nref:
1124                         self.session.nav.playService(nref)
1125                         self.saveRoot()
1126                         self.saveChannel(nref)
1127                         config.servicelist.lastmode.save()
1128                         self.addToHistory(nref)
1129
1130         def addToHistory(self, ref):
1131                 if self.servicePath is not None:
1132                         tmp=self.servicePath[:]
1133                         tmp.append(ref)
1134                         try:
1135                                 del self.history[self.history_pos+1:]
1136                         except:
1137                                 pass
1138                         self.history.append(tmp)
1139                         hlen = len(self.history)
1140                         if hlen > HISTORYSIZE:
1141                                 del self.history[0]
1142                                 hlen -= 1
1143                         self.history_pos = hlen-1
1144
1145         def historyBack(self):
1146                 hlen = len(self.history)
1147                 if hlen > 1 and self.history_pos > 0:
1148                         self.history_pos -= 1
1149                         self.setHistoryPath()
1150
1151         def historyNext(self):
1152                 hlen = len(self.history)
1153                 if hlen > 1 and self.history_pos < (hlen-1):
1154                         self.history_pos += 1
1155                         self.setHistoryPath()
1156
1157         def setHistoryPath(self):
1158                 path = self.history[self.history_pos][:]
1159                 ref = path.pop()
1160                 del self.servicePath[:]
1161                 self.servicePath += path
1162                 self.saveRoot()
1163                 plen = len(path)
1164                 root = path[plen-1]
1165                 if self.getRoot() != root:
1166                         self.setRoot(root)
1167                 self.session.nav.playService(ref)
1168                 self.setCurrentSelection(ref)
1169                 self.saveChannel(ref)
1170
1171         def saveRoot(self):
1172                 path = ''
1173                 for i in self.servicePath:
1174                         path += i.toString()
1175                         path += ';'
1176                 if len(path) and path != self.lastroot.value:
1177                         self.lastroot.value = path
1178                         self.lastroot.save()
1179
1180         def restoreRoot(self):
1181                 self.clearPath()
1182                 re = compile('.+?;')
1183                 tmp = re.findall(self.lastroot.value)
1184                 cnt = 0
1185                 for i in tmp:
1186                         self.servicePath.append(eServiceReference(i[:len(i)-1]))
1187                         cnt += 1
1188                 if cnt:
1189                         path = self.servicePath.pop()
1190                         self.enterPath(path)
1191                 else:
1192                         self.showFavourites()
1193                         self.saveRoot()
1194
1195         def preEnterPath(self, refstr):
1196                 if len(self.servicePath) and self.servicePath[0] != eServiceReference(refstr):
1197                         pathstr = self.lastroot.value
1198                         if pathstr is not None and pathstr.find(refstr) == 0:
1199                                 self.restoreRoot()
1200                                 lastservice=eServiceReference(self.lastservice.value)
1201                                 if lastservice.valid():
1202                                         self.setCurrentSelection(lastservice)
1203                                 return True
1204                 return False
1205
1206         def saveChannel(self, ref):
1207                 if ref is not None:
1208                         refstr = ref.toString()
1209                 else:
1210                         refstr = ""
1211                 if refstr != self.lastservice.value:
1212                         self.lastservice.value = refstr
1213                         self.lastservice.save()
1214
1215         def setCurrentServicePath(self, path):
1216                 hlen = len(self.history)
1217                 if hlen > 0:
1218                         self.history[self.history_pos] = path
1219                 else:
1220                         self.history.append(path)
1221                 self.setHistoryPath()
1222
1223         def getCurrentServicePath(self):
1224                 hlen = len(self.history)
1225                 if hlen > 0:
1226                         return self.history[self.history_pos]
1227                 return None
1228
1229         def recallPrevService(self):
1230                 hlen = len(self.history)
1231                 if hlen > 1:
1232                         if self.history_pos == hlen-1:
1233                                 tmp = self.history[self.history_pos]
1234                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1235                                 self.history[self.history_pos-1] = tmp
1236                         else:
1237                                 tmp = self.history[self.history_pos+1]
1238                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1239                                 self.history[self.history_pos] = tmp
1240                         self.setHistoryPath()
1241
1242         def cancel(self):
1243                 if self.revertMode is None:
1244                         self.restoreRoot()
1245                         lastservice=eServiceReference(self.lastservice.value)
1246                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1247                                 self.setCurrentSelection(lastservice)
1248                 elif self.revertMode == MODE_TV:
1249                         self.setModeTv()
1250                 elif self.revertMode == MODE_RADIO:
1251                         self.setModeRadio()
1252                 self.revertMode = None
1253                 self.close(None)
1254
1255 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord, InfoBarRadioText
1256
1257 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
1258         def __init__(self, session):
1259                 Screen.__init__(self, session)
1260                 InfoBarEvent.__init__(self)
1261                 InfoBarServiceName.__init__(self)
1262                 InfoBarInstantRecord.__init__(self)
1263                 self["CurrentTime"] = Clock()
1264
1265 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarRadioText):
1266
1267         ALLOW_SUSPEND = True
1268
1269         def __init__(self, session):
1270                 ChannelSelectionBase.__init__(self, session)
1271                 ChannelSelectionEdit.__init__(self)
1272                 ChannelSelectionEPG.__init__(self)
1273                 InfoBarRadioText.__init__(self)
1274
1275                 config.radio = ConfigSubsection();
1276                 config.radio.lastservice = ConfigText()
1277                 config.radio.lastroot = ConfigText()
1278                 self.onLayoutFinish.append(self.onCreate)
1279
1280                 self.info = session.instantiateDialog(RadioInfoBar)
1281
1282                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1283                         {
1284                                 "keyTV": self.closeRadio,
1285                                 "keyRadio": self.closeRadio,
1286                                 "cancel": self.closeRadio,
1287                                 "ok": self.channelSelected,
1288                         })
1289
1290                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1291                         {
1292                                 iPlayableService.evStart: self.__evServiceStart,
1293                                 iPlayableService.evEnd: self.__evServiceEnd
1294                         })
1295
1296         def __evServiceStart(self):
1297                 service = self.session.nav.getCurrentService()
1298                 if service:
1299                         info = service.info()
1300                         if info:
1301                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1302                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1303
1304         def __evServiceEnd(self):
1305                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1306
1307         def saveRoot(self):
1308                 path = ''
1309                 for i in self.servicePathRadio:
1310                         path += i.toString()
1311                         path += ';'
1312                 if len(path) and path != config.radio.lastroot.value:
1313                         config.radio.lastroot.value = path
1314                         config.radio.lastroot.save()
1315
1316         def restoreRoot(self):
1317                 self.clearPath()
1318                 re = compile('.+?;')
1319                 tmp = re.findall(config.radio.lastroot.value)
1320                 cnt = 0
1321                 for i in tmp:
1322                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
1323                         cnt += 1
1324                 if cnt:
1325                         path = self.servicePathRadio.pop()
1326                         self.enterPath(path)
1327                 else:
1328                         self.showFavourites()
1329                         self.saveRoot()
1330
1331         def preEnterPath(self, refstr):
1332                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
1333                         pathstr = config.radio.lastroot.value
1334                         if pathstr is not None and pathstr.find(refstr) == 0:
1335                                 self.restoreRoot()
1336                                 lastservice=eServiceReference(config.radio.lastservice.value)
1337                                 if lastservice.valid():
1338                                         self.setCurrentSelection(lastservice)
1339                                 return True
1340                 return False
1341
1342         def onCreate(self):
1343                 self.setRadioMode()
1344                 self.restoreRoot()
1345                 lastservice=eServiceReference(config.radio.lastservice.value)
1346                 if lastservice.valid():
1347                         self.servicelist.setCurrent(lastservice)
1348                         self.session.nav.playService(lastservice)
1349                 self.info.show()
1350
1351         def channelSelected(self): # just return selected service
1352                 ref = self.getCurrentSelection()
1353                 if self.movemode:
1354                         self.toggleMoveMarked()
1355                 elif (ref.flags & 7) == 7:
1356                         self.enterPath(ref)
1357                 elif self.bouquet_mark_edit != OFF:
1358                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1359                                 self.doMark()
1360                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1361                         if not (self.getRoot().flags & eServiceReference.isGroup):
1362                                 playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1363                                 if playingref is None or playingref != ref:
1364                                         self.session.nav.playService(ref)
1365                                         config.radio.lastservice.value = ref.toString()
1366                                         config.radio.lastservice.save()
1367                                 self.saveRoot()
1368
1369         def closeRadio(self):
1370                 self.info.hide()
1371                 #set previous tv service
1372                 lastservice=eServiceReference(config.tv.lastservice.value)
1373                 self.session.nav.playService(lastservice)
1374                 self.close(None)
1375
1376 class SimpleChannelSelection(ChannelSelectionBase):
1377         def __init__(self, session, title):
1378                 ChannelSelectionBase.__init__(self, session)
1379                 self.title = title
1380                 self.onShown.append(self.__onExecCallback)
1381
1382                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1383                         {
1384                                 "cancel": self.close,
1385                                 "ok": self.channelSelected,
1386                                 "keyRadio": self.setModeRadio,
1387                                 "keyTV": self.setModeTv,
1388                         })
1389
1390         def __onExecCallback(self):
1391                 self.setTitle(self.title)
1392                 self.setModeTv()
1393
1394         def channelSelected(self): # just return selected service
1395                 ref = self.getCurrentSelection()
1396                 if (ref.flags & 7) == 7:
1397                         self.enterPath(ref)
1398                 elif not (ref.flags & eServiceReference.isMarker):
1399                         ref = self.getCurrentSelection()
1400                         self.close(ref)
1401
1402         def setModeTv(self):
1403                 self.setTvMode()
1404                 self.showFavourites()
1405
1406         def setModeRadio(self):
1407                 self.setRadioMode()
1408                 self.showFavourites()