history fix
[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                         hlen -= 1
825                 self.history_pos = hlen-1
826
827         def historyBack(self):
828                 hlen = len(self.history)
829                 if hlen > 1 and self.history_pos > 0:
830                         self.history_pos -= 1
831                         self.setHistoryPath()
832
833         def historyNext(self):
834                 hlen = len(self.history)
835                 if hlen > 1 and self.history_pos < (hlen-1):
836                         self.history_pos += 1
837                         self.setHistoryPath()
838
839         def setHistoryPath(self):
840                 path = self.history[self.history_pos][:]
841                 ref = path.pop()
842                 self.servicePath = path
843                 self.saveRoot()
844                 plen = len(path)
845                 root = path[plen-1]
846                 if self.getRoot() != root:
847                         self.setRoot(root)
848                 self.session.nav.playService(ref)
849                 self.setCurrentSelection(ref)
850                 self.saveChannel()
851
852         def saveRoot(self):
853                 path = ''
854                 for i in self.servicePathTV:
855                         path += i.toString()
856                         path += ';'
857                 if config.tv.prevroot.value != config.tv.lastroot.value:
858                         config.tv.prevroot.value = config.tv.lastroot.value
859                         config.tv.prevroot.save()
860                 if len(path) and path != config.tv.lastroot.value:
861                         config.tv.lastroot.value = path
862                         config.tv.lastroot.save()
863
864         def restoreRoot(self):
865                 self.clearPath()
866                 re = compile('.+?;')
867                 tmp = re.findall(config.tv.lastroot.value)
868                 cnt = 0
869                 for i in tmp:
870                         self.servicePathTV.append(eServiceReference(i[:len(i)-1]))
871                         cnt += 1
872                 if cnt:
873                         path = self.servicePathTV.pop()
874                         self.enterPath(path)
875                 else:
876                         self.showFavourites()
877                         self.saveRoot()
878
879         def preEnterPath(self, refstr):
880                 if len(self.servicePathTV) and self.servicePathTV[0] != eServiceReference(refstr):
881                         pathstr = config.tv.lastroot.value
882                         if pathstr is not None and pathstr.find(refstr) == 0:
883                                 self.restoreRoot()
884                                 lastservice=eServiceReference(config.tv.lastservice.value)
885                                 if lastservice is not None:
886                                         self.setCurrentSelection(lastservice)
887                                 return True
888                 return False
889
890         def saveChannel(self):
891                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
892                 if ref is not None:
893                         refstr = ref.toString()
894                 else:
895                         refstr = ""
896                 if refstr != config.tv.lastservice.value:
897                         config.tv.prevservice.value = config.tv.lastservice.value
898                         config.tv.prevservice.save()
899                         config.tv.lastservice.value = refstr
900                         config.tv.lastservice.save()
901
902         def recallPrevService(self):
903                 if len(config.tv.prevservice.value) and len(config.tv.prevroot.value):
904                         if config.tv.lastroot.value != config.tv.prevroot.value:
905                                 tmp = config.tv.lastroot.value
906                                 config.tv.lastroot.value = config.tv.prevroot.value
907                                 config.tv.lastroot.save()
908                                 config.tv.prevroot.value = tmp
909                                 config.tv.prevroot.save()
910                                 self.restoreRoot()
911                         if config.tv.lastservice.value != config.tv.prevservice.value:
912                                 tmp = config.tv.lastservice.value
913                                 config.tv.lastservice.value = config.tv.prevservice.value
914                                 config.tv.lastservice.save()
915                                 config.tv.prevservice.value = tmp
916                                 config.tv.prevservice.save()
917                                 lastservice=eServiceReference(config.tv.lastservice.value)
918                                 self.session.nav.playService(lastservice)
919                                 self.setCurrentSelection(lastservice)
920
921         def cancel(self):
922                 self.close(None)
923                 self.restoreRoot()
924                 lastservice=eServiceReference(config.tv.lastservice.value)
925                 if lastservice.valid() and self.getCurrentSelection() != lastservice:
926                         self.setCurrentSelection(lastservice)
927
928 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord
929
930 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
931         def __init__(self, session):
932                 Screen.__init__(self, session)
933                 InfoBarEvent.__init__(self)
934                 InfoBarServiceName.__init__(self)
935                 InfoBarInstantRecord.__init__(self)
936                 self["Clock"] = Clock()
937
938 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
939         def __init__(self, session):
940                 ChannelSelectionBase.__init__(self, session)
941                 ChannelSelectionEdit.__init__(self)
942                 ChannelSelectionEPG.__init__(self)
943
944                 config.radio = ConfigSubsection();
945                 config.radio.lastservice = configElement("config.radio.lastservice", configText, "", 0);
946                 config.radio.lastroot = configElement("config.radio.lastroot", configText, "", 0);
947                 self.onLayoutFinish.append(self.onCreate)
948
949                 self.info = session.instantiateDialog(RadioInfoBar)
950
951                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
952                         {
953                                 "keyTV": self.closeRadio,
954                                 "keyRadio": self.closeRadio,
955                                 "cancel": self.closeRadio,
956                                 "ok": self.channelSelected,
957                         })
958
959         def saveRoot(self):
960                 path = ''
961                 for i in self.servicePathRadio:
962                         path += i.toString()
963                         path += ';'
964                 if len(path) and path != config.radio.lastroot.value:
965                         config.radio.lastroot.value = path
966                         config.radio.lastroot.save()
967
968         def restoreRoot(self):
969                 self.clearPath()
970                 re = compile('.+?;')
971                 tmp = re.findall(config.radio.lastroot.value)
972                 cnt = 0
973                 for i in tmp:
974                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
975                         cnt += 1
976                 if cnt:
977                         path = self.servicePathRadio.pop()
978                         self.enterPath(path)
979                 else:
980                         self.showFavourites()
981                         self.saveRoot()
982
983         def preEnterPath(self, refstr):
984                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
985                         pathstr = config.radio.lastroot.value
986                         if pathstr is not None and pathstr.find(refstr) == 0:
987                                 self.restoreRoot()
988                                 lastservice=eServiceReference(config.radio.lastservice.value)
989                                 if lastservice is not None:
990                                         self.setCurrentSelection(lastservice)
991                                 return True
992                 return False
993
994         def onCreate(self):
995                 self.setRadioMode()
996                 self.restoreRoot()
997                 lastservice=eServiceReference(config.radio.lastservice.value)
998                 if lastservice.valid():
999                         self.servicelist.setCurrent(lastservice)
1000                         self.session.nav.playService(lastservice)
1001                         self.servicelist.setPlayableIgnoreService(lastservice)
1002                 self.info.show()
1003
1004         def channelSelected(self): # just return selected service
1005                 ref = self.getCurrentSelection()
1006                 if self.movemode:
1007                         self.toggleMoveMarked()
1008                 elif (ref.flags & 7) == 7:
1009                         self.enterPath(ref)
1010                 elif self.bouquet_mark_edit:
1011                         self.doMark()
1012                 else:
1013                         playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1014                         if playingref is None or playingref != ref:
1015                                 self.session.nav.playService(ref)
1016                                 self.servicelist.setPlayableIgnoreService(ref)
1017                                 config.radio.lastservice.value = ref.toString()
1018                                 config.radio.lastservice.save()
1019                         self.saveRoot()
1020
1021         def closeRadio(self):
1022                 self.info.hide()
1023                 #set previous tv service
1024                 lastservice=eServiceReference(config.tv.lastservice.value)
1025                 self.session.nav.playService(lastservice)
1026                 self.close(None)
1027
1028 class SimpleChannelSelection(ChannelSelectionBase):
1029         def __init__(self, session, title):
1030                 ChannelSelectionBase.__init__(self, session)
1031                 self.title = title
1032                 self.onShown.append(self.__onExecCallback)
1033
1034                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1035                         {
1036                                 "cancel": self.close,
1037                                 "ok": self.channelSelected,
1038                                 "keyRadio": self.setModeRadio,
1039                                 "keyTV": self.setModeTv,
1040                         })
1041
1042         def __onExecCallback(self):
1043                 self.session.currentDialog.instance.setTitle(self.title)
1044                 self.setModeTv()
1045
1046         def channelSelected(self): # just return selected service
1047                 ref = self.getCurrentSelection()
1048                 if (ref.flags & 7) == 7:
1049                         self.enterPath(ref)
1050                 else:
1051                         ref = self.getCurrentSelection()
1052                         self.close(ref)
1053
1054         def setModeTv(self):
1055                 self.setTvMode()
1056                 self.showFavourites()
1057
1058         def setModeRadio(self):
1059                 self.setRadioMode()
1060                 self.showFavourites()