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