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