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