add ability to remove list and config from a wizard
[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
5 from EpgSelection import EPGSelection
6 from enigma import eServiceReference, eEPGCache, eEPGCachePtr, eServiceCenter, eServiceCenterPtr, iMutableServiceListPtr, iStaticServiceInformationPtr, eTimer
7 from Components.config import config, configElement, ConfigSubsection, configText
8 from Screens.FixedMenu import FixedMenu
9 from Tools.NumericalTextInput import NumericalTextInput
10
11 import xml.dom.minidom
12
13 class BouquetSelector(FixedMenu):
14         def __init__(self, session, bouquets, parent):
15                 self.parent=parent
16                 entrys = [ ]
17                 for x in bouquets:
18                         entrys.append((x[0], self.bouquetSelected, x[1]))
19                 FixedMenu.__init__(self, session, "Bouquetlist", entrys)
20                 self.skinName = "Menu"
21
22         def bouquetSelected(self):
23                 self.parent.addCurrentServiceToBouquet(self["menu"].getCurrent()[2])
24                 self.close()
25
26 class ChannelContextMenu(FixedMenu):
27         def __init__(self, session, csel):
28                 self.csel = csel
29
30                 menu = [ ]
31
32                 inBouquetRootList = csel.servicelist.getRoot().getPath().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
33                 inBouquet = csel.getMutableList() is not None
34
35                 if not csel.bouquet_mark_edit and not csel.movemode and not inBouquetRootList:
36                         if (csel.getCurrentSelection().type & eServiceReference.flagDirectory) != eServiceReference.flagDirectory:
37                                 menu.append((_("add service to bouquet"), self.addServiceToBouquetSelected))
38                         if inBouquet:
39                                 menu.append((_("remove service"), self.removeCurrentService))
40
41                 if inBouquet: # current list is editable?
42                         if not csel.bouquet_mark_edit:
43                                 if not csel.movemode:
44                                         menu.append((_("enable move mode"), self.toggleMoveMode))
45                                         if not inBouquetRootList:
46                                                 menu.append((_("enable bouquet edit"), self.bouquetMarkStart))
47                                 else:
48                                         menu.append((_("disable move mode"), self.toggleMoveMode))
49                         elif not inBouquetRootList:
50                                 menu.append((_("end bouquet edit"), self.bouquetMarkEnd))
51                                 menu.append((_("abort bouquet edit"), self.bouquetMarkAbort))
52
53                 menu.append((_("back"), self.close))
54
55                 FixedMenu.__init__(self, session, _("Channel Selection"), menu)
56                 self.skinName = "Menu"
57
58         def addServiceToBouquetSelected(self):
59                 bouquets = [ ]
60                 serviceHandler = eServiceCenter.getInstance()
61                 list = serviceHandler.list(self.csel.bouquet_root)
62                 if not list is None:
63                         while True:
64                                 s = list.getNext()
65                                 if not s.valid():
66                                         break
67                                 if ((s.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory):
68                                         info = serviceHandler.info(s)
69                                         if not info is None:
70                                                 bouquets.append((info.getName(s), s))
71                 cnt = len(bouquets)
72                 if cnt > 1: # show bouquet list
73                         self.session.open(BouquetSelector, bouquets, self)
74                 elif cnt == 1: # add to only one existing bouquet
75                         self.addCurrentServiceToBouquet(bouquet[0][1])
76                 else: #no bouquets in root.. so assume only one favourite list is used
77                         self.addCurrentServiceToBouquet(self.csel.bouquet_root)
78
79         def addCurrentServiceToBouquet(self, dest):
80                 self.csel.addCurrentServiceToBouquet(dest)
81                 self.close()
82
83         def removeCurrentService(self):
84                 self.csel.removeCurrentService()
85                 self.close()
86
87         def toggleMoveMode(self):
88                 self.csel.toggleMoveMode()
89                 self.close()
90
91         def bouquetMarkStart(self):
92                 self.csel.startMarkedEdit()
93                 self.close()
94
95         def bouquetMarkEnd(self):
96                 self.csel.endMarkedEdit(abort=False)
97                 self.close()
98
99         def bouquetMarkAbort(self):
100                 self.csel.endMarkedEdit(abort=True)
101                 self.close()
102
103 class ChannelSelectionEdit:
104         def __init__(self):
105                 self.entry_marked = False
106                 self.movemode = False
107                 self.bouquet_mark_edit = False
108                 self.mutableList = None
109                 self.__marked = [ ]
110
111         def getMutableList(self, root=eServiceReference()):
112                 if not self.mutableList is None:
113                         return self.mutableList
114                 serviceHandler = eServiceCenter.getInstance()
115                 if not root.valid():
116                         root=self.servicelist.getRoot()
117                 list = serviceHandler.list(root)
118                 if list is not None:
119                         return list.startEdit()
120                 return None
121
122 #  multiple marked entry stuff ( edit mode, later multiepg selection )
123         def startMarkedEdit(self):
124                 self.mutableList = self.getMutableList()
125                 # add all services from the current list to internal marked set in listboxservicecontent
126                 self.bouquetRoot = self.servicelist.getRoot()
127                 self.clearMarks() # this clears the internal marked set in the listboxservicecontent
128                 self.bouquet_mark_edit = True
129                 self.__marked = self.servicelist.getRootServices()
130                 for x in self.__marked:
131                         self.servicelist.addMarked(eServiceReference(x))
132
133         def endMarkedEdit(self, abort):
134                 if not abort and self.mutableList is not None:
135                         new_marked = set(self.servicelist.getMarked())
136                         old_marked = set(self.__marked)
137                         removed = old_marked - new_marked
138                         added = new_marked - old_marked
139                         changed = False
140                         for x in removed:
141                                 changed = True
142                                 self.mutableList.removeService(eServiceReference(x))
143                         for x in added:
144                                 changed = True
145                                 self.mutableList.addService(eServiceReference(x))
146                         if changed:
147                                 self.mutableList.flushChanges()
148                                 self.setRoot(self.bouquetRoot)
149                                 #self.showFavourites()
150                 self.__marked = []
151                 self.clearMarks()
152                 self.bouquet_mark_edit = False
153                 self.bouquetRoot = None
154                 self.mutableList = None
155
156         def clearMarks(self):
157                 self.servicelist.clearMarks()
158
159         def doMark(self):
160                 ref = self.servicelist.getCurrent()
161                 if self.servicelist.isMarked(ref):
162                         self.servicelist.removeMarked(ref)
163                 else:
164                         self.servicelist.addMarked(ref)
165
166         def removeCurrentService(self):
167                 ref = self.servicelist.getCurrent()
168                 mutableList = self.getMutableList()
169                 if ref.valid() and mutableList is not None:
170                         if not mutableList.removeService(ref):
171                                 mutableList.flushChanges() #FIXME dont flush on each single removed service
172                                 self.setRoot(self.servicelist.getRoot())
173
174         def addCurrentServiceToBouquet(self, dest):
175                 mutableList = self.getMutableList(dest)
176                 if not mutableList is None:
177                         if not mutableList.addService(self.servicelist.getCurrent()):
178                                 mutableList.flushChanges()
179                 self.close()
180
181         def toggleMoveMode(self):
182                 if self.movemode:
183                         if self.entry_marked:
184                                 self.toggleMoveMarked() # unmark current entry
185                         self.movemode = False
186                         self.mutableList.flushChanges() # FIXME add check if changes was made
187                         self.mutableList = None
188                 else:
189                         self.mutableList = self.getMutableList()
190                         self.movemode = True
191
192         def handleEditCancel(self):
193                 if self.movemode: #movemode active?
194                         self.channelSelected() # unmark
195                         self.toggleMoveMode() # disable move mode
196                 elif self.bouquet_mark_edit:
197                         self.endMarkedEdit(True) # abort edit mode
198
199         def toggleMoveMarked(self):
200                 if self.entry_marked:
201                         self.servicelist.setCurrentMarked(False)
202                         self.entry_marked = False
203                 else:
204                         self.servicelist.setCurrentMarked(True)
205                         self.entry_marked = True
206
207         def doContext(self):
208                 self.session.open(ChannelContextMenu, self)
209
210 class ChannelSelectionBase(Screen):
211         def __init__(self, session):
212                 Screen.__init__(self, session)
213
214                 # this makes it much simple to implement a selectable radio or tv mode :)
215                 self.service_types_tv = '1:7:1:0:0:0:0:0:0:0:(type == 1) || (type == 17)'
216                 self.service_types_radio = '1:7:1:0:0:0:0:0:0:0:(type == 2)'
217
218                 self.service_types = self.service_types_tv
219
220                 #self.bouquet_root = eServiceReference('1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet')
221                 self.bouquet_root = eServiceReference('%s FROM BOUQUET "userbouquet.favourites.tv" ORDER BY bouquet'%(self.service_types))
222
223                 self["key_red"] = Button(_("All"))
224                 self["key_green"] = Button(_("Satellites"))
225                 self["key_yellow"] = Button(_("Provider"))
226                 self["key_blue"] = Button(_("Favourites"))
227
228                 self["list"] = ServiceList()
229                 self.servicelist = self["list"]
230
231                 #self["okbutton"] = Button("ok", [self.channelSelected])
232
233                 self.numericalTextInput = NumericalTextInput()
234
235         def getBouquetNumOffset(self, bouquet):
236                 if self.bouquet_root.getPath().find('FROM BOUQUET "bouquets.') == -1: #FIXME HACK
237                         return 0
238                 offsetCount = 0
239                 serviceHandler = eServiceCenter.getInstance()
240                 bouquetlist = serviceHandler.list(self.bouquet_root)
241                 if not bouquetlist is None:
242                         while True:
243                                 bouquetIterator = bouquetlist.getNext()
244                                 if not bouquetIterator.valid() or bouquetIterator == bouquet: #end of list or bouquet found
245                                         break
246                                 if ((bouquetIterator.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
247                                         continue
248                                 servicelist = serviceHandler.list(bouquetIterator)
249                                 if not servicelist is None:
250                                         while True:
251                                                 serviceIterator = servicelist.getNext()
252                                                 if not serviceIterator.valid(): #check if end of list
253                                                         break
254                                                 if serviceIterator.flags: #playable services have no flags
255                                                         continue
256                                                 offsetCount += 1
257                 return offsetCount
258
259         def setRootBase(self, root):
260                 inBouquetRootList = root.getPath().find('FROM BOUQUET "bouquets.') != -1 #FIXME HACK
261                 if not inBouquetRootList and (root.getPath().find('FROM BOUQUET') != -1):
262                         self.servicelist.setMode(ServiceList.MODE_FAVOURITES)
263                         self.servicelist.setNumberOffset(self.getBouquetNumOffset(root))
264                 else:
265                         self.servicelist.setMode(ServiceList.MODE_NORMAL)
266                 self.servicelist.setRoot(root)
267
268         def moveUp(self):
269                 self.servicelist.moveUp()
270
271         def moveDown(self):
272                 self.servicelist.moveDown()
273
274         def showAllServices(self):
275                 ref = eServiceReference('%s ORDER BY name'%(self.service_types))
276                 self.setRoot(ref)
277
278         def showSatellites(self):
279                 ref = eServiceReference('%s FROM SATELLITES ORDER BY satellitePosition'%(self.service_types))
280                 self.setRoot(ref)
281
282         def showProviders(self):
283                 ref = eServiceReference('%s FROM PROVIDERS ORDER BY name'%(self.service_types))
284                 self.setRoot(ref)
285
286         def showFavourites(self):
287                 self.setRoot(self.bouquet_root)
288
289         def keyNumberGlobal(self, number):
290                 char = self.numericalTextInput.getKey(number)
291                 print "You pressed number " + str(number)
292                 print "You would go to character " + str(char)
293                 self.servicelist.moveToChar(char)
294
295         def enterBouquet(self, action):
296                 if action[:7] == "bouquet":
297                         if action.find("FROM BOUQUET") != -1:
298                                 self.setRoot(eServiceReference("1:7:1:0:0:0:0:0:0:0:" + action[8:]))
299                         else:
300                                 self.setRoot(eServiceReference("1:0:1:0:0:0:0:0:0:0:" + action[8:]))
301                         return True
302                 return False
303
304         def getRoot(self):
305                 return self.servicelist.getRoot()
306
307         def getCurrentSelection(self):
308                 return self.servicelist.getCurrent()
309
310         def setCurrentSelection(self, service):
311                 self.servicelist.setCurrent(service)
312
313         def cancel(self):
314                 self.close(None)
315
316 class ChannelSelection(ChannelSelectionBase, ChannelSelectionEdit):
317         def __init__(self, session):
318                 ChannelSelectionBase.__init__(self,session)
319                 ChannelSelectionEdit.__init__(self)
320
321                 #config for lastservice
322                 config.tv = ConfigSubsection();
323                 config.tv.lastservice = configElement("config.tv.lastservice", configText, "", 0);
324                 config.tv.lastroot = configElement("config.tv.lastroot", configText, "", 0);
325
326                 class ChannelActionMap(NumberActionMap):
327                         def action(self, contexts, action):
328                                 if not self.csel.enterBouquet(action):
329                                         if action == "cancel":
330                                                 self.csel.handleEditCancel()
331                                         NumberActionMap.action(self, contexts, action)
332                 self["actions"] = ChannelActionMap(["ChannelSelectActions", "OkCancelActions", "ContextMenuActions"],
333                         {
334                                 "cancel": self.cancel,
335                                 "ok": self.channelSelected,
336                                 "mark": self.doMark,
337                                 "contextMenu": self.doContext,
338                                 "showFavourites": self.showFavourites,
339                                 "showAllServices": self.showAllServices,
340                                 "showProviders": self.showProviders,
341                                 "showSatellites": self.showSatellites,
342                                 "showEPGList": self.showEPGList,
343                                 "1": self.keyNumberGlobal,
344                                 "2": self.keyNumberGlobal,
345                                 "3": self.keyNumberGlobal,
346                                 "4": self.keyNumberGlobal,
347                                 "5": self.keyNumberGlobal,
348                                 "6": self.keyNumberGlobal,
349                                 "7": self.keyNumberGlobal,
350                                 "8": self.keyNumberGlobal,
351                                 "9": self.keyNumberGlobal,
352                                 "0": self.keyNumberGlobal
353                         })
354                 self["actions"].csel = self
355                 self.onShown.append(self.onShow)
356
357 #               self.onLayoutFinish.append(self.onCreate)
358                 self.lastChannelRootTimer = eTimer()
359                 self.lastChannelRootTimer.timeout.get().append(self.onCreate)
360                 self.lastChannelRootTimer.start(100,True)
361
362         def onCreate(self):
363                 lastroot=eServiceReference(config.tv.lastroot.value)
364                 if lastroot.valid():
365                         self.setRoot(lastroot)
366                 else:
367                         self.showFavourites()
368                         self.saveRoot(self.getRoot())
369                 lastservice=eServiceReference(config.tv.lastservice.value)
370                 if lastservice.valid():
371                         self.session.nav.playService(lastservice)
372                         self.servicelist.setCurrent(lastservice)
373
374         def onShow(self):
375                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
376                 if ref is not None and ref.valid() and ref.getPath() == "":
377                         self.servicelist.setPlayableIgnoreService(ref)
378                 else:
379                         self.servicelist.setPlayableIgnoreService(eServiceReference())
380
381         def showEPGList(self):
382                 ref=self.getCurrentSelection()
383                 ptr=eEPGCache.getInstance()
384                 if ptr.startTimeQuery(ref) != -1:
385                         self.session.open(EPGSelection, ref)
386                 else:
387                         print 'no epg for service', ref.toString()
388
389         def channelSelected(self):
390                 ref = self.getCurrentSelection()
391                 if self.movemode:
392                         self.toggleMoveMarked()
393                 elif (ref.flags & 7) == 7:
394                         self.setRoot(ref)
395                 elif self.bouquet_mark_edit:
396                         self.doMark()
397                 else:
398                         self.zap()
399                         self.close(ref)
400
401         def setRoot(self, root):
402                 if not self.movemode:
403                         self.setRootBase(root)
404
405         #called from infoBar and channelSelected
406         def zap(self):
407                 self.session.nav.playService(self.getCurrentSelection())
408                 self.saveRoot(self.getRoot())
409                 self.saveChannel()
410
411         def saveRoot(self, root):
412                 if root is not None:
413                         config.tv.lastroot.value = root.toString()
414                         config.tv.lastroot.save()
415
416         def saveChannel(self):
417                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
418                 if ref is not None:
419                         refstr = ref.toString()
420                 else:
421                         refstr = ""
422                 config.tv.lastservice.value = refstr
423                 config.tv.lastservice.save()
424
425         def cancel(self):
426                 self.close(None)
427                 lastroot=eServiceReference(config.tv.lastroot.value)
428                 lastservice=eServiceReference(config.tv.lastservice.value)
429                 if lastroot.valid() and self.getRoot() != lastroot:
430                         self.setRoot(lastroot)
431                 if lastservice.valid() and self.getCurrentSelection() != lastservice:
432                         self.servicelist.setCurrent(lastservice)
433
434 class SimpleChannelSelection(ChannelSelectionBase):
435         def __init__(self, session, title):
436                 ChannelSelectionBase.__init__(self, session)
437                 self.title = title
438                 self.onShown.append(self.onExecCallback)
439
440                 class ChannelActionMap(NumberActionMap):
441                         def action(self, contexts, action):
442                                 if not self.csel.enterBouquet(action):
443                                         NumberActionMap.action(self, contexts, action)
444                 self["actions"] = ChannelActionMap(["ChannelSelectActions", "OkCancelActions", "ContextMenuActions"],
445                         {
446                                 "cancel": self.cancel,
447                                 "ok": self.channelSelected,
448                                 "showFavourites": self.showFavourites,
449                                 "showAllServices": self.showAllServices,
450                                 "showProviders": self.showProviders,
451                                 "showSatellites": self.showSatellites,
452                                 "1": self.keyNumberGlobal,
453                                 "2": self.keyNumberGlobal,
454                                 "3": self.keyNumberGlobal,
455                                 "4": self.keyNumberGlobal,
456                                 "5": self.keyNumberGlobal,
457                                 "6": self.keyNumberGlobal,
458                                 "7": self.keyNumberGlobal,
459                                 "8": self.keyNumberGlobal,
460                                 "9": self.keyNumberGlobal,
461                                 "0": self.keyNumberGlobal
462                         })
463                 self["actions"].csel = self
464
465         def onExecCallback(self):
466                 print "onExecCallback"
467                 self.showFavourites()
468                 self.session.currentDialog.instance.setTitle(self.title)
469
470         def channelSelected(self): # just return selected service
471                 ref = self.getCurrentSelection()
472                 self.close(ref)
473
474         def setRoot(self, root):
475                 self.setRootBase(root)
476