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