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