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