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