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