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