implement subservice quickzap on < > keys
[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, 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)'
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 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
840         def __init__(self, session):
841                 ChannelSelectionBase.__init__(self,session)
842                 ChannelSelectionEdit.__init__(self)
843                 ChannelSelectionEPG.__init__(self)
844
845                 #config for lastservice
846                 config.tv = ConfigSubsection();
847                 config.tv.lastservice = configElement("config.tv.lastservice", configText, "", 0);
848                 config.tv.lastroot = configElement("config.tv.lastroot", configText, "", 0);
849
850                 self["actions"] = ActionMap(["OkCancelActions"],
851                         {
852                                 "cancel": self.cancel,
853                                 "ok": self.channelSelected,
854                         })
855                 self.onShown.append(self.__onShown)
856
857                 self.lastChannelRootTimer = eTimer()
858                 self.lastChannelRootTimer.timeout.get().append(self.__onCreate)
859                 self.lastChannelRootTimer.start(100,True)
860
861                 self.history = [ ]
862                 self.history_pos = 0
863
864         def __onCreate(self):
865                 self.setTvMode()
866                 self.restoreRoot()
867                 lastservice=eServiceReference(config.tv.lastservice.value)
868                 if lastservice.valid():
869                         self.setCurrentSelection(lastservice)
870                         self.zap()
871
872         def __onShown(self):
873                 self.recallBouquetMode()
874                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
875                 if ref is not None and ref.valid() and ref.getPath() == "":
876                         self.servicelist.setPlayableIgnoreService(ref)
877                 else:
878                         self.servicelist.setPlayableIgnoreService(eServiceReference())
879
880         def channelSelected(self):
881                 ref = self.getCurrentSelection()
882                 if self.movemode:
883                         self.toggleMoveMarked()
884                 elif (ref.flags & 7) == 7:
885                         self.enterPath(ref)
886                 elif self.bouquet_mark_edit:
887                         self.doMark()
888                 else:
889                         self.zap()
890                         self.close(ref)
891
892         #called from infoBar and channelSelected
893         def zap(self):
894                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
895                 nref = self.getCurrentSelection()
896                 if ref is None or ref != nref:
897                         self.session.nav.playService(nref)
898                 self.saveRoot()
899                 self.saveChannel()
900                 if self.servicePath is not None:
901                         tmp=self.servicePath[:]
902                         tmp.append(nref)
903                         try:
904                                 del self.history[self.history_pos+1:]
905                         except:
906                                 pass
907                         self.history.append(tmp)
908                         hlen = len(self.history)
909                         if hlen > HISTORYSIZE:
910                                 del self.history[0]
911                                 hlen -= 1
912                         self.history_pos = hlen-1
913
914         def historyBack(self):
915                 hlen = len(self.history)
916                 if hlen > 1 and self.history_pos > 0:
917                         self.history_pos -= 1
918                         self.setHistoryPath()
919
920         def historyNext(self):
921                 hlen = len(self.history)
922                 if hlen > 1 and self.history_pos < (hlen-1):
923                         self.history_pos += 1
924                         self.setHistoryPath()
925
926         def setHistoryPath(self):
927                 path = self.history[self.history_pos][:]
928                 ref = path.pop()
929                 del self.servicePath[:]
930                 self.servicePath += path
931                 self.saveRoot()
932                 plen = len(path)
933                 root = path[plen-1]
934                 if self.getRoot() != root:
935                         self.setRoot(root)
936                 self.session.nav.playService(ref)
937                 self.setCurrentSelection(ref)
938                 self.saveChannel()
939
940         def saveRoot(self):
941                 path = ''
942                 for i in self.servicePathTV:
943                         path += i.toString()
944                         path += ';'
945                 if len(path) and path != config.tv.lastroot.value:
946                         config.tv.lastroot.value = path
947                         config.tv.lastroot.save()
948
949         def restoreRoot(self):
950                 self.clearPath()
951                 re = compile('.+?;')
952                 tmp = re.findall(config.tv.lastroot.value)
953                 cnt = 0
954                 for i in tmp:
955                         self.servicePathTV.append(eServiceReference(i[:len(i)-1]))
956                         cnt += 1
957                 if cnt:
958                         path = self.servicePathTV.pop()
959                         self.enterPath(path)
960                 else:
961                         self.showFavourites()
962                         self.saveRoot()
963
964         def preEnterPath(self, refstr):
965                 if len(self.servicePathTV) and self.servicePathTV[0] != eServiceReference(refstr):
966                         pathstr = config.tv.lastroot.value
967                         if pathstr is not None and pathstr.find(refstr) == 0:
968                                 self.restoreRoot()
969                                 lastservice=eServiceReference(config.tv.lastservice.value)
970                                 if lastservice.valid():
971                                         self.setCurrentSelection(lastservice)
972                                 return True
973                 return False
974
975         def saveChannel(self):
976                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
977                 if ref is not None:
978                         refstr = ref.toString()
979                 else:
980                         refstr = ""
981                 if refstr != config.tv.lastservice.value:
982                         config.tv.lastservice.value = refstr
983                         config.tv.lastservice.save()
984
985         def recallPrevService(self):
986                 hlen = len(self.history)
987                 if hlen > 1:
988                         if self.history_pos == hlen-1:
989                                 tmp = self.history[self.history_pos]
990                                 self.history[self.history_pos] = self.history[self.history_pos-1]
991                                 self.history[self.history_pos-1] = tmp
992                         else:
993                                 tmp = self.history[self.history_pos+1]
994                                 self.history[self.history_pos+1] = self.history[self.history_pos]
995                                 self.history[self.history_pos] = tmp
996                         self.setHistoryPath()
997
998         def cancel(self):
999                 self.close(None)
1000                 self.restoreRoot()
1001                 lastservice=eServiceReference(config.tv.lastservice.value)
1002                 if lastservice.valid() and self.getCurrentSelection() != lastservice:
1003                         self.setCurrentSelection(lastservice)
1004
1005 from Screens.InfoBarGenerics import InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord
1006
1007 class RadioInfoBar(Screen, InfoBarEvent, InfoBarServiceName, InfoBarInstantRecord):
1008         def __init__(self, session):
1009                 Screen.__init__(self, session)
1010                 InfoBarEvent.__init__(self)
1011                 InfoBarServiceName.__init__(self)
1012                 InfoBarInstantRecord.__init__(self)
1013                 self["Clock"] = Clock()
1014
1015 class ChannelSelectionRadio(ChannelSelectionBase, ChannelSelectionEdit, ChannelSelectionEPG):
1016         def __init__(self, session):
1017                 ChannelSelectionBase.__init__(self, session)
1018                 ChannelSelectionEdit.__init__(self)
1019                 ChannelSelectionEPG.__init__(self)
1020
1021                 config.radio = ConfigSubsection();
1022                 config.radio.lastservice = configElement("config.radio.lastservice", configText, "", 0);
1023                 config.radio.lastroot = configElement("config.radio.lastroot", configText, "", 0);
1024                 self.onLayoutFinish.append(self.onCreate)
1025
1026                 self.info = session.instantiateDialog(RadioInfoBar)
1027
1028                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1029                         {
1030                                 "keyTV": self.closeRadio,
1031                                 "keyRadio": self.closeRadio,
1032                                 "cancel": self.closeRadio,
1033                                 "ok": self.channelSelected,
1034                         })
1035
1036         def saveRoot(self):
1037                 path = ''
1038                 for i in self.servicePathRadio:
1039                         path += i.toString()
1040                         path += ';'
1041                 if len(path) and path != config.radio.lastroot.value:
1042                         config.radio.lastroot.value = path
1043                         config.radio.lastroot.save()
1044
1045         def restoreRoot(self):
1046                 self.clearPath()
1047                 re = compile('.+?;')
1048                 tmp = re.findall(config.radio.lastroot.value)
1049                 cnt = 0
1050                 for i in tmp:
1051                         self.servicePathRadio.append(eServiceReference(i[:len(i)-1]))
1052                         cnt += 1
1053                 if cnt:
1054                         path = self.servicePathRadio.pop()
1055                         self.enterPath(path)
1056                 else:
1057                         self.showFavourites()
1058                         self.saveRoot()
1059
1060         def preEnterPath(self, refstr):
1061                 if len(self.servicePathRadio) and self.servicePathRadio[0] != eServiceReference(refstr):
1062                         pathstr = config.radio.lastroot.value
1063                         if pathstr is not None and pathstr.find(refstr) == 0:
1064                                 self.restoreRoot()
1065                                 lastservice=eServiceReference(config.radio.lastservice.value)
1066                                 if lastservice.valid():
1067                                         self.setCurrentSelection(lastservice)
1068                                 return True
1069                 return False
1070
1071         def onCreate(self):
1072                 self.setRadioMode()
1073                 self.restoreRoot()
1074                 lastservice=eServiceReference(config.radio.lastservice.value)
1075                 if lastservice.valid():
1076                         self.servicelist.setCurrent(lastservice)
1077                         self.session.nav.playService(lastservice)
1078                         self.servicelist.setPlayableIgnoreService(lastservice)
1079                 self.info.show()
1080
1081         def channelSelected(self): # just return selected service
1082                 ref = self.getCurrentSelection()
1083                 if self.movemode:
1084                         self.toggleMoveMarked()
1085                 elif (ref.flags & 7) == 7:
1086                         self.enterPath(ref)
1087                 elif self.bouquet_mark_edit:
1088                         self.doMark()
1089                 else:
1090                         playingref = self.session.nav.getCurrentlyPlayingServiceReference()
1091                         if playingref is None or playingref != ref:
1092                                 self.session.nav.playService(ref)
1093                                 self.servicelist.setPlayableIgnoreService(ref)
1094                                 config.radio.lastservice.value = ref.toString()
1095                                 config.radio.lastservice.save()
1096                         self.saveRoot()
1097
1098         def closeRadio(self):
1099                 self.info.hide()
1100                 #set previous tv service
1101                 lastservice=eServiceReference(config.tv.lastservice.value)
1102                 self.session.nav.playService(lastservice)
1103                 self.close(None)
1104
1105 class SimpleChannelSelection(ChannelSelectionBase):
1106         def __init__(self, session, title):
1107                 ChannelSelectionBase.__init__(self, session)
1108                 self.title = title
1109                 self.onShown.append(self.__onExecCallback)
1110
1111                 self["actions"] = ActionMap(["OkCancelActions", "TvRadioActions"],
1112                         {
1113                                 "cancel": self.close,
1114                                 "ok": self.channelSelected,
1115                                 "keyRadio": self.setModeRadio,
1116                                 "keyTV": self.setModeTv,
1117                         })
1118
1119         def __onExecCallback(self):
1120                 self.setTitle(self.title)
1121                 self.setModeTv()
1122
1123         def channelSelected(self): # just return selected service
1124                 ref = self.getCurrentSelection()
1125                 if (ref.flags & 7) == 7:
1126                         self.enterPath(ref)
1127                 else:
1128                         ref = self.getCurrentSelection()
1129                         self.close(ref)
1130
1131         def setModeTv(self):
1132                 self.setTvMode()
1133                 self.showFavourites()
1134
1135         def setModeRadio(self):
1136                 self.setRadioMode()
1137                 self.showFavourites()