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