add zapping history.. useable with < > buttons
[enigma2.git] / lib / python / Screens / ChannelSelection.py
1 from Screen import Screen
2 from Components.Button import Button
3 from Components.ServiceList import ServiceList
4 from Components.ActionMap import NumberActionMap, ActionMap
5 from Components.MenuList import MenuList
6 from EpgSelection import EPGSelection
7 from enigma import eServiceReference, eEPGCache, eEPGCachePtr, eServiceCenter, eServiceCenterPtr, iMutableServiceListPtr, iStaticServiceInformationPtr, eTimer, eDVBDB
8 from Components.config import config, configElement, ConfigSubsection, configText, currentConfigSelectionElement
9 from Screens.FixedMenu import FixedMenu
10 from Tools.NumericalTextInput import NumericalTextInput
11 from Components.NimManager import nimmanager
12 from Components.ServiceName import ServiceName
13 from Components.Clock import Clock
14 from Components.EventInfo import EventInfo
15 from ServiceReference import ServiceReference
16 from re import *
17 from os import remove
18
19 import xml.dom.minidom
20
21 class BouquetSelector(Screen):
22         def __init__(self, session, bouquets, selectedFunc):
23                 Screen.__init__(self, session)
24
25                 self.selectedFunc=selectedFunc
26
27                 self["actions"] = ActionMap(["OkCancelActions"],
28                         {
29                                 "ok": self.okbuttonClick,
30                                 "cancel": self.cancelClick
31                         })
32                 entrys = [ ]
33                 for x in bouquets:
34                         entrys.append((x[0], x[1]))
35                 self["menu"] = MenuList(entrys)
36
37         def okbuttonClick(self):
38                 self.selectedFunc(self["menu"].getCurrent()[1])
39
40         def cancelClick(self):
41                 self.close(False)
42
43 class ChannelContextMenu(Screen):
44         def __init__(self, session, csel):
45                 Screen.__init__(self, session)
46                 self.csel = csel
47
48                 self["actions"] = ActionMap(["OkCancelActions"],
49                         {
50                                 "ok": self.okbuttonClick,
51                                 "cancel": self.cancelClick
52                         })
53                 menu = [ ]
54
55                 inBouquetRootList = csel.getRoot().getPath().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
56                 inBouquet = csel.getMutableList() is not None
57                 haveBouquets = csel.bouquet_root.getPath().find('FROM BOUQUET "bouquets.') != -1
58
59                 if not csel.bouquet_mark_edit and not csel.movemode:
60                         if not inBouquetRootList:
61                                 if (csel.getCurrentSelection().flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
62                                         if haveBouquets:
63                                                 menu.append((_("add service to bouquet"), self.addServiceToBouquetSelected))
64                                         else:
65                                                 menu.append((_("add service to favourites"), self.addServiceToBouquetSelected))
66                                 elif haveBouquets:
67                                         if not inBouquet and csel.getCurrentSelection().getPath().find("PROVIDERS") == -1:
68                                                 menu.append((_("copy to favourites"), csel.copyCurrentToBouquetList))
69                                 if inBouquet:
70                                         menu.append((_("remove service"), self.removeCurrentService))
71                         elif haveBouquets:
72                                 menu.append((_("remove bouquet"), csel.removeBouquet))
73
74                 if inBouquet: # current list is editable?
75                         if not csel.bouquet_mark_edit:
76                                 if not csel.movemode:
77                                         menu.append((_("enable move mode"), self.toggleMoveMode))
78                                         if not inBouquetRootList:
79                                                 if haveBouquets:
80                                                         menu.append((_("enable bouquet edit"), self.bouquetMarkStart))
81                                                 else:
82                                                         menu.append((_("enable favourite edit"), self.bouquetMarkStart))
83                                 else:
84                                         menu.append((_("disable move mode"), self.toggleMoveMode))
85                         elif not inBouquetRootList:
86                                 if haveBouquets:
87                                         menu.append((_("end bouquet edit"), self.bouquetMarkEnd))
88                                         menu.append((_("abort bouquet edit"), self.bouquetMarkAbort))
89                                 else:
90                                         menu.append((_("end favourites edit"), self.bouquetMarkEnd))
91                                         menu.append((_("abort favourites edit"), self.bouquetMarkAbort))
92
93                 menu.append((_("back"), self.cancelClick))
94                 self["menu"] = MenuList(menu)
95
96         def okbuttonClick(self):
97                 self["menu"].getCurrent()[1]()
98
99         def cancelClick(self):
100                 self.close(False)
101
102         def addServiceToBouquetSelected(self):
103                 bouquets = self.csel.getBouquetList()
104                 if bouquets is None:
105                         cnt = 0
106                 else:
107                         cnt = len(bouquets)
108                 if cnt > 1: # show bouquet list
109                         self.session.openWithCallback(self.bouquetSelClosed, BouquetSelector, bouquets, self.addCurrentServiceToBouquet)
110                 elif cnt == 1: # add to only one existing bouquet
111                         self.addCurrentServiceToBouquet(bouquets[0][1])
112                 else: #no bouquets in root.. so assume only one favourite list is used
113                         self.addCurrentServiceToBouquet(self.csel.bouquet_root)
114
115         def bouquetSelClosed(self, recursive):
116                 if recursive:
117                         self.close(False)
118
119         def copyCurrentToBouquetList(self):
120                 self.csel.copyCurrentToBouquetList()
121                 self.close()
122
123         def removeBouquet(self):
124                 self.csel.removeBouquet()
125                 self.close()
126
127         def addCurrentServiceToBouquet(self, dest):
128                 self.csel.addCurrentServiceToBouquet(dest)
129                 self.close(True) # close bouquet selection
130
131         def removeCurrentService(self):
132                 self.csel.removeCurrentService()
133                 self.close()
134
135         def toggleMoveMode(self):
136                 self.csel.toggleMoveMode()
137                 self.close()
138
139         def bouquetMarkStart(self):
140                 self.csel.startMarkedEdit()
141                 self.close()
142
143         def bouquetMarkEnd(self):
144                 self.csel.endMarkedEdit(abort=False)
145                 self.close()
146
147         def bouquetMarkAbort(self):
148                 self.csel.endMarkedEdit(abort=True)
149                 self.close()
150
151 class ChannelSelectionEPG:
152         def __init__(self):
153                 self["ChannelSelectEPGActions"] = ActionMap(["ChannelSelectEPGActions"],
154                         {
155                                 "showEPGList": self.showEPGList,
156                         })
157
158         def showEPGList(self):
159                 ref=self.getCurrentSelection()
160                 ptr=eEPGCache.getInstance()
161                 if ptr.startTimeQuery(ref) != -1:
162                         self.session.open(EPGSelection, ref)
163                 else:
164                         print 'no epg for service', ref.toString()
165
166 class ChannelSelectionEdit:
167         def __init__(self):
168                 self.entry_marked = False
169                 self.movemode = False
170                 self.bouquet_mark_edit = False
171                 self.mutableList = None
172                 self.__marked = [ ]
173                 self.saved_title = None
174                 self.saved_root = None
175
176                 class ChannelSelectionEditActionMap(ActionMap):
177                         def __init__(self, csel, contexts = [ ], actions = { }, prio=0):
178                                 ActionMap.__init__(self, contexts, actions, prio)
179                                 self.csel = csel
180                         def action(self, contexts, action):
181                                 if action == "cancel":
182                                         self.csel.handleEditCancel()
183                                 elif action == "ok":
184                                         pass # avoid typo warning...
185                                 else:
186                                         ActionMap.action(self, contexts, action)
187                 self["ChannelSelectEditActions"] = ChannelSelectionEditActionMap(self, ["ChannelSelectEditActions", "OkCancelActions"],
188                         {
189                                 "contextMenu": self.doContext,
190                         })
191
192         def getMutableList(self, root=eServiceReference()):
193                 if not self.mutableList is None:
194                         return self.mutableList
195                 serviceHandler = eServiceCenter.getInstance()
196                 if not root.valid():
197                         root=self.getRoot()
198                 list = serviceHandler.list(root)
199                 if list is not None:
200                         return list.startEdit()
201                 return None
202
203         def buildBouquetID(self, str):
204                 tmp = str.lower()
205                 name = ''
206                 for c in tmp:
207                         if (c >= 'a' and c <= 'z') or (c >= '0' and c <= '9'):
208                                 name += c
209                         else:
210                                 name += '_'
211                 return name
212
213         def copyCurrentToBouquetList(self):
214                 provider = ServiceReference(self.getCurrentSelection())
215                 serviceHandler = eServiceCenter.getInstance()
216                 mutableBouquetList = serviceHandler.list(self.bouquet_root).startEdit()
217                 if mutableBouquetList:
218                         providerName = provider.getServiceName()
219                         if self.mode == MODE_TV:
220                                 str = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET \"userbouquet.%s.tv\" ORDER BY bouquet'%(self.buildBouquetID(providerName))
221                         else:
222                                 str = '1:7:2:0:0:0:0:0:0:0:(type == 2) FROM BOUQUET \"userbouquet.%s.radio\" ORDER BY bouquet'%(self.buildBouquetID(providerName))
223                         new_bouquet_ref = eServiceReference(str)
224                         if not mutableBouquetList.addService(new_bouquet_ref):
225                                 self.bouquetNumOffsetCache = { }
226                                 mutableBouquetList.flushChanges()
227                                 eDVBDB.getInstance().reloadBouquets()
228                                 mutableBouquet = serviceHandler.list(new_bouquet_ref).startEdit()
229                                 if mutableBouquet:
230                                         mutableBouquet.setListName(providerName)
231                                         list = [ ]
232                                         services = serviceHandler.list(provider.ref)
233                                         if not services is None:
234                                                 if not services.getContent(list, True):
235                                                         for service in list:
236                                                                 if mutableBouquet.addService(service):
237                                                                         print "add", service.toString(), "to new bouquet failed"
238                                                         mutableBouquet.flushChanges()
239                                                 else:
240                                                         print "getContent failed"
241                                         else:
242                                                 print "list provider", providerName, "failed"
243                                 else:
244                                         print "get mutable list for new created bouquet failed"
245                         else:
246                                 print "add", str, "to bouquets failed"
247                 else:
248                         print "bouquetlist is not editable"
249
250         def removeBouquet(self):
251                 refstr = self.getCurrentSelection().toString()
252                 self.bouquetNumOffsetCache = { }
253                 pos = refstr.find('FROM BOUQUET "')
254                 if pos != -1:
255                         refstr = refstr[pos+14:]
256                         pos = refstr.find('"')
257                         if pos != -1:
258                                 filename = '/etc/enigma2/' + refstr[:pos] # FIXMEEE !!! HARDCODED /etc/enigma2
259                 self.removeCurrentService()
260                 remove(filename)
261                 eDVBDB.getInstance().reloadBouquets()
262
263 #  multiple marked entry stuff ( edit mode, later multiepg selection )
264         def startMarkedEdit(self):
265                 self.mutableList = self.getMutableList()
266                 # add all services from the current list to internal marked set in listboxservicecontent
267                 self.clearMarks() # this clears the internal marked set in the listboxservicecontent
268                 self.saved_title = self.instance.getTitle()
269                 pos = self.saved_title.find(')')
270                 new_title = self.saved_title[:pos+1]
271                 if self.bouquet_root.getPath().find('FROM BOUQUET "bouquets.') != -1:
272                         new_title += ' ' + _("[bouquet edit]")
273                 else:
274                         new_title += ' ' + _("[favourite edit]")
275                 self.instance.setTitle(new_title)
276                 self.bouquet_mark_edit = True
277                 self.__marked = self.servicelist.getRootServices()
278                 for x in self.__marked:
279                         self.servicelist.addMarked(eServiceReference(x))
280                 self.savedPath = self.servicePath[:]
281                 self.showAllServices()
282
283         def endMarkedEdit(self, abort):
284                 if not abort and self.mutableList is not None:
285                         self.bouquetNumOffsetCache = { }
286                         new_marked = set(self.servicelist.getMarked())
287                         old_marked = set(self.__marked)
288                         removed = old_marked - new_marked
289                         added = new_marked - old_marked
290                         changed = False
291                         for x in removed:
292                                 changed = True
293                                 self.mutableList.removeService(eServiceReference(x))
294                         for x in added:
295                                 changed = True
296                                 self.mutableList.addService(eServiceReference(x))
297                         if changed:
298                                 self.mutableList.flushChanges()
299                 self.__marked = []
300                 self.clearMarks()
301                 self.bouquet_mark_edit = False
302                 self.mutableList = None
303                 self.instance.setTitle(self.saved_title)
304                 self.saved_title = None
305                 self.servicePath = self.savedPath[:]
306                 del self.savedPath
307                 self.setRoot(self.servicePath[len(self.servicePath)-1])
308
309         def clearMarks(self):
310                 self.servicelist.clearMarks()
311
312         def doMark(self):
313                 ref = self.servicelist.getCurrent()
314                 if self.servicelist.isMarked(ref):
315                         self.servicelist.removeMarked(ref)
316                 else:
317                         self.servicelist.addMarked(ref)
318
319         def removeCurrentService(self):
320                 ref = self.servicelist.getCurrent()
321                 mutableList = self.getMutableList()
322                 if ref.valid() and mutableList is not None:
323                         if not mutableList.removeService(ref):
324                                 self.bouquetNumOffsetCache = { }
325                                 currentIndex = self.servicelist.getCurrentIndex()
326                                 self.servicelist.moveDown()
327                                 if self.servicelist.getCurrentIndex() == currentIndex:
328                                         currentIndex -= 1
329                                 mutableList.flushChanges() #FIXME dont flush on each single removed service
330                                 self.setRoot(self.getRoot())
331                                 self.servicelist.moveToIndex(currentIndex)
332
333         def addCurrentServiceToBouquet(self, dest):
334                 mutableList = self.getMutableList(dest)
335                 if not mutableList is None:
336                         if not mutableList.addService(self.servicelist.getCurrent()):
337                                 self.bouquetNumOffsetCache = { }
338                                 mutableList.flushChanges()
339                 self.close()
340
341         def toggleMoveMode(self):
342                 if self.movemode:
343                         if self.entry_marked:
344                                 self.toggleMoveMarked() # unmark current entry
345                         self.movemode = False
346                         self.pathChangedDisabled = False # re-enable path change
347                         self.mutableList.flushChanges() # FIXME add check if changes was made
348                         self.mutableList = None
349                         self.instance.setTitle(self.saved_title)
350                         self.saved_title = None
351                         if self.getRoot() == self.bouquet_root:
352                                 self.bouquetNumOffsetCache = { }
353                 else:
354                         self.mutableList = self.getMutableList()
355                         self.movemode = True
356                         self.pathChangedDisabled = True # no path change allowed in movemode
357                         self.saved_title = self.instance.getTitle()
358                         new_title = self.saved_title
359                         pos = self.saved_title.find(')')
360                         new_title = self.saved_title[:pos+1] + ' ' + _("[move mode]") + self.saved_title[pos+1:]
361                         self.instance.setTitle(new_title);
362
363         def handleEditCancel(self):
364                 if self.movemode: #movemode active?
365                         self.channelSelected() # unmark
366                         self.toggleMoveMode() # disable move mode
367                 elif self.bouquet_mark_edit:
368                         self.endMarkedEdit(True) # abort edit mode
369
370         def toggleMoveMarked(self):
371                 if self.entry_marked:
372                         self.servicelist.setCurrentMarked(False)
373                         self.entry_marked = False
374                 else:
375                         self.servicelist.setCurrentMarked(True)
376                         self.entry_marked = True
377
378         def doContext(self):
379                 self.session.open(ChannelContextMenu, self)
380
381 MODE_TV = 0
382 MODE_RADIO = 1
383
384 class ChannelSelectionBase(Screen):
385         def __init__(self, session):
386                 Screen.__init__(self, session)
387
388                 # this makes it much simple to implement a selectable radio or tv mode :)
389                 self.service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17)'
390                 self.service_types_radio = '1:7:2:0:0:0:0:0:0:0:(type == 2)'
391
392                 self["key_red"] = Button(_("All"))
393                 self["key_green"] = Button(_("Satellites"))
394                 self["key_yellow"] = Button(_("Provider"))
395                 self["key_blue"] = Button(_("Favourites"))
396
397                 self["list"] = ServiceList()
398                 self.servicelist = self["list"]
399
400                 self.numericalTextInput = NumericalTextInput()
401
402                 self.servicePathTV = [ ]
403                 self.servicePathRadio = [ ]
404                 self.servicePath = None
405
406                 self.pathChangedDisabled = False
407
408                 self.bouquetNumOffsetCache = { }
409
410                 self["ChannelSelectBaseActions"] = NumberActionMap(["ChannelSelectBaseActions", "NumberActions"],
411                         {
412                                 "showFavourites": self.showFavourites,
413                                 "showAllServices": self.showAllServices,
414                                 "showProviders": self.showProviders,
415                                 "showSatellites": self.showSatellites,
416                                 "nextBouquet": self.nextBouquet,
417                                 "prevBouquet": self.prevBouquet,
418                                 "1": self.keyNumberGlobal,
419                                 "2": self.keyNumberGlobal,
420                                 "3": self.keyNumberGlobal,
421                                 "4": self.keyNumberGlobal,
422                                 "5": self.keyNumberGlobal,
423                                 "6": self.keyNumberGlobal,
424                                 "7": self.keyNumberGlobal,
425                                 "8": self.keyNumberGlobal,
426                                 "9": self.keyNumberGlobal,
427                                 "0": self.keyNumberGlobal
428                         })
429
430         def appendDVBTypes(self, ref):
431                 path = ref.getPath()
432                 pos = path.find(' FROM BOUQUET')
433                 if pos != -1:
434                         return eServiceReference(self.service_types + path[pos:])
435                 return ref
436
437         def getBouquetNumOffset(self, bouquet):
438                 if self.bouquet_root.getPath().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
439                         return 0
440                 bouquet = self.appendDVBTypes(bouquet)
441                 try:
442                         return self.bouquetNumOffsetCache[bouquet.toString()]
443                 except:
444                         offsetCount = 0
445                         serviceHandler = eServiceCenter.getInstance()
446                         bouquetlist = serviceHandler.list(self.bouquet_root)
447                         if not bouquetlist is None:
448                                 while True:
449                                         bouquetIterator = self.appendDVBTypes(bouquetlist.getNext())
450                                         if not bouquetIterator.valid(): #end of list
451                                                 break
452                                         self.bouquetNumOffsetCache[bouquetIterator.toString()]=offsetCount
453                                         if ((bouquetIterator.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
454                                                 continue
455                                         servicelist = serviceHandler.list(bouquetIterator)
456                                         if not servicelist is None:
457                                                 while True:
458                                                         serviceIterator = servicelist.getNext()
459                                                         if not serviceIterator.valid(): #check if end of list
460                                                                 break
461                                                         if serviceIterator.flags: #playable services have no flags
462                                                                 continue
463                                                         offsetCount += 1
464                 return self.bouquetNumOffsetCache.get(bouquet.toString(), offsetCount)
465
466         def recallBouquetMode(self):
467                 if self.mode == MODE_TV:
468                         self.service_types = self.service_types_tv
469                         if currentConfigSelectionElement(config.usage.multibouquet) == "yes":
470                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet'
471                         else:
472                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types)
473                 else:
474                         self.service_types = self.service_types_radio
475                         if currentConfigSelectionElement(config.usage.multibouquet) == "yes":
476                                 self.bouquet_rootstr = '1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.radio" ORDER BY bouquet'
477                         else:
478                                 self.bouquet_rootstr = '%s FROM BOUQUET "userbouquet.favourites.radio" ORDER BY bouquet'%(self.service_types)
479                 self.bouquet_root = eServiceReference(self.bouquet_rootstr)
480
481         def setTvMode(self):
482                 self.mode = MODE_TV
483                 self.servicePath = self.servicePathTV
484                 self.recallBouquetMode()
485                 title = self.instance.getTitle()
486                 pos = title.find(" (")
487                 if pos != -1:
488                         title = title[:pos]
489                 title += " (TV)"
490                 self.instance.setTitle(title)
491
492         def setRadioMode(self):
493                 self.mode = MODE_RADIO
494                 self.servicePath = self.servicePathRadio
495                 self.recallBouquetMode()
496                 title = self.instance.getTitle()
497                 pos = title.find(" (")
498                 if pos != -1:
499                         title = title[:pos]
500                 title += " (Radio)"
501                 self.instance.setTitle(title)
502
503         def setRoot(self, root, justSet=False):
504                 path = root.getPath()
505                 inBouquetRootList = path.find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
506                 pos = path.find(' FROM BOUQUET')
507                 isBouquet = pos != -1
508                 if not inBouquetRootList and isBouquet:
509                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
510                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
511                         refstr = self.service_types + path[pos:]
512                         root = eServiceReference(refstr)
513                 else:
514                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
515                 self.servicelist.setRoot(root, justSet)
516                 self.buildTitleString()
517
518         def removeModeStr(self, str):
519                 if self.mode == MODE_TV:
520                         pos = str.find(' (TV)')
521                 else:
522                         pos = str.find(' (Radio)')
523                 if pos != -1:
524                         return str[:pos]
525                 return str
526
527         def getServiceName(self, ref):
528                 str = self.removeModeStr(ServiceReference(ref).getServiceName())
529                 if not len(str):
530                         pathstr = ref.getPath()
531                         if pathstr.find('FROM PROVIDERS') != -1:
532                                 return _("Provider")
533                         if pathstr.find('FROM SATELLITES') != -1:
534                                 return _("Satellites")
535                         if pathstr.find(') ORDER BY name') != -1:
536                                 return _("All")
537                 return str
538
539         def buildTitleString(self):
540                 titleStr = self.instance.getTitle()
541                 pos = titleStr.find(']')
542                 if pos == -1:
543                         pos = titleStr.find(')')
544                 if pos != -1:
545                         titleStr = titleStr[:pos+1]
546                         Len = len(self.servicePath)
547                         if Len > 0:
548                                 base_ref = self.servicePath[0]
549                                 if Len > 1:
550                                         end_ref = self.servicePath[Len-1]
551                                 else:
552                                         end_ref = None
553                                 nameStr = self.getServiceName(base_ref)
554                                 titleStr += ' ' + nameStr
555                                 if end_ref is not None:
556                                         if Len > 2:
557                                                 titleStr += '/../'
558                                         else:
559                                                 titleStr += '/'
560                                         nameStr = self.getServiceName(end_ref)
561                                         titleStr += nameStr
562                                 self.instance.setTitle(titleStr)
563
564         def moveUp(self):
565                 self.servicelist.moveUp()
566
567         def moveDown(self):
568                 self.servicelist.moveDown()
569
570         def clearPath(self):
571                 del self.servicePath[:]
572
573         def enterPath(self, ref, justSet=False):
574                 self.servicePath.append(ref)
575                 self.setRoot(ref, justSet)
576
577         def pathUp(self, justSet=False):
578                 prev = self.servicePath.pop()
579                 length = len(self.servicePath)
580                 if length:
581                         current = self.servicePath[length-1]
582                 self.setRoot(current, justSet)
583                 if not justSet:
584                         self.setCurrentSelection(prev)
585                 return prev
586
587         def isBasePathEqual(self, ref):
588                 if len(self.servicePath) > 1 and self.servicePath[0] == ref:
589                         return True
590                 return False
591
592         def isPrevPathEqual(self, ref):
593                 length = len(self.servicePath)
594                 if length > 1 and self.servicePath[length-2] == ref:
595                         return True
596                 return False
597
598         def preEnterPath(self, refstr):
599                 return False
600
601         def showAllServices(self):
602                 if not self.pathChangedDisabled:
603                         refstr = '%s ORDER BY name'%(self.service_types)
604                         if not self.preEnterPath(refstr):
605                                 ref = eServiceReference(refstr)
606                                 currentRoot = self.getRoot()
607                                 if currentRoot is None or currentRoot != ref:
608                                         self.clearPath()
609                                         self.enterPath(ref)
610
611         def showSatellites(self):
612                 if not self.pathChangedDisabled:
613                         refstr = '%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types)
614                         if not self.preEnterPath(refstr):
615                                 ref = eServiceReference(refstr)
616                                 justSet=False
617                                 prev = None
618
619                                 if self.isBasePathEqual(ref):
620                                         if self.isPrevPathEqual(ref):
621                                                 justSet=True
622                                         prev = self.pathUp(justSet)
623                                 else:
624                                         currentRoot = self.getRoot()
625                                         if currentRoot is None or currentRoot != ref:
626                                                 justSet=True
627                                                 self.clearPath()
628                                                 self.enterPath(ref, True)
629                                 if justSet:
630                                         serviceHandler = eServiceCenter.getInstance()
631                                         servicelist = serviceHandler.list(ref)
632                                         if not servicelist is None:
633                                                 while True:
634                                                         service = servicelist.getNext()
635                                                         if not service.valid(): #check if end of list
636                                                                 break
637                                                         orbpos = service.getData(4) >> 16
638                                                         if service.getPath().find("FROM PROVIDER") != -1:
639                                                                 service_name = _("Providers")
640                                                         else:
641                                                                 service_name = _("Services")
642                                                         try:
643                                                                 service_name += str(' - %s'%(nimmanager.getSatDescription(orbpos)))
644                                                                 service.setName(service_name) # why we need this cast?
645                                                         except:
646                                                                 if orbpos > 1800: # west
647                                                                         service.setName("%s (%3.1f" + _("W") + ")" %(str, (0 - (orbpos - 3600)) / 10.0))
648                                                                 else:
649                                                                         service.setName("%s (%3.1f" + _("E") + ")" % (str, orbpos / 10.0))
650                                                         self.servicelist.addService(service)
651                                                         self.servicelist.finishFill()
652                                                         if prev is not None:
653                                                                 self.setCurrentSelection(prev)
654
655         def showProviders(self):
656                 if not self.pathChangedDisabled:
657                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
658                         if not self.preEnterPath(refstr):
659                                 ref = eServiceReference(refstr)
660                                 if self.isBasePathEqual(ref):
661                                         self.pathUp()
662                                 else:
663                                         currentRoot = self.getRoot()
664                                         if currentRoot is None or currentRoot != ref:
665                                                 self.clearPath()
666                                                 self.enterPath(ref)
667
668         def changeBouquet(self, direction):
669                 if not self.pathChangedDisabled:
670                         if self.isBasePathEqual(self.bouquet_root):
671                                 self.pathUp()
672                                 if direction < 0:
673                                         self.moveUp()
674                                 else:
675                                         self.moveDown()
676                                 ref = self.getCurrentSelection()
677                                 self.enterPath(ref)
678
679         def inBouquet(self):
680                 return self.isBasePathEqual(self.bouquet_root)
681
682         def atBegin(self):
683                 return self.servicelist.atBegin()
684
685         def atEnd(self):
686                 return self.servicelist.atEnd()
687
688         def nextBouquet(self):
689                 self.changeBouquet(+1)
690
691         def prevBouquet(self):
692                 self.changeBouquet(-1)
693
694         def showFavourites(self):
695                 if not self.pathChangedDisabled:
696                         if not self.preEnterPath(self.bouquet_rootstr):
697                                 if self.isBasePathEqual(self.bouquet_root):
698                                         self.pathUp()
699                                 else:
700                                         currentRoot = self.getRoot()
701                                         if currentRoot is None or currentRoot != self.bouquet_root:
702                                                 self.clearPath()
703                                                 self.enterPath(self.bouquet_root)
704
705         def keyNumberGlobal(self, number):
706                 char = self.numericalTextInput.getKey(number)
707                 self.servicelist.moveToChar(char)
708
709         def getRoot(self):
710                 return self.servicelist.getRoot()
711
712         def getCurrentSelection(self):
713                 return self.servicelist.getCurrent()
714
715         def setCurrentSelection(self, service):
716                 servicepath = service.getPath()
717                 pos = servicepath.find(" FROM BOUQUET")
718                 if pos != -1:
719                         if self.mode == MODE_TV:
720                                 servicepath = '(type == 1)' + servicepath[pos:]
721                         else:
722                                 servicepath = '(type == 2)' + servicepath[pos:]
723                         service.setPath(servicepath)
724                 self.servicelist.setCurrent(service)
725
726         def getBouquetList(self):
727                 serviceCount=0
728                 bouquets = [ ]
729                 serviceHandler = eServiceCenter.getInstance()
730                 list = serviceHandler.list(self.bouquet_root)
731                 if not list is None:
732                         while True:
733                                 s = list.getNext()
734                                 if not s.valid():
735                                         break
736                                 if ((s.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory):
737                                         info = serviceHandler.info(s)
738                                         if not info is None:
739                                                 bouquets.append((info.getName(s), s))
740                                 else:
741                                         serviceCount += 1
742                         if len(bouquets) == 0 and serviceCount > 0:
743                                 info = serviceHandler.info(self.bouquet_root)
744                                 if not info is None:
745                                         bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
746                         return bouquets
747                 return None
748
749 HISTORYSIZE = 20
750
751 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
752         def __init__(self, session):
753                 ChannelSelectionBase.__init__(self,session)
754                 ChannelSelectionEdit.__init__(self)
755                 ChannelSelectionEPG.__init__(self)
756
757                 #config for lastservice
758                 config.tv = ConfigSubsection();
759                 config.tv.lastservice = configElement("config.tv.lastservice", configText, "", 0);
760                 config.tv.lastroot = configElement("config.tv.lastroot", configText, "", 0);
761                 config.tv.prevservice = configElement("config.tv.prevservice", configText, "", 0);
762                 config.tv.prevroot = configElement("config.tv.prevroot", configText, "", 0);
763
764                 self["actions"] = ActionMap(["OkCancelActions"],
765                         {
766                                 "cancel": self.cancel,
767                                 "ok": self.channelSelected,
768                         })
769                 self.onShown.append(self.__onShown)
770
771                 self.lastChannelRootTimer = eTimer()
772                 self.lastChannelRootTimer.timeout.get().append(self.__onCreate)
773                 self.lastChannelRootTimer.start(100,True)
774
775                 self.history = [ ]
776                 self.history_pos = 0
777
778         def __onCreate(self):
779                 self.setTvMode()
780                 self.restoreRoot()
781                 lastservice=eServiceReference(config.tv.lastservice.value)
782                 if lastservice.valid():
783                         self.setCurrentSelection(lastservice)
784                         self.zap()
785
786         def __onShown(self):
787                 self.recallBouquetMode()
788                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
789                 if ref is not None and ref.valid() and ref.getPath() == "":
790                         self.servicelist.setPlayableIgnoreService(ref)
791                 else:
792                         self.servicelist.setPlayableIgnoreService(eServiceReference())
793
794         def channelSelected(self):
795                 ref = self.getCurrentSelection()
796                 if self.movemode:
797                         self.toggleMoveMarked()
798                 elif (ref.flags & 7) == 7:
799                         self.enterPath(ref)
800                 elif self.bouquet_mark_edit:
801                         self.doMark()
802                 else:
803                         self.zap()
804                         self.close(ref)
805
806         #called from infoBar and channelSelected
807         def zap(self):
808                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
809                 nref = self.getCurrentSelection()
810                 if ref is None or ref != nref:
811                         self.session.nav.playService(nref)
812                 self.saveRoot()
813                 self.saveChannel()
814                 tmp=self.servicePath[:]
815                 tmp.append(nref)
816                 try:
817                         del self.history[self.history_pos+1:]
818                 except:
819                         pass
820                 self.history.append(tmp)
821                 hlen = len(self.history)
822                 if hlen > HISTORYSIZE:
823                         del self.history[0]
824                 self.history_pos = hlen-1
825
826         def historyBack(self):
827                 hlen = len(self.history)
828                 if hlen > 1 and self.history_pos > 0:
829                         self.history_pos -= 1
830                         self.setHistoryPath()
831
832         def historyNext(self):
833                 hlen = len(self.history)
834                 if hlen > 1 and self.history_pos < (hlen-1):
835                         self.history_pos += 1
836                         self.setHistoryPath()
837
838         def setHistoryPath(self):
839                 path = self.history[self.history_pos][:]
840                 ref = path.pop()
841                 self.servicePath = path
842                 self.saveRoot()
843                 plen = len(path)
844                 root = path[plen-1]
845                 if self.getRoot() != root:
846                         self.setRoot(root)
847                 self.session.nav.playService(ref)
848                 self.setCurrentSelection(ref)
849                 self.saveChannel()
850
851         def saveRoot(self):
852                 path = ''
853                 for i in self.servicePathTV:
854                         path += i.toString()
855                         path += ';'
856                 if config.tv.prevroot.value != config.tv.lastroot.value:
857                         config.tv.prevroot.value = config.tv.lastroot.value
858                         config.tv.prevroot.save()
859                 if len(path) and path != config.tv.lastroot.value:
860                         config.tv.lastroot.value = path
861                         config.tv.lastroot.save()
862
863         def restoreRoot(self):
864                 self.clearPath()
865                 re = compile('.+?;')
866                 tmp = re.findall(config.tv.lastroot.value)
867                 cnt = 0
868                 for i in tmp:
869                         self.servicePathTV.append(eServiceReference(i[:len(i)-1]))
870                         cnt += 1
871                 if cnt:
872                         path = self.servicePathTV.pop()
873                         self.enterPath(path)
874                 else:
875                         self.showFavourites()
876                         self.saveRoot()
877
878         def preEnterPath(self, refstr):
879                 if len(self.servicePathTV) and self.servicePathTV[0] != eServiceReference(refstr):
880                         pathstr = config.tv.lastroot.value
881                         if pathstr is not None and pathstr.find(refstr) == 0:
882                                 self.restoreRoot()
883                                 lastservice=eServiceReference(config.tv.lastservice.value)
884                                 if lastservice is not None:
885                                         self.setCurrentSelection(lastservice)
886                                 return True
887                 return False
888
889         def saveChannel(self):
890                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
891                 if ref is not None:
892                         refstr = ref.toString()
893                 else:
894                         refstr = ""
895                 if refstr != config.tv.lastservice.value:
896                         config.tv.prevservice.value = config.tv.lastservice.value
897                         config.tv.prevservice.save()
898                         config.tv.lastservice.value = refstr
899                         config.tv.lastservice.save()
900
901         def recallPrevService(self):
902                 if len(config.tv.prevservice.value) and len(config.tv.prevroot.value):
903                         if config.tv.lastroot.value != config.tv.prevroot.value:
904                                 tmp = config.tv.lastroot.value
905                                 config.tv.lastroot.value = config.tv.prevroot.value
906                                 config.tv.lastroot.save()
907                                 config.tv.prevroot.value = tmp
908                                 config.tv.prevroot.save()
909                                 self.restoreRoot()
910                         if config.tv.lastservice.value != config.tv.prevservice.value:
911                                 tmp = config.tv.lastservice.value
912                                 config.tv.lastservice.value = config.tv.prevservice.value
913                                 config.tv.lastservice.save()
914                                 config.tv.prevservice.value = tmp
915                                 config.tv.prevservice.save()
916                                 lastservice=eServiceReference(config.tv.lastservice.value)
917                                 self.session.nav.playService(lastservice)
918                                 self.setCurrentSelection(lastservice)
919
920         def cancel(self):
921                 self.close(None)
922                 self.restoreRoot()
923                 lastservice=eServiceReference(config.tv.lastservice.value)
924                 if lastservice.valid() and self.getCurrentSelection() != lastservice:
925                         self.setCurrentSelection(lastservice)
926
927 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord
928
929 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
930         def __init__(self, session):
931                 Screen.__init__(self, session)
932                 InfoBarEvent.__init__(self)
933                 InfoBarServiceName.__init__(self)
934                 InfoBarInstantRecord.__init__(self)
935                 self["Clock"] = Clock()
936
937 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
938         def __init__(self, session):
939                 ChannelSelectionBase.__init__(self, session)
940                 ChannelSelectionEdit.__init__(self)
941                 ChannelSelectionEPG.__init__(self)
942
943                 config.radio = ConfigSubsection();
944                 config.radio.lastservice = configElement("config.radio.lastservice", configText, "", 0);
945                 config.radio.lastroot = configElement("config.radio.lastroot", configText, "", 0);
946                 self.onLayoutFinish.append(self.onCreate)
947
948                 self.info = session.instantiateDialog(RadioInfoBar)
949
950                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
951                         {
952                                 "keyTV": self.closeRadio,
953                                 "keyRadio": self.closeRadio,
954                                 "cancel": self.closeRadio,
955                                 "ok": self.channelSelected,
956                         })
957
958         def saveRoot(self):
959                 path = ''
960                 for i in self.servicePathRadio:
961                         path += i.toString()
962                         path += ';'
963                 if len(path) and path != config.radio.lastroot.value:
964                         config.radio.lastroot.value = path
965                         config.radio.lastroot.save()
966
967         def restoreRoot(self):
968                 self.clearPath()
969                 re = compile('.+?;')
970                 tmp = re.findall(config.radio.lastroot.value)
971                 cnt = 0
972                 for i in tmp:
973                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
974                         cnt += 1
975                 if cnt:
976                         path = self.servicePathRadio.pop()
977                         self.enterPath(path)
978                 else:
979                         self.showFavourites()
980                         self.saveRoot()
981
982         def preEnterPath(self, refstr):
983                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
984                         pathstr = config.radio.lastroot.value
985                         if pathstr is not None and pathstr.find(refstr) == 0:
986                                 self.restoreRoot()
987                                 lastservice=eServiceReference(config.radio.lastservice.value)
988                                 if lastservice is not None:
989                                         self.setCurrentSelection(lastservice)
990                                 return True
991                 return False
992
993         def onCreate(self):
994                 self.setRadioMode()
995                 self.restoreRoot()
996                 lastservice=eServiceReference(config.radio.lastservice.value)
997                 if lastservice.valid():
998                         self.servicelist.setCurrent(lastservice)
999                         self.session.nav.playService(lastservice)
1000                         self.servicelist.setPlayableIgnoreService(lastservice)
1001                 self.info.show()
1002
1003         def channelSelected(self): # just return selected service
1004                 ref = self.getCurrentSelection()
1005                 if self.movemode:
1006                         self.toggleMoveMarked()
1007                 elif (ref.flags & 7) == 7:
1008                         self.enterPath(ref)
1009                 elif self.bouquet_mark_edit:
1010                         self.doMark()
1011                 else:
1012                         playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1013                         if playingref is None or playingref != ref:
1014                                 self.session.nav.playService(ref)
1015                                 self.servicelist.setPlayableIgnoreService(ref)
1016                                 config.radio.lastservice.value = ref.toString()
1017                                 config.radio.lastservice.save()
1018                         self.saveRoot()
1019
1020         def closeRadio(self):
1021                 self.info.hide()
1022                 #set previous tv service
1023                 lastservice=eServiceReference(config.tv.lastservice.value)
1024                 self.session.nav.playService(lastservice)
1025                 self.close(None)
1026
1027 class SimpleChannelSelection(ChannelSelectionBase):
1028         def __init__(self, session, title):
1029                 ChannelSelectionBase.__init__(self, session)
1030                 self.title = title
1031                 self.onShown.append(self.__onExecCallback)
1032
1033                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1034                         {
1035                                 "cancel": self.close,
1036                                 "ok": self.channelSelected,
1037                                 "keyRadio": self.setModeRadio,
1038                                 "keyTV": self.setModeTv,
1039                         })
1040
1041         def __onExecCallback(self):
1042                 self.session.currentDialog.instance.setTitle(self.title)
1043                 self.setModeTv()
1044
1045         def channelSelected(self): # just return selected service
1046                 ref = self.getCurrentSelection()
1047                 if (ref.flags & 7) == 7:
1048                         self.enterPath(ref)
1049                 else:
1050                         ref = self.getCurrentSelection()
1051                         self.close(ref)
1052
1053         def setModeTv(self):
1054                 self.setTvMode()
1055                 self.showFavourites()
1056
1057         def setModeRadio(self):
1058                 self.setRadioMode()
1059                 self.showFavourites()