use 'Console' font in console window
[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: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: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) || (type == 134)'
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                 self.servicelist.setCurrent(service)
1001
1002         def getBouquetList(self):
1003                 bouquets = [ ]
1004                 serviceHandler = eServiceCenter.getInstance()
1005                 if config.usage.multibouquet.value:
1006                         list = serviceHandler.list(self.bouquet_root)
1007                         if list:
1008                                 while True:
1009                                         s = list.getNext()
1010                                         if not s.valid():
1011                                                 break
1012                                         if s.flags & eServiceReference.isDirectory:
1013                                                 info = serviceHandler.info(s)
1014                                                 if info:
1015                                                         bouquets.append((info.getName(s), s))
1016                                 return bouquets
1017                 else:
1018                         info = serviceHandler.info(self.bouquet_root)
1019                         if info:
1020                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
1021                         return bouquets
1022                 return None
1023
1024         def keyNumber0(self, num):
1025                 if len(self.servicePath) > 1:
1026                         self.keyGoUp()
1027                 else:
1028                         self.keyNumberGlobal(num)
1029
1030         def keyGoUp(self):
1031                 if len(self.servicePath) > 1:
1032                         if self.isBasePathEqual(self.bouquet_root):
1033                                 self.showFavourites()
1034                         else:
1035                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
1036                                 if self.isBasePathEqual(ref):
1037                                         self.showSatellites()
1038                                 else:
1039                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
1040                                         if self.isBasePathEqual(ref):
1041                                                 self.showProviders()
1042                                         else:
1043                                                 self.showAllServices()
1044
1045         def nextMarker(self):
1046                 self.servicelist.moveToNextMarker()
1047
1048         def prevMarker(self):
1049                 self.servicelist.moveToPrevMarker()
1050
1051 HISTORYSIZE = 20
1052
1053 #config for lastservice
1054 config.tv = ConfigSubsection()
1055 config.tv.lastservice = ConfigText()
1056 config.tv.lastroot = ConfigText()
1057 config.radio = ConfigSubsection()
1058 config.radio.lastservice = ConfigText()
1059 config.radio.lastroot = ConfigText()
1060 config.servicelist = ConfigSubsection()
1061 config.servicelist.lastmode = ConfigText(default = "tv")
1062
1063 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, SelectionEventInfo):
1064         def __init__(self, session):
1065                 ChannelSelectionBase.__init__(self,session)
1066                 ChannelSelectionEdit.__init__(self)
1067                 ChannelSelectionEPG.__init__(self)
1068                 SelectionEventInfo.__init__(self)
1069
1070                 self["CurrentTime"] = ObsoleteSource(new_source = "global.CurrentTime", removal_date = "2008-01")
1071
1072                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1073                         {
1074                                 "cancel": self.cancel,
1075                                 "ok": self.channelSelected,
1076                                 "keyRadio": self.setModeRadio,
1077                                 "keyTV": self.setModeTv,
1078                         })
1079
1080                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1081                         {
1082                                 iPlayableService.evStart: self.__evServiceStart,
1083                                 iPlayableService.evEnd: self.__evServiceEnd
1084                         })
1085
1086                 self.lastChannelRootTimer = eTimer()
1087                 self.lastChannelRootTimer.callback.append(self.__onCreate)
1088                 self.lastChannelRootTimer.start(100,True)
1089
1090                 self.history_tv = [ ]
1091                 self.history_radio = [ ]
1092                 self.history = self.history_tv
1093                 self.history_pos = 0
1094
1095                 self.lastservice = config.tv.lastservice
1096                 self.lastroot = config.tv.lastroot
1097                 self.revertMode = None
1098                 config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
1099                 self.new_service_played = False
1100                 self.onExecBegin.append(self.asciiOn)
1101
1102         def asciiOn(self):
1103                 rcinput = eRCInput.getInstance()
1104                 rcinput.setKeyboardMode(rcinput.kmAscii)
1105
1106         def asciiOff(self):
1107                 rcinput = eRCInput.getInstance()
1108                 rcinput.setKeyboardMode(rcinput.kmNone)
1109
1110         def multibouquet_config_changed(self, val):
1111                 self.recallBouquetMode()
1112
1113         def __evServiceStart(self):
1114                 service = self.session.nav.getCurrentService()
1115                 if service:
1116                         info = service.info()
1117                         if info:
1118                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1119                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1120
1121         def __evServiceEnd(self):
1122                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1123
1124         def setMode(self):
1125                 self.restoreRoot()
1126                 lastservice=eServiceReference(self.lastservice.value)
1127                 if lastservice.valid():
1128                         self.setCurrentSelection(lastservice)
1129
1130         def setModeTv(self):
1131                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
1132                         self.revertMode = MODE_RADIO
1133                 self.history = self.history_tv
1134                 self.lastservice = config.tv.lastservice
1135                 self.lastroot = config.tv.lastroot
1136                 config.servicelist.lastmode.value = "tv"
1137                 self.setTvMode()
1138                 self.setMode()
1139
1140         def setModeRadio(self):
1141                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
1142                         self.revertMode = MODE_TV
1143                 if config.usage.e1like_radio_mode.value:
1144                         self.history = self.history_radio
1145                         self.lastservice = config.radio.lastservice
1146                         self.lastroot = config.radio.lastroot
1147                         config.servicelist.lastmode.value = "radio"
1148                         self.setRadioMode()
1149                         self.setMode()
1150
1151         def __onCreate(self):
1152                 if config.usage.e1like_radio_mode.value:
1153                         if config.servicelist.lastmode.value == "tv":
1154                                 self.setModeTv()
1155                         else:
1156                                 self.setModeRadio()
1157                 else:
1158                         self.setModeTv()
1159                 lastservice=eServiceReference(self.lastservice.value)
1160                 if lastservice.valid():
1161                         self.zap()
1162
1163         def channelSelected(self):
1164                 ref = self.getCurrentSelection()
1165                 if self.movemode:
1166                         self.toggleMoveMarked()
1167                 elif (ref.flags & 7) == 7:
1168                         self.enterPath(ref)
1169                 elif self.bouquet_mark_edit != OFF:
1170                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1171                                 self.doMark()
1172                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1173                         root = self.getRoot()
1174                         if not root or not (root.flags & eServiceReference.isGroup):
1175                                 self.zap()
1176                                 self.asciiOff()
1177                                 self.close(ref)
1178
1179         #called from infoBar and channelSelected
1180         def zap(self):
1181                 self.revertMode=None
1182                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1183                 nref = self.getCurrentSelection()
1184                 if ref is None or ref != nref:
1185                         self.new_service_played = True
1186                         self.session.nav.playService(nref)
1187                         self.saveRoot()
1188                         self.saveChannel(nref)
1189                         config.servicelist.lastmode.save()
1190                         self.addToHistory(nref)
1191
1192         def newServicePlayed(self):
1193                 ret = self.new_service_played
1194                 self.new_service_played = False
1195                 return ret
1196
1197         def addToHistory(self, ref):
1198                 if self.servicePath is not None:
1199                         tmp=self.servicePath[:]
1200                         tmp.append(ref)
1201                         try:
1202                                 del self.history[self.history_pos+1:]
1203                         except:
1204                                 pass
1205                         self.history.append(tmp)
1206                         hlen = len(self.history)
1207                         if hlen > HISTORYSIZE:
1208                                 del self.history[0]
1209                                 hlen -= 1
1210                         self.history_pos = hlen-1
1211
1212         def historyBack(self):
1213                 hlen = len(self.history)
1214                 if hlen > 1 and self.history_pos > 0:
1215                         self.history_pos -= 1
1216                         self.setHistoryPath()
1217
1218         def historyNext(self):
1219                 hlen = len(self.history)
1220                 if hlen > 1 and self.history_pos < (hlen-1):
1221                         self.history_pos += 1
1222                         self.setHistoryPath()
1223
1224         def setHistoryPath(self):
1225                 path = self.history[self.history_pos][:]
1226                 ref = path.pop()
1227                 del self.servicePath[:]
1228                 self.servicePath += path
1229                 self.saveRoot()
1230                 plen = len(path)
1231                 root = path[plen-1]
1232                 cur_root = self.getRoot()
1233                 if cur_root and cur_root != root:
1234                         self.setRoot(root)
1235                 self.session.nav.playService(ref)
1236                 self.setCurrentSelection(ref)
1237                 self.saveChannel(ref)
1238
1239         def saveRoot(self):
1240                 path = ''
1241                 for i in self.servicePath:
1242                         path += i.toString()
1243                         path += ';'
1244                 if len(path) and path != self.lastroot.value:
1245                         self.lastroot.value = path
1246                         self.lastroot.save()
1247
1248         def restoreRoot(self):
1249                 self.clearPath()
1250                 re = compile('.+?;')
1251                 tmp = re.findall(self.lastroot.value)
1252                 cnt = 0
1253                 for i in tmp:
1254                         self.servicePath.append(eServiceReference(i[:len(i)-1]))
1255                         cnt += 1
1256                 if cnt:
1257                         path = self.servicePath.pop()
1258                         self.enterPath(path)
1259                 else:
1260                         self.showFavourites()
1261                         self.saveRoot()
1262
1263         def preEnterPath(self, refstr):
1264                 if len(self.servicePath) and self.servicePath[0] != eServiceReference(refstr):
1265                         pathstr = self.lastroot.value
1266                         if pathstr is not None and pathstr.find(refstr) == 0:
1267                                 self.restoreRoot()
1268                                 lastservice=eServiceReference(self.lastservice.value)
1269                                 if lastservice.valid():
1270                                         self.setCurrentSelection(lastservice)
1271                                 return True
1272                 return False
1273
1274         def saveChannel(self, ref):
1275                 if ref is not None:
1276                         refstr = ref.toString()
1277                 else:
1278                         refstr = ""
1279                 if refstr != self.lastservice.value:
1280                         self.lastservice.value = refstr
1281                         self.lastservice.save()
1282
1283         def setCurrentServicePath(self, path):
1284                 hlen = len(self.history)
1285                 if hlen > 0:
1286                         self.history[self.history_pos] = path
1287                 else:
1288                         self.history.append(path)
1289                 self.setHistoryPath()
1290
1291         def getCurrentServicePath(self):
1292                 hlen = len(self.history)
1293                 if hlen > 0:
1294                         return self.history[self.history_pos]
1295                 return None
1296
1297         def recallPrevService(self):
1298                 hlen = len(self.history)
1299                 if hlen > 1:
1300                         if self.history_pos == hlen-1:
1301                                 tmp = self.history[self.history_pos]
1302                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1303                                 self.history[self.history_pos-1] = tmp
1304                         else:
1305                                 tmp = self.history[self.history_pos+1]
1306                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1307                                 self.history[self.history_pos] = tmp
1308                         self.setHistoryPath()
1309
1310         def cancel(self):
1311                 if self.revertMode is None:
1312                         self.restoreRoot()
1313                         lastservice=eServiceReference(self.lastservice.value)
1314                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1315                                 self.setCurrentSelection(lastservice)
1316                 elif self.revertMode == MODE_TV:
1317                         self.setModeTv()
1318                 elif self.revertMode == MODE_RADIO:
1319                         self.setModeRadio()
1320                 self.revertMode = None
1321                 self.asciiOff()
1322                 self.close(None)
1323
1324 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName
1325
1326 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName):
1327         def __init__(self, session):
1328                 Screen.__init__(self, session)
1329                 InfoBarEvent.__init__(self)
1330                 InfoBarServiceName.__init__(self)
1331                 self["CurrentTime"] = ObsoleteSource(new_source = "global.CurrentTime", removal_date = "2008-01")
1332                 self["RdsDecoder"] = RdsDecoder(self.session.nav)
1333                 self["BlinkingPoint"] = Pixmap()
1334                 self["BlinkingPoint"].hide()
1335
1336 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
1337         ALLOW_SUSPEND = True
1338
1339         def __init__(self, session, infobar):
1340                 ChannelSelectionBase.__init__(self, session)
1341                 ChannelSelectionEdit.__init__(self)
1342                 ChannelSelectionEPG.__init__(self)
1343                 self.infobar = infobar
1344                 self.onLayoutFinish.append(self.onCreate)
1345
1346                 self.info = session.instantiateDialog(RadioInfoBar) # our simple infobar
1347
1348                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1349                         {
1350                                 "keyTV": self.closeRadio,
1351                                 "keyRadio": self.closeRadio,
1352                                 "cancel": self.closeRadio,
1353                                 "ok": self.channelSelected,
1354                         })
1355
1356                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1357                         {
1358                                 iPlayableService.evStart: self.__evServiceStart,
1359                                 iPlayableService.evEnd: self.__evServiceEnd
1360                         })
1361
1362 ########## RDS Radiotext / Rass Support BEGIN
1363                 self.infobar = infobar # reference to real infobar (the one and only)
1364                 self["RdsDecoder"] = self.info["RdsDecoder"]
1365                 self["RdsActions"] = HelpableActionMap(self, "InfobarRdsActions",
1366                 {
1367                         "startRassInteractive": (self.startRassInteractive, _("View Rass interactive..."))
1368                 },-1)
1369                 self["RdsActions"].setEnabled(False)
1370                 infobar.rds_display.onRassInteractivePossibilityChanged.append(self.RassInteractivePossibilityChanged)
1371
1372         def startRassInteractive(self):
1373                 self.info.hide();
1374                 self.infobar.rass_interactive = self.session.openWithCallback(self.RassInteractiveClosed, RassInteractive)
1375
1376         def RassInteractiveClosed(self):
1377                 self.info.show()
1378                 self.infobar.rass_interactive = None
1379                 self.infobar.RassSlidePicChanged()
1380
1381         def RassInteractivePossibilityChanged(self, state):
1382                 self["RdsActions"].setEnabled(state)
1383 ########## RDS Radiotext / Rass Support END
1384
1385         def closeRadio(self):
1386                 self.infobar.rds_display.onRassInteractivePossibilityChanged.remove(self.RassInteractivePossibilityChanged)
1387                 self.info.hide()
1388                 #set previous tv service
1389                 lastservice=eServiceReference(config.tv.lastservice.value)
1390                 self.session.nav.playService(lastservice)
1391                 self.close(None)
1392
1393         def __evServiceStart(self):
1394                 service = self.session.nav.getCurrentService()
1395                 if service:
1396                         info = service.info()
1397                         if info:
1398                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1399                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1400
1401         def __evServiceEnd(self):
1402                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1403
1404         def saveRoot(self):
1405                 path = ''
1406                 for i in self.servicePathRadio:
1407                         path += i.toString()
1408                         path += ';'
1409                 if len(path) and path != config.radio.lastroot.value:
1410                         config.radio.lastroot.value = path
1411                         config.radio.lastroot.save()
1412
1413         def restoreRoot(self):
1414                 self.clearPath()
1415                 re = compile('.+?;')
1416                 tmp = re.findall(config.radio.lastroot.value)
1417                 cnt = 0
1418                 for i in tmp:
1419                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
1420                         cnt += 1
1421                 if cnt:
1422                         path = self.servicePathRadio.pop()
1423                         self.enterPath(path)
1424                 else:
1425                         self.showFavourites()
1426                         self.saveRoot()
1427
1428         def preEnterPath(self, refstr):
1429                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
1430                         pathstr = config.radio.lastroot.value
1431                         if pathstr is not None and pathstr.find(refstr) == 0:
1432                                 self.restoreRoot()
1433                                 lastservice=eServiceReference(config.radio.lastservice.value)
1434                                 if lastservice.valid():
1435                                         self.setCurrentSelection(lastservice)
1436                                 return True
1437                 return False
1438
1439         def onCreate(self):
1440                 self.setRadioMode()
1441                 self.restoreRoot()
1442                 lastservice=eServiceReference(config.radio.lastservice.value)
1443                 if lastservice.valid():
1444                         self.servicelist.setCurrent(lastservice)
1445                         self.session.nav.playService(lastservice)
1446                 else:
1447                         self.session.nav.stopService()
1448                 self.info.show()
1449
1450         def channelSelected(self): # just return selected service
1451                 ref = self.getCurrentSelection()
1452                 if self.movemode:
1453                         self.toggleMoveMarked()
1454                 elif (ref.flags & 7) == 7:
1455                         self.enterPath(ref)
1456                 elif self.bouquet_mark_edit != OFF:
1457                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1458                                 self.doMark()
1459                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1460                         cur_root = self.getRoot()
1461                         if not cur_root or not (cur_root.flags & eServiceReference.isGroup):
1462                                 playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1463                                 if playingref is None or playingref != ref:
1464                                         self.session.nav.playService(ref)
1465                                         config.radio.lastservice.value = ref.toString()
1466                                         config.radio.lastservice.save()
1467                                 self.saveRoot()
1468
1469 class SimpleChannelSelection(ChannelSelectionBase):
1470         def __init__(self, session, title):
1471                 ChannelSelectionBase.__init__(self, session)
1472                 self.title = title
1473                 self.onShown.append(self.__onExecCallback)
1474
1475                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1476                         {
1477                                 "cancel": self.close,
1478                                 "ok": self.channelSelected,
1479                                 "keyRadio": self.setModeRadio,
1480                                 "keyTV": self.setModeTv,
1481                         })
1482
1483         def __onExecCallback(self):
1484                 self.setTitle(self.title)
1485                 self.setModeTv()
1486
1487         def channelSelected(self): # just return selected service
1488                 ref = self.getCurrentSelection()
1489                 if (ref.flags & 7) == 7:
1490                         self.enterPath(ref)
1491                 elif not (ref.flags & eServiceReference.isMarker):
1492                         ref = self.getCurrentSelection()
1493                         self.close(ref)
1494
1495         def setModeTv(self):
1496                 self.setTvMode()
1497                 self.showFavourites()
1498
1499         def setModeRadio(self):
1500                 self.setRadioMode()
1501                 self.showFavourites()