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