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