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