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