fix possibility for bluescreen
[vuplus_dvbapp] / 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 appendDVBTypes(self, ref):
654                 path = ref.getPath()
655                 pos = path.find(' FROM BOUQUET')
656                 if pos != -1:
657                         return eServiceReference(self.service_types + path[pos:])
658                 return ref
659
660         def getBouquetNumOffset(self, bouquet):
661                 if not config.usage.multibouquet.value:
662                         return 0
663                 bouquet = self.appendDVBTypes(bouquet)
664                 str = bouquet.toString()
665                 offsetCount = 0
666                 if not self.bouquetNumOffsetCache.has_key(str):
667                         serviceHandler = eServiceCenter.getInstance()
668                         bouquetlist = serviceHandler.list(self.bouquet_root)
669                         if not bouquetlist is None:
670                                 while True:
671                                         bouquetIterator = self.appendDVBTypes(bouquetlist.getNext())
672                                         if not bouquetIterator.valid(): #end of list
673                                                 break
674                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
675                                         if not (bouquetIterator.flags & eServiceReference.isDirectory):
676                                                 continue
677                                         servicelist = serviceHandler.list(bouquetIterator)
678                                         if not servicelist is None:
679                                                 while True:
680                                                         serviceIterator = servicelist.getNext()
681                                                         if not serviceIterator.valid(): #check if end of list
682                                                                 break
683                                                         playable = not (serviceIterator.flags & (eServiceReference.isDirectory|eServiceReference.isMarker))
684                                                         if playable:
685                                                                 offsetCount += 1
686                 return self.bouquetNumOffsetCache.get(str, offsetCount)
687
688         def recallBouquetMode(self):
689                 if self.mode == MODE_TV:
690                         self.service_types = service_types_tv
691                         if config.usage.multibouquet.value:
692                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
693                         else:
694                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
695                 else:
696                         self.service_types = service_types_radio
697                         if config.usage.multibouquet.value:
698                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
699                         else:
700                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
701                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
702
703         def setTvMode(self):
704                 self.mode = MODE_TV
705                 self.servicePath = self.servicePathTV
706                 self.recallBouquetMode()
707                 title = self.instance.getTitle()
708                 pos = title.find(" (")
709                 if pos != -1:
710                         title = title[:pos]
711                 title += " (TV)"
712                 self.setTitle(title)
713
714         def setRadioMode(self):
715                 self.mode = MODE_RADIO
716                 self.servicePath = self.servicePathRadio
717                 self.recallBouquetMode()
718                 title = self.instance.getTitle()
719                 pos = title.find(" (")
720                 if pos != -1:
721                         title = title[:pos]
722                 title += " (Radio)"
723                 self.setTitle(title)
724
725         def setRoot(self, root, justSet=False):
726                 path = root.getPath()
727                 inBouquetRootList = path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
728                 pos = path.find(' FROM BOUQUET')
729                 isBouquet = (pos != -1) and (root.flags & eServiceReference.isDirectory)
730                 if not inBouquetRootList and isBouquet:
731                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
732                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
733                         refstr = self.service_types + path[pos:]
734                         root = eServiceReference(refstr)
735                 else:
736                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
737                 self.servicelist.setRoot(root, justSet)
738                 self.buildTitleString()
739
740         def removeModeStr(self, str):
741                 if self.mode == MODE_TV:
742                         pos = str.find(' (TV)')
743                 else:
744                         pos = str.find(' (Radio)')
745                 if pos != -1:
746                         return str[:pos]
747                 return str
748
749         def getServiceName(self, ref):
750                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
751                 if not len(str):
752                         pathstr = ref.getPath()
753                         if pathstr.find('FROM PROVIDERS') != -1:
754                                 return _("Provider")
755                         if pathstr.find('FROM SATELLITES') != -1:
756                                 return _("Satellites")
757                         if pathstr.find(') ORDER BY name') != -1:
758                                 return _("All")
759                 return str
760
761         def buildTitleString(self):
762                 titleStr = self.instance.getTitle()
763                 pos = titleStr.find(']')
764                 if pos == -1:
765                         pos = titleStr.find(')')
766                 if pos != -1:
767                         titleStr = titleStr[:pos+1]
768                         Len = len(self.servicePath)
769                         if Len > 0:
770                                 base_ref = self.servicePath[0]
771                                 if Len > 1:
772                                         end_ref = self.servicePath[Len-1]
773                                 else:
774                                         end_ref = None
775                                 nameStr = self.getServiceName(base_ref)
776                                 titleStr += ' ' + nameStr
777                                 if end_ref is not None:
778                                         if Len > 2:
779                                                 titleStr += '/../'
780                                         else:
781                                                 titleStr += '/'
782                                         nameStr = self.getServiceName(end_ref)
783                                         titleStr += nameStr
784                                 self.setTitle(titleStr)
785
786         def moveUp(self):
787                 self.servicelist.moveUp()
788
789         def moveDown(self):
790                 self.servicelist.moveDown()
791
792         def clearPath(self):
793                 del self.servicePath[:]
794
795         def enterPath(self, ref, justSet=False):
796                 self.servicePath.append(ref)
797                 self.setRoot(ref, justSet)
798
799         def pathUp(self, justSet=False):
800                 prev = self.servicePath.pop()
801                 length = len(self.servicePath)
802                 if length:
803                         current = self.servicePath[length-1]
804                         self.setRoot(current, justSet)
805                         if not justSet:
806                                 self.setCurrentSelection(prev)
807                 return prev
808
809         def isBasePathEqual(self, ref):
810                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
811                         return True
812                 return False
813
814         def isPrevPathEqual(self, ref):
815                 length = len(self.servicePath)
816                 if length > 1 and self.servicePath[length-2] == ref:
817                         return True
818                 return False
819
820         def preEnterPath(self, refstr):
821                 return False
822
823         def showAllServices(self):
824                 if not self.pathChangeDisabled:
825                         refstr = '%s ORDER BY name'%(self.service_types)
826                         if not self.preEnterPath(refstr):
827                                 ref = eServiceReference(refstr)
828                                 currentRoot = self.getRoot()
829                                 if currentRoot is None or currentRoot != ref:
830                                         self.clearPath()
831                                         self.enterPath(ref)
832
833         def showSatellites(self):
834                 if not self.pathChangeDisabled:
835                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
836                         if not self.preEnterPath(refstr):
837                                 ref = eServiceReference(refstr)
838                                 justSet=False
839                                 prev = None
840
841                                 if self.isBasePathEqual(ref):
842                                         if self.isPrevPathEqual(ref):
843                                                 justSet=True
844                                         prev = self.pathUp(justSet)
845                                 else:
846                                         currentRoot = self.getRoot()
847                                         if currentRoot is None or currentRoot != ref:
848                                                 justSet=True
849                                                 self.clearPath()
850                                                 self.enterPath(ref, True)
851                                 if justSet:
852                                         serviceHandler = eServiceCenter.getInstance()
853                                         servicelist = serviceHandler.list(ref)
854                                         if not servicelist is None:
855                                                 while True:
856                                                         service = servicelist.getNext()
857                                                         if not service.valid(): #check if end of list
858                                                                 break
859                                                         orbpos = service.getUnsignedData(4) >> 16
860                                                         if service.getPath().find("FROM PROVIDER") != -1:
861                                                                 service_name = _("Providers")
862                                                         elif service.getPath().find("flags == %d" %(FLAG_SERVICE_NEW_FOUND)) != -1:
863                                                                 service_name = _("New")
864                                                         else:
865                                                                 service_name = _("Services")
866                                                         try:
867                                                                 service_name += str(' - %s'%(nimmanager.getSatDescription(orbpos)))
868                                                                 service.setName(service_name) # why we need this cast?
869                                                         except:
870                                                                 if orbpos == 0xFFFF: #Cable
871                                                                         n = ("%s (%s)") % (service_name, _("Cable"))
872                                                                 elif orbpos == 0xEEEE: #Terrestrial
873                                                                         n = ("%s (%s)") % (service_name, _("Terrestrial"))
874                                                                 else:
875                                                                         if orbpos > 1800: # west
876                                                                                 orbpos = 3600 - orbpos
877                                                                                 h = _("W")
878                                                                         else:
879                                                                                 h = _("E")
880                                                                         n = ("%s (%d.%d" + h + ")") % (service_name, orbpos / 10, orbpos % 10)
881                                                                 service.setName(n)
882                                                         self.servicelist.addService(service)
883                                                 self.servicelist.finishFill()
884                                                 if prev is not None:
885                                                         self.setCurrentSelection(prev)
886
887         def showProviders(self):
888                 if not self.pathChangeDisabled:
889                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
890                         if not self.preEnterPath(refstr):
891                                 ref = eServiceReference(refstr)
892                                 if self.isBasePathEqual(ref):
893                                         self.pathUp()
894                                 else:
895                                         currentRoot = self.getRoot()
896                                         if currentRoot is None or currentRoot != ref:
897                                                 self.clearPath()
898                                                 self.enterPath(ref)
899
900         def changeBouquet(self, direction):
901                 if not self.pathChangeDisabled:
902                         if len(self.servicePath) > 1:
903                                 #when enter satellite root list we must do some magic stuff..
904                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
905                                 if self.isBasePathEqual(ref):
906                                         self.showSatellites()
907                                 else:
908                                         self.pathUp()
909                                 if direction < 0:
910                                         self.moveUp()
911                                 else:
912                                         self.moveDown()
913                                 ref = self.getCurrentSelection()
914                                 self.enterPath(ref)
915
916         def inBouquet(self):
917                 return self.isBasePathEqual(self.bouquet_root)
918
919         def atBegin(self):
920                 return self.servicelist.atBegin()
921
922         def atEnd(self):
923                 return self.servicelist.atEnd()
924
925         def nextBouquet(self):
926                 self.changeBouquet(+1)
927
928         def prevBouquet(self):
929                 self.changeBouquet(-1)
930
931         def showFavourites(self):
932                 if not self.pathChangeDisabled:
933                         if not self.preEnterPath(self.bouquet_rootstr):
934                                 if self.isBasePathEqual(self.bouquet_root):
935                                         self.pathUp()
936                                 else:
937                                         currentRoot = self.getRoot()
938                                         if currentRoot is None or currentRoot != self.bouquet_root:
939                                                 self.clearPath()
940                                                 self.enterPath(self.bouquet_root)
941
942         def keyNumberGlobal(self, number):
943                 unichar = self.numericalTextInput.getKey(number)
944                 charstr = unichar.encode("utf-8")
945                 if len(charstr) == 1:
946                         self.servicelist.moveToChar(charstr[0])
947
948         def getRoot(self):
949                 return self.servicelist.getRoot()
950
951         def getCurrentSelection(self):
952                 return self.servicelist.getCurrent()
953
954         def setCurrentSelection(self, service):
955                 servicepath = service.getPath()
956                 pos = servicepath.find(" FROM BOUQUET")
957                 if pos != -1:
958                         if self.mode == MODE_TV:
959                                 servicepath = '(type == 1)' + servicepath[pos:]
960                         else:
961                                 servicepath = '(type == 2)' + servicepath[pos:]
962                         service.setPath(servicepath)
963                 self.servicelist.setCurrent(service)
964
965         def getBouquetList(self):
966                 bouquets = [ ]
967                 serviceHandler = eServiceCenter.getInstance()
968                 if config.usage.multibouquet.value:
969                         list = serviceHandler.list(self.bouquet_root)
970                         if list:
971                                 while True:
972                                         s = list.getNext()
973                                         if not s.valid():
974                                                 break
975                                         if s.flags & eServiceReference.isDirectory:
976                                                 info = serviceHandler.info(s)
977                                                 if info:
978                                                         bouquets.append((info.getName(s), s))
979                                 return bouquets
980                 else:
981                         info = serviceHandler.info(self.bouquet_root)
982                         if info:
983                                 bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
984                         return bouquets
985                 return None
986
987         def keyNumber0(self, num):
988                 if len(self.servicePath) > 1:
989                         self.keyGoUp()
990                 else:
991                         self.keyNumberGlobal(num)
992
993         def keyGoUp(self):
994                 if len(self.servicePath) > 1:
995                         if self.isBasePathEqual(self.bouquet_root):
996                                 self.showFavourites()
997                         else:
998                                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
999                                 if self.isBasePathEqual(ref):
1000                                         self.showSatellites()
1001                                 else:
1002                                         ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
1003                                         if self.isBasePathEqual(ref):
1004                                                 self.showProviders()
1005                                         else:
1006                                                 self.showAllServices()
1007
1008         def nextMarker(self):
1009                 self.servicelist.moveToNextMarker()
1010
1011         def prevMarker(self):
1012                 self.servicelist.moveToPrevMarker()
1013
1014 HISTORYSIZE = 20
1015
1016 #config for lastservice
1017 config.tv = ConfigSubsection()
1018 config.tv.lastservice = ConfigText()
1019 config.tv.lastroot = ConfigText()
1020 config.radio = ConfigSubsection()
1021 config.radio.lastservice = ConfigText()
1022 config.radio.lastroot = ConfigText()
1023 config.servicelist = ConfigSubsection()
1024 config.servicelist.lastmode = ConfigText(default = "tv")
1025
1026 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
1027         def __init__(self, session):
1028                 ChannelSelectionBase.__init__(self,session)
1029                 ChannelSelectionEdit.__init__(self)
1030                 ChannelSelectionEPG.__init__(self)
1031
1032                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1033                         {
1034                                 "cancel": self.cancel,
1035                                 "ok": self.channelSelected,
1036                                 "keyRadio": self.setModeRadio,
1037                                 "keyTV": self.setModeTv,
1038                         })
1039
1040                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1041                         {
1042                                 iPlayableService.evStart: self.__evServiceStart,
1043                                 iPlayableService.evEnd: self.__evServiceEnd
1044                         })
1045
1046                 self.lastChannelRootTimer = eTimer()
1047                 self.lastChannelRootTimer.timeout.get().append(self.__onCreate)
1048                 self.lastChannelRootTimer.start(100,True)
1049
1050                 self.history_tv = [ ]
1051                 self.history_radio = [ ]
1052                 self.history = self.history_tv
1053                 self.history_pos = 0
1054
1055                 self.lastservice = config.tv.lastservice
1056                 self.lastroot = config.tv.lastroot
1057                 self.revertMode = None
1058                 config.usage.multibouquet.addNotifier(self.multibouquet_config_changed)
1059
1060         def multibouquet_config_changed(self, val):
1061                 self.recallBouquetMode()
1062
1063         def __evServiceStart(self):
1064                 service = self.session.nav.getCurrentService()
1065                 if service:
1066                         info = service.info()
1067                         if info:
1068                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1069                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1070
1071         def __evServiceEnd(self):
1072                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1073
1074         def setMode(self):
1075                 self.restoreRoot()
1076                 lastservice=eServiceReference(self.lastservice.value)
1077                 if lastservice.valid():
1078                         self.setCurrentSelection(lastservice)
1079
1080         def setModeTv(self):
1081                 if self.revertMode is None and config.servicelist.lastmode.value == "radio":
1082                         self.revertMode = MODE_RADIO
1083                 self.history = self.history_tv
1084                 self.lastservice = config.tv.lastservice
1085                 self.lastroot = config.tv.lastroot
1086                 config.servicelist.lastmode.value = "tv"
1087                 self.setTvMode()
1088                 self.setMode()
1089
1090         def setModeRadio(self):
1091                 if self.revertMode is None and config.servicelist.lastmode.value == "tv":
1092                         self.revertMode = MODE_TV
1093                 if config.usage.e1like_radio_mode.value:
1094                         self.history = self.history_radio
1095                         self.lastservice = config.radio.lastservice
1096                         self.lastroot = config.radio.lastroot
1097                         config.servicelist.lastmode.value = "radio"
1098                         self.setRadioMode()
1099                         self.setMode()
1100
1101         def __onCreate(self):
1102                 if config.usage.e1like_radio_mode.value:
1103                         if config.servicelist.lastmode.value == "tv":
1104                                 self.setModeTv()
1105                         else:
1106                                 self.setModeRadio()
1107                 else:
1108                         self.setModeTv()
1109                 lastservice=eServiceReference(self.lastservice.value)
1110                 if lastservice.valid():
1111                         self.zap()
1112
1113         def channelSelected(self):
1114                 ref = self.getCurrentSelection()
1115                 if self.movemode:
1116                         self.toggleMoveMarked()
1117                 elif (ref.flags & 7) == 7:
1118                         self.enterPath(ref)
1119                 elif self.bouquet_mark_edit != OFF:
1120                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1121                                 self.doMark()
1122                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1123                         root = self.getRoot()
1124                         if not root or not (root.flags & eServiceReference.isGroup):
1125                                 self.zap()
1126                                 self.close(ref)
1127
1128         #called from infoBar and channelSelected
1129         def zap(self):
1130                 self.revertMode=None
1131                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
1132                 nref = self.getCurrentSelection()
1133                 if ref is None or ref != nref:
1134                         self.session.nav.playService(nref)
1135                         self.saveRoot()
1136                         self.saveChannel(nref)
1137                         config.servicelist.lastmode.save()
1138                         self.addToHistory(nref)
1139
1140         def addToHistory(self, ref):
1141                 if self.servicePath is not None:
1142                         tmp=self.servicePath[:]
1143                         tmp.append(ref)
1144                         try:
1145                                 del self.history[self.history_pos+1:]
1146                         except:
1147                                 pass
1148                         self.history.append(tmp)
1149                         hlen = len(self.history)
1150                         if hlen > HISTORYSIZE:
1151                                 del self.history[0]
1152                                 hlen -= 1
1153                         self.history_pos = hlen-1
1154
1155         def historyBack(self):
1156                 hlen = len(self.history)
1157                 if hlen > 1 and self.history_pos > 0:
1158                         self.history_pos -= 1
1159                         self.setHistoryPath()
1160
1161         def historyNext(self):
1162                 hlen = len(self.history)
1163                 if hlen > 1 and self.history_pos < (hlen-1):
1164                         self.history_pos += 1
1165                         self.setHistoryPath()
1166
1167         def setHistoryPath(self):
1168                 path = self.history[self.history_pos][:]
1169                 ref = path.pop()
1170                 del self.servicePath[:]
1171                 self.servicePath += path
1172                 self.saveRoot()
1173                 plen = len(path)
1174                 root = path[plen-1]
1175                 cur_root = self.getRoot()
1176                 if cur_root and cur_root != root:
1177                         self.setRoot(root)
1178                 self.session.nav.playService(ref)
1179                 self.setCurrentSelection(ref)
1180                 self.saveChannel(ref)
1181
1182         def saveRoot(self):
1183                 path = ''
1184                 for i in self.servicePath:
1185                         path += i.toString()
1186                         path += ';'
1187                 if len(path) and path != self.lastroot.value:
1188                         self.lastroot.value = path
1189                         self.lastroot.save()
1190
1191         def restoreRoot(self):
1192                 self.clearPath()
1193                 re = compile('.+?;')
1194                 tmp = re.findall(self.lastroot.value)
1195                 cnt = 0
1196                 for i in tmp:
1197                         self.servicePath.append(eServiceReference(i[:len(i)-1]))
1198                         cnt += 1
1199                 if cnt:
1200                         path = self.servicePath.pop()
1201                         self.enterPath(path)
1202                 else:
1203                         self.showFavourites()
1204                         self.saveRoot()
1205
1206         def preEnterPath(self, refstr):
1207                 if len(self.servicePath) and self.servicePath[0] != eServiceReference(refstr):
1208                         pathstr = self.lastroot.value
1209                         if pathstr is not None and pathstr.find(refstr) == 0:
1210                                 self.restoreRoot()
1211                                 lastservice=eServiceReference(self.lastservice.value)
1212                                 if lastservice.valid():
1213                                         self.setCurrentSelection(lastservice)
1214                                 return True
1215                 return False
1216
1217         def saveChannel(self, ref):
1218                 if ref is not None:
1219                         refstr = ref.toString()
1220                 else:
1221                         refstr = ""
1222                 if refstr != self.lastservice.value:
1223                         self.lastservice.value = refstr
1224                         self.lastservice.save()
1225
1226         def setCurrentServicePath(self, path):
1227                 hlen = len(self.history)
1228                 if hlen > 0:
1229                         self.history[self.history_pos] = path
1230                 else:
1231                         self.history.append(path)
1232                 self.setHistoryPath()
1233
1234         def getCurrentServicePath(self):
1235                 hlen = len(self.history)
1236                 if hlen > 0:
1237                         return self.history[self.history_pos]
1238                 return None
1239
1240         def recallPrevService(self):
1241                 hlen = len(self.history)
1242                 if hlen > 1:
1243                         if self.history_pos == hlen-1:
1244                                 tmp = self.history[self.history_pos]
1245                                 self.history[self.history_pos] = self.history[self.history_pos-1]
1246                                 self.history[self.history_pos-1] = tmp
1247                         else:
1248                                 tmp = self.history[self.history_pos+1]
1249                                 self.history[self.history_pos+1] = self.history[self.history_pos]
1250                                 self.history[self.history_pos] = tmp
1251                         self.setHistoryPath()
1252
1253         def cancel(self):
1254                 if self.revertMode is None:
1255                         self.restoreRoot()
1256                         lastservice=eServiceReference(self.lastservice.value)
1257                         if lastservice.valid() and self.getCurrentSelection() != lastservice:
1258                                 self.setCurrentSelection(lastservice)
1259                 elif self.revertMode == MODE_TV:
1260                         self.setModeTv()
1261                 elif self.revertMode == MODE_RADIO:
1262                         self.setModeRadio()
1263                 self.revertMode = None
1264                 self.close(None)
1265
1266 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord, InfoBarRadioText
1267
1268 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
1269         def __init__(self, session):
1270                 Screen.__init__(self, session)
1271                 InfoBarEvent.__init__(self)
1272                 InfoBarServiceName.__init__(self)
1273                 InfoBarInstantRecord.__init__(self)
1274                 self["CurrentTime"] = Clock()
1275
1276 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG, InfoBarRadioText):
1277
1278         ALLOW_SUSPEND = True
1279
1280         def __init__(self, session):
1281                 ChannelSelectionBase.__init__(self, session)
1282                 ChannelSelectionEdit.__init__(self)
1283                 ChannelSelectionEPG.__init__(self)
1284                 InfoBarRadioText.__init__(self)
1285
1286                 config.radio = ConfigSubsection();
1287                 config.radio.lastservice = ConfigText()
1288                 config.radio.lastroot = ConfigText()
1289                 self.onLayoutFinish.append(self.onCreate)
1290
1291                 self.info = session.instantiateDialog(RadioInfoBar)
1292
1293                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1294                         {
1295                                 "keyTV": self.closeRadio,
1296                                 "keyRadio": self.closeRadio,
1297                                 "cancel": self.closeRadio,
1298                                 "ok": self.channelSelected,
1299                         })
1300
1301                 self.__event_tracker = ServiceEventTracker(screen=self, eventmap=
1302                         {
1303                                 iPlayableService.evStart: self.__evServiceStart,
1304                                 iPlayableService.evEnd: self.__evServiceEnd
1305                         })
1306
1307         def __evServiceStart(self):
1308                 service = self.session.nav.getCurrentService()
1309                 if service:
1310                         info = service.info()
1311                         if info:
1312                                 refstr = info.getInfoString(iServiceInformation.sServiceref)
1313                                 self.servicelist.setPlayableIgnoreService(eServiceReference(refstr))
1314
1315         def __evServiceEnd(self):
1316                 self.servicelist.setPlayableIgnoreService(eServiceReference())
1317
1318         def saveRoot(self):
1319                 path = ''
1320                 for i in self.servicePathRadio:
1321                         path += i.toString()
1322                         path += ';'
1323                 if len(path) and path != config.radio.lastroot.value:
1324                         config.radio.lastroot.value = path
1325                         config.radio.lastroot.save()
1326
1327         def restoreRoot(self):
1328                 self.clearPath()
1329                 re = compile('.+?;')
1330                 tmp = re.findall(config.radio.lastroot.value)
1331                 cnt = 0
1332                 for i in tmp:
1333                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
1334                         cnt += 1
1335                 if cnt:
1336                         path = self.servicePathRadio.pop()
1337                         self.enterPath(path)
1338                 else:
1339                         self.showFavourites()
1340                         self.saveRoot()
1341
1342         def preEnterPath(self, refstr):
1343                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
1344                         pathstr = config.radio.lastroot.value
1345                         if pathstr is not None and pathstr.find(refstr) == 0:
1346                                 self.restoreRoot()
1347                                 lastservice=eServiceReference(config.radio.lastservice.value)
1348                                 if lastservice.valid():
1349                                         self.setCurrentSelection(lastservice)
1350                                 return True
1351                 return False
1352
1353         def onCreate(self):
1354                 self.setRadioMode()
1355                 self.restoreRoot()
1356                 lastservice=eServiceReference(config.radio.lastservice.value)
1357                 if lastservice.valid():
1358                         self.servicelist.setCurrent(lastservice)
1359                         self.session.nav.playService(lastservice)
1360                 self.info.show()
1361
1362         def channelSelected(self): # just return selected service
1363                 ref = self.getCurrentSelection()
1364                 if self.movemode:
1365                         self.toggleMoveMarked()
1366                 elif (ref.flags & 7) == 7:
1367                         self.enterPath(ref)
1368                 elif self.bouquet_mark_edit != OFF:
1369                         if not (self.bouquet_mark_edit == EDIT_ALTERNATIVES and ref.flags & eServiceReference.isGroup):
1370                                 self.doMark()
1371                 elif not (ref.flags & eServiceReference.isMarker): # no marker
1372                         cur_root = self.getRoot()
1373                         if not cur_root or not (cur_root.flags & eServiceReference.isGroup):
1374                                 playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1375                                 if playingref is None or playingref != ref:
1376                                         self.session.nav.playService(ref)
1377                                         config.radio.lastservice.value = ref.toString()
1378                                         config.radio.lastservice.save()
1379                                 self.saveRoot()
1380
1381         def closeRadio(self):
1382                 self.info.hide()
1383                 #set previous tv service
1384                 lastservice=eServiceReference(config.tv.lastservice.value)
1385                 self.session.nav.playService(lastservice)
1386                 self.close(None)
1387
1388 class SimpleChannelSelection(ChannelSelectionBase):
1389         def __init__(self, session, title):
1390                 ChannelSelectionBase.__init__(self, session)
1391                 self.title = title
1392                 self.onShown.append(self.__onExecCallback)
1393
1394                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1395                         {
1396                                 "cancel": self.close,
1397                                 "ok": self.channelSelected,
1398                                 "keyRadio": self.setModeRadio,
1399                                 "keyTV": self.setModeTv,
1400                         })
1401
1402         def __onExecCallback(self):
1403                 self.setTitle(self.title)
1404                 self.setModeTv()
1405
1406         def channelSelected(self): # just return selected service
1407                 ref = self.getCurrentSelection()
1408                 if (ref.flags & 7) == 7:
1409                         self.enterPath(ref)
1410                 elif not (ref.flags & eServiceReference.isMarker):
1411                         ref = self.getCurrentSelection()
1412                         self.close(ref)
1413
1414         def setModeTv(self):
1415                 self.setTvMode()
1416                 self.showFavourites()
1417
1418         def setModeRadio(self):
1419                 self.setRadioMode()
1420                 self.showFavourites()