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