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