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