minimally improved LCD support
[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.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.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.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.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.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.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.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                                                                         orbpos = 3600 - orbpos
648                                                                         h = _("W")
649                                                                 else:
650                                                                         h = _("E")
651                                                                 n = ("%s (%d.%d" + h + ")") % (service_name, orbpos / 10, orbpos % 10)
652                                                                 service.setName(n)
653                                                         self.servicelist.addService(service)
654                                                         self.servicelist.finishFill()
655                                                         if prev is not None:
656                                                                 self.setCurrentSelection(prev)
657
658         def showProviders(self):
659                 if not self.pathChangedDisabled:
660                         refstr = '%s FROM PROVIDERS ORDER BY name'%(self.service_types)
661                         if not self.preEnterPath(refstr):
662                                 ref = eServiceReference(refstr)
663                                 if self.isBasePathEqual(ref):
664                                         self.pathUp()
665                                 else:
666                                         currentRoot = self.getRoot()
667                                         if currentRoot is None or currentRoot != ref:
668                                                 self.clearPath()
669                                                 self.enterPath(ref)
670
671         def changeBouquet(self, direction):
672                 if not self.pathChangedDisabled:
673                         if self.isBasePathEqual(self.bouquet_root):
674                                 self.pathUp()
675                                 if direction < 0:
676                                         self.moveUp()
677                                 else:
678                                         self.moveDown()
679                                 ref = self.getCurrentSelection()
680                                 self.enterPath(ref)
681
682         def inBouquet(self):
683                 return self.isBasePathEqual(self.bouquet_root)
684
685         def atBegin(self):
686                 return self.servicelist.atBegin()
687
688         def atEnd(self):
689                 return self.servicelist.atEnd()
690
691         def nextBouquet(self):
692                 self.changeBouquet(+1)
693
694         def prevBouquet(self):
695                 self.changeBouquet(-1)
696
697         def showFavourites(self):
698                 if not self.pathChangedDisabled:
699                         if not self.preEnterPath(self.bouquet_rootstr):
700                                 if self.isBasePathEqual(self.bouquet_root):
701                                         self.pathUp()
702                                 else:
703                                         currentRoot = self.getRoot()
704                                         if currentRoot is None or currentRoot != self.bouquet_root:
705                                                 self.clearPath()
706                                                 self.enterPath(self.bouquet_root)
707
708         def keyNumberGlobal(self, number):
709                 char = self.numericalTextInput.getKey(number)
710                 self.servicelist.moveToChar(char)
711
712         def getRoot(self):
713                 return self.servicelist.getRoot()
714
715         def getCurrentSelection(self):
716                 return self.servicelist.getCurrent()
717
718         def setCurrentSelection(self, service):
719                 servicepath = service.getPath()
720                 pos = servicepath.find(" FROM BOUQUET")
721                 if pos != -1:
722                         if self.mode == MODE_TV:
723                                 servicepath = '(type == 1)' + servicepath[pos:]
724                         else:
725                                 servicepath = '(type == 2)' + servicepath[pos:]
726                         service.setPath(servicepath)
727                 self.servicelist.setCurrent(service)
728
729         def getBouquetList(self):
730                 serviceCount=0
731                 bouquets = [ ]
732                 serviceHandler = eServiceCenter.getInstance()
733                 list = serviceHandler.list(self.bouquet_root)
734                 if not list is None:
735                         while True:
736                                 s = list.getNext()
737                                 if not s.valid():
738                                         break
739                                 if ((s.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory):
740                                         info = serviceHandler.info(s)
741                                         if not info is None:
742                                                 bouquets.append((info.getName(s), s))
743                                 else:
744                                         serviceCount += 1
745                         if len(bouquets) == 0 and serviceCount > 0:
746                                 info = serviceHandler.info(self.bouquet_root)
747                                 if not info is None:
748                                         bouquets.append((info.getName(self.bouquet_root), self.bouquet_root))
749                         return bouquets
750                 return None
751
752 HISTORYSIZE = 20
753
754 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
755         def __init__(self, session):
756                 ChannelSelectionBase.__init__(self,session)
757                 ChannelSelectionEdit.__init__(self)
758                 ChannelSelectionEPG.__init__(self)
759
760                 #config for lastservice
761                 config.tv = ConfigSubsection();
762                 config.tv.lastservice = configElement("config.tv.lastservice", configText, "", 0);
763                 config.tv.lastroot = configElement("config.tv.lastroot", configText, "", 0);
764                 config.tv.prevservice = configElement("config.tv.prevservice", configText, "", 0);
765                 config.tv.prevroot = configElement("config.tv.prevroot", configText, "", 0);
766
767                 self["actions"] = ActionMap(["OkCancelActions"],
768                         {
769                                 "cancel": self.cancel,
770                                 "ok": self.channelSelected,
771                         })
772                 self.onShown.append(self.__onShown)
773
774                 self.lastChannelRootTimer = eTimer()
775                 self.lastChannelRootTimer.timeout.get().append(self.__onCreate)
776                 self.lastChannelRootTimer.start(100,True)
777
778                 self.history = [ ]
779                 self.history_pos = 0
780
781         def __onCreate(self):
782                 self.setTvMode()
783                 self.restoreRoot()
784                 lastservice=eServiceReference(config.tv.lastservice.value)
785                 if lastservice.valid():
786                         self.setCurrentSelection(lastservice)
787                         self.zap()
788
789         def __onShown(self):
790                 self.recallBouquetMode()
791                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
792                 if ref is not None and ref.valid() and ref.getPath() == "":
793                         self.servicelist.setPlayableIgnoreService(ref)
794                 else:
795                         self.servicelist.setPlayableIgnoreService(eServiceReference())
796
797         def channelSelected(self):
798                 ref = self.getCurrentSelection()
799                 if self.movemode:
800                         self.toggleMoveMarked()
801                 elif (ref.flags & 7) == 7:
802                         self.enterPath(ref)
803                 elif self.bouquet_mark_edit:
804                         self.doMark()
805                 else:
806                         self.zap()
807                         self.close(ref)
808
809         #called from infoBar and channelSelected
810         def zap(self):
811                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
812                 nref = self.getCurrentSelection()
813                 if ref is None or ref != nref:
814                         self.session.nav.playService(nref)
815                 self.saveRoot()
816                 self.saveChannel()
817                 tmp=self.servicePath[:]
818                 tmp.append(nref)
819                 try:
820                         del self.history[self.history_pos+1:]
821                 except:
822                         pass
823                 self.history.append(tmp)
824                 hlen = len(self.history)
825                 if hlen > HISTORYSIZE:
826                         del self.history[0]
827                         hlen -= 1
828                 self.history_pos = hlen-1
829
830         def historyBack(self):
831                 hlen = len(self.history)
832                 if hlen > 1 and self.history_pos > 0:
833                         self.history_pos -= 1
834                         self.setHistoryPath()
835
836         def historyNext(self):
837                 hlen = len(self.history)
838                 if hlen > 1 and self.history_pos < (hlen-1):
839                         self.history_pos += 1
840                         self.setHistoryPath()
841
842         def setHistoryPath(self):
843                 path = self.history[self.history_pos][:]
844                 ref = path.pop()
845                 self.servicePath = path
846                 self.saveRoot()
847                 plen = len(path)
848                 root = path[plen-1]
849                 if self.getRoot() != root:
850                         self.setRoot(root)
851                 self.session.nav.playService(ref)
852                 self.setCurrentSelection(ref)
853                 self.saveChannel()
854
855         def saveRoot(self):
856                 path = ''
857                 for i in self.servicePathTV:
858                         path += i.toString()
859                         path += ';'
860                 if config.tv.prevroot.value != config.tv.lastroot.value:
861                         config.tv.prevroot.value = config.tv.lastroot.value
862                         config.tv.prevroot.save()
863                 if len(path) and path != config.tv.lastroot.value:
864                         config.tv.lastroot.value = path
865                         config.tv.lastroot.save()
866
867         def restoreRoot(self):
868                 self.clearPath()
869                 re = compile('.+?;')
870                 tmp = re.findall(config.tv.lastroot.value)
871                 cnt = 0
872                 for i in tmp:
873                         self.servicePathTV.append(eServiceReference(i[:len(i)-1]))
874                         cnt += 1
875                 if cnt:
876                         path = self.servicePathTV.pop()
877                         self.enterPath(path)
878                 else:
879                         self.showFavourites()
880                         self.saveRoot()
881
882         def preEnterPath(self, refstr):
883                 if len(self.servicePathTV) and self.servicePathTV[0] != eServiceReference(refstr):
884                         pathstr = config.tv.lastroot.value
885                         if pathstr is not None and pathstr.find(refstr) == 0:
886                                 self.restoreRoot()
887                                 lastservice=eServiceReference(config.tv.lastservice.value)
888                                 if lastservice.valid():
889                                         self.setCurrentSelection(lastservice)
890                                 return True
891                 return False
892
893         def saveChannel(self):
894                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
895                 if ref is not None:
896                         refstr = ref.toString()
897                 else:
898                         refstr = ""
899                 if refstr != config.tv.lastservice.value:
900                         config.tv.prevservice.value = config.tv.lastservice.value
901                         config.tv.prevservice.save()
902                         config.tv.lastservice.value = refstr
903                         config.tv.lastservice.save()
904
905         def recallPrevService(self):
906                 if len(config.tv.prevservice.value) and len(config.tv.prevroot.value):
907                         if config.tv.lastroot.value != config.tv.prevroot.value:
908                                 tmp = config.tv.lastroot.value
909                                 config.tv.lastroot.value = config.tv.prevroot.value
910                                 config.tv.lastroot.save()
911                                 config.tv.prevroot.value = tmp
912                                 config.tv.prevroot.save()
913                                 self.restoreRoot()
914                         if config.tv.lastservice.value != config.tv.prevservice.value:
915                                 tmp = config.tv.lastservice.value
916                                 config.tv.lastservice.value = config.tv.prevservice.value
917                                 config.tv.lastservice.save()
918                                 config.tv.prevservice.value = tmp
919                                 config.tv.prevservice.save()
920                                 lastservice=eServiceReference(config.tv.lastservice.value)
921                                 self.session.nav.playService(lastservice)
922                                 self.setCurrentSelection(lastservice)
923
924         def cancel(self):
925                 self.close(None)
926                 self.restoreRoot()
927                 lastservice=eServiceReference(config.tv.lastservice.value)
928                 if lastservice.valid() and self.getCurrentSelection() != lastservice:
929                         self.setCurrentSelection(lastservice)
930
931 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord
932
933 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
934         def __init__(self, session):
935                 Screen.__init__(self, session)
936                 InfoBarEvent.__init__(self)
937                 InfoBarServiceName.__init__(self)
938                 InfoBarInstantRecord.__init__(self)
939                 self["Clock"] = Clock()
940
941 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
942         def __init__(self, session):
943                 ChannelSelectionBase.__init__(self, session)
944                 ChannelSelectionEdit.__init__(self)
945                 ChannelSelectionEPG.__init__(self)
946
947                 config.radio = ConfigSubsection();
948                 config.radio.lastservice = configElement("config.radio.lastservice", configText, "", 0);
949                 config.radio.lastroot = configElement("config.radio.lastroot", configText, "", 0);
950                 self.onLayoutFinish.append(self.onCreate)
951
952                 self.info = session.instantiateDialog(RadioInfoBar)
953
954                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
955                         {
956                                 "keyTV": self.closeRadio,
957                                 "keyRadio": self.closeRadio,
958                                 "cancel": self.closeRadio,
959                                 "ok": self.channelSelected,
960                         })
961
962         def saveRoot(self):
963                 path = ''
964                 for i in self.servicePathRadio:
965                         path += i.toString()
966                         path += ';'
967                 if len(path) and path != config.radio.lastroot.value:
968                         config.radio.lastroot.value = path
969                         config.radio.lastroot.save()
970
971         def restoreRoot(self):
972                 self.clearPath()
973                 re = compile('.+?;')
974                 tmp = re.findall(config.radio.lastroot.value)
975                 cnt = 0
976                 for i in tmp:
977                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
978                         cnt += 1
979                 if cnt:
980                         path = self.servicePathRadio.pop()
981                         self.enterPath(path)
982                 else:
983                         self.showFavourites()
984                         self.saveRoot()
985
986         def preEnterPath(self, refstr):
987                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
988                         pathstr = config.radio.lastroot.value
989                         if pathstr is not None and pathstr.find(refstr) == 0:
990                                 self.restoreRoot()
991                                 lastservice=eServiceReference(config.radio.lastservice.value)
992                                 if lastservice.valid():
993                                         self.setCurrentSelection(lastservice)
994                                 return True
995                 return False
996
997         def onCreate(self):
998                 self.setRadioMode()
999                 self.restoreRoot()
1000                 lastservice=eServiceReference(config.radio.lastservice.value)
1001                 if lastservice.valid():
1002                         self.servicelist.setCurrent(lastservice)
1003                         self.session.nav.playService(lastservice)
1004                         self.servicelist.setPlayableIgnoreService(lastservice)
1005                 self.info.show()
1006
1007         def channelSelected(self): # just return selected service
1008                 ref = self.getCurrentSelection()
1009                 if self.movemode:
1010                         self.toggleMoveMarked()
1011                 elif (ref.flags & 7) == 7:
1012                         self.enterPath(ref)
1013                 elif self.bouquet_mark_edit:
1014                         self.doMark()
1015                 else:
1016                         playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1017                         if playingref is None or playingref != ref:
1018                                 self.session.nav.playService(ref)
1019                                 self.servicelist.setPlayableIgnoreService(ref)
1020                                 config.radio.lastservice.value = ref.toString()
1021                                 config.radio.lastservice.save()
1022                         self.saveRoot()
1023
1024         def closeRadio(self):
1025                 self.info.hide()
1026                 #set previous tv service
1027                 lastservice=eServiceReference(config.tv.lastservice.value)
1028                 self.session.nav.playService(lastservice)
1029                 self.close(None)
1030
1031 class SimpleChannelSelection(ChannelSelectionBase):
1032         def __init__(self, session, title):
1033                 ChannelSelectionBase.__init__(self, session)
1034                 self.title = title
1035                 self.onShown.append(self.__onExecCallback)
1036
1037                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1038                         {
1039                                 "cancel": self.close,
1040                                 "ok": self.channelSelected,
1041                                 "keyRadio": self.setModeRadio,
1042                                 "keyTV": self.setModeTv,
1043                         })
1044
1045         def __onExecCallback(self):
1046                 self.setTitle(self.title)
1047                 self.setModeTv()
1048
1049         def channelSelected(self): # just return selected service
1050                 ref = self.getCurrentSelection()
1051                 if (ref.flags & 7) == 7:
1052                         self.enterPath(ref)
1053                 else:
1054                         ref = self.getCurrentSelection()
1055                         self.close(ref)
1056
1057         def setModeTv(self):
1058                 self.setTvMode()
1059                 self.showFavourites()
1060
1061         def setModeRadio(self):
1062                 self.setRadioMode()
1063                 self.showFavourites()