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