zap with numbers is now possible
[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 ActionMap
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
10 import xml.dom.minidom
11
12 class BouquetSelector(FixedMenu):
13         def __init__(self, session, bouquets, parent):
14                 self.parent=parent
15                 entrys = [ ]
16                 for x in bouquets:
17                         entrys.append((x[0], self.bouquetSelected, x[1]))
18                 FixedMenu.__init__(self, session, "Bouquetlist", entrys)
19                 self.skinName = "Menu"
20
21         def bouquetSelected(self):
22                 self.parent.addCurrentServiceToBouquet(self["menu"].getCurrent()[2])
23                 self.close()
24
25 class ChannelContextMenu(FixedMenu):
26         def __init__(self, session, csel):
27                 self.csel = csel
28
29                 menu = [ ]
30
31                 #HACK
32                 inBouquetRootList = csel["list"].getRoot().toString().find('FROM BOUQUET "bouquets.') != -1
33                 inBouquet = csel.getMutableList() is not None
34
35                 if not csel.bouquet_mark_edit and not csel.movemode and not inBouquetRootList:
36                         menu.append(("add service to bouquet", self.addServiceToBouquetSelected))
37                         if inBouquet:
38                                 menu.append(("remove service", self.removeCurrentService))
39
40                 if inBouquet: # current list is editable?
41                         if not csel.bouquet_mark_edit:
42                                 if not csel.movemode:
43                                         menu.append(("enable move mode", self.toggleMoveMode))
44                                         if not inBouquetRootList: 
45                                                 menu.append(("enable bouquet edit", self.bouquetMarkStart))
46                                 else:
47                                         menu.append(("disable move mode", self.toggleMoveMode))
48                         elif not inBouquetRootList: 
49                                 menu.append(("end bouquet edit", self.bouquetMarkEnd))
50                                 menu.append(("abort bouquet edit", self.bouquetMarkAbort))
51
52                 menu.append(("back", self.close))
53
54                 FixedMenu.__init__(self, session, "Channel Selection", menu)
55                 self.skinName = "Menu"
56
57         def addServiceToBouquetSelected(self):
58                 bouquets = [ ]
59                 serviceHandler = eServiceCenter.getInstance()
60                 list = serviceHandler.list(self.csel.bouquet_root)
61                 if not list is None:
62                         while 1:
63                                 s = list.getNext()
64                                 if not s.valid():
65                                         break
66                                 if ((s.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory):
67                                         info = serviceHandler.info(s)
68                                         if not info is None:
69                                                 str = info.getName(s)
70                                                 bouquets.append((str, 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 ChannelSelection(Screen):
104         def lastService(self):
105                 self.lastServiceTimer.stop()
106                 #zap to last running tv service
107                 self.setRoot(eServiceReference(config.tv.lastroot.value))
108                 self.session.nav.playService(eServiceReference(config.tv.lastservice.value))
109         
110         def __init__(self, session):
111                 Screen.__init__(self, session)
112
113                 #config for lastservice
114                 config.tv = ConfigSubsection();
115                 config.tv.lastservice = configElement("config.tv.lastservice", configText, "", 0);
116                 config.tv.lastroot = configElement("config.tv.lastroot", configText, "", 0);
117
118                 self.entry_marked = False
119                 self.movemode = False
120                 self.bouquet_mark_edit = False
121                 self.bouquet_root = eServiceReference('1:7:1:0:0:0:0:0:0:0:(type == 1) FROM BOUQUET "bouquets.tv" ORDER BY bouquet')
122                 self.mutableList = None
123
124                 self.__marked = [ ]
125
126                 self["key_red"] = Button("All")
127                 self["key_green"] = Button("Provider")
128                 self["key_yellow"] = Button("Satellite")
129                 self["key_blue"] = Button("Favourites")
130                 
131                 self["list"] = ServiceList()
132
133                 if config.tv.lastroot.value == "":
134                         self["list"].setRoot(eServiceReference("""1:0:1:0:0:0:0:0:0:0:(type == 1)"""))
135                 #self["okbutton"] = Button("ok", [self.channelSelected])
136
137                 self.lastServiceTimer = eTimer()
138                 self.lastServiceTimer.timeout.get().append(self.lastService)
139                 self.lastServiceTimer.start(100)
140
141                 class ChannelActionMap(ActionMap):
142                         def action(self, contexts, action):
143                                 if action[:7] == "bouquet":
144                                         l = self.csel
145                                         list = l["list"]
146                                         if action.find("FROM BOUQUET") != -1:
147                                                 l.setRoot(eServiceReference("1:7:1:0:0:0:0:0:0:0:" + action[8:]))
148                                         else:
149                                                 l.setRoot(eServiceReference("1:0:1:0:0:0:0:0:0:0:" + action[8:]))
150                                 else:
151                                         if action == "cancel":
152                                                 l = self.csel
153                                                 if l.movemode: #movemode active?
154                                                         l.channelSelected() # unmark
155                                                         l.toggleMoveMode() # disable move mode
156                                                 elif l.bouquet_mark_edit:
157                                                         l.endMarkedEdit(True) # abort edit mode
158                                         ActionMap.action(self, contexts, action)
159
160                 self["actions"] = ChannelActionMap(["ChannelSelectActions", "OkCancelActions", "ContextMenuActions"], 
161                         {
162                                 "cancel": self.close,
163                                 "ok": self.channelSelected,
164                                 "mark": self.doMark,
165                                 "contextMenu": self.doContext,
166                                 "showFavourites": self.showFavourites,
167                     "showEPGList": self.showEPGList
168                         })
169                 self["actions"].csel = self
170
171         def showEPGList(self):
172                 ref=self["list"].getCurrent()
173                 ptr=eEPGCache.getInstance()
174                 if ptr.startTimeQuery(ref) != -1:
175                         self.session.open(EPGSelection, ref)
176                 else:
177                         print 'no epg for service', ref.toString()
178
179         def getMutableList(self, root=eServiceReference()):
180                 if not self.mutableList is None:
181                         return self.mutableList
182                 serviceHandler = eServiceCenter.getInstance()
183                 if not root.valid():
184                         root=self["list"].getRoot()
185                 list = serviceHandler.list(root)
186                 mutableList = None
187                 if list is not None:
188                         mutableList = list.startEdit()
189                 return mutableList
190
191 #  multiple marked entry stuff ( edit mode, later multiepg selection )
192         def startMarkedEdit(self):
193                 self.mutableList = self.getMutableList()
194                 l = self["list"]
195                 # add all services from the current list to internal marked set in listboxservicecontent
196                 self.bouquetRoot = l.getRoot()
197                 self.clearMarks() # this clears the internal marked set in the listboxservicecontent
198                 self.bouquet_mark_edit = True
199                 self.__marked = l.getRootServices()
200                 for x in self.__marked:
201                         l.addMarked(eServiceReference(x))
202
203         def endMarkedEdit(self, abort):
204                 l = self["list"]
205                 if not abort and self.mutableList is not None:
206                         new_marked = set(l.getMarked())
207                         old_marked = set(self.__marked)
208                         removed = old_marked - new_marked
209                         added = new_marked - old_marked
210                         changed = False
211                         for x in removed:
212                                 changed = True
213                                 self.mutableList.removeService(eServiceReference(x))
214                         for x in added:
215                                 changed = True
216                                 self.mutableList.addService(eServiceReference(x))
217                         if changed:
218                                 self.mutableList.flushChanges()
219                                 self.setRoot(self.bouquetRoot)
220                                 #self.showFavourites()
221                 self.__marked = []
222                 self.clearMarks()
223                 self.bouquet_mark_edit = False
224                 self.bouquetRoot = None
225                 self.mutableList = None
226
227         def clearMarks(self):
228                 self["list"].clearMarks()
229
230         def doMark(self):
231                 ref = self["list"].getCurrent()
232                 if self["list"].isMarked(ref):
233                         self["list"].removeMarked(ref)
234                 else:
235                         self["list"].addMarked(ref)
236
237         def removeCurrentService(self):
238                 l = self["list"]
239                 ref = l.getCurrent()
240                 mutableList = self.getMutableList()
241                 if ref.valid() and mutableList is not None:
242                         if mutableList.removeService(ref) == 0:
243                                 mutableList.flushChanges() #FIXME dont flush on each single removed service
244                                 self.setRoot(l.getRoot())
245
246         def addCurrentServiceToBouquet(self, dest):
247                 mutableList = self.getMutableList(dest)
248                 if not mutableList is None:
249                         if mutableList.addService(self["list"].getCurrent()) == 0:
250                                 mutableList.flushChanges()
251                 self.close()
252
253         def findService(self, serviceHandler, num, bouquet):
254                 list = serviceHandler.list(bouquet)
255                 if not list is None:
256                         while num > 0:
257                                 s = list.getNext()
258                                 if not s.valid():
259                                         break
260                                 if s.flags != 0: #assume normal dvb service have no flags set
261                                         continue
262                                 num = num - 1;
263                         if num == 0:
264                                 return s, 0
265                 return None, num
266
267         def zapToNumber(self, number):
268                 bouquet = None
269                 service = None
270                 serviceHandler = eServiceCenter.getInstance()
271                 if self.bouquet_root.toString().find('FROM BOUQUET "bouquets.') == -1:
272                         service, number = self.findService(serviceHandler, number, self.bouquet_root)
273                         bouquet = self.bouquet_root
274                 else:
275                         list = serviceHandler.list(self.bouquet_root)
276                         if not list is None:
277                                 while number:
278                                         s = list.getNext()
279                                         if not s.valid():
280                                                 break
281                                         bouquet = s
282                                         service, number = self.findService(serviceHandler, number, s)
283                 if not service is None:
284                         self.session.nav.playService(service)
285                         if not bouquet is None:
286                                 if self["list"].getRoot() != bouquet:
287                                         self.setRoot(bouquet)
288                                 self.setCurrent(service)
289
290         def setCurrent(self, service):
291                 self["list"].setCurrent(service)
292
293         def getBouquetNumOffset(self, bouquet):
294                 if self.bouquet_root.toString().find('FROM BOUQUET "bouquets.') == -1:
295                         return 0
296                 offset=0
297                 serviceHandler = eServiceCenter.getInstance()
298                 list = serviceHandler.list(self.bouquet_root)
299                 if not list is None:
300                         while 1:
301                                 s = list.getNext()
302                                 if not s.valid() or s == bouquet:
303                                         break
304                                 if ((s.flags & eServiceReference.flagDirectory) != eServiceReference.flagDirectory):
305                                         continue
306                                 slist = serviceHandler.list(s)
307                                 if not slist is None:
308                                         while 1:
309                                                 ss = slist.getNext()
310                                                 if not ss.valid():
311                                                         break
312                                                 if ss.flags != 0:
313                                                         continue
314                                                 offset = offset + 1
315                 return offset
316
317         def setRoot(self, root):
318                 if not self.movemode: # dont change root when movemode is enabled
319                         list = self["list"]
320
321                         #HACK
322                         inBouquetRootList = root.toString().find('FROM BOUQUET "bouquets.') != -1
323
324                         if not inBouquetRootList and ((root.flags & eServiceReference.flagDirectory) == eServiceReference.flagDirectory):
325                                 list.setMode(list.MODE_FAVOURITES)
326                                 offset = self.getBouquetNumOffset(root)
327                                 list.setNumberOffset(offset)
328                         else:
329                                 list.setMode(list.MODE_NORMAL)
330                         list.setRoot(root)
331
332         def channelSelected(self):
333                 ref = self["list"].getCurrent()
334                 if self.movemode:
335                         if self.entry_marked:
336                                 self["list"].setCurrentMarked(False)
337                                 self.entry_marked = False
338                         else:
339                                 self["list"].setCurrentMarked(True)
340                                 self.entry_marked = True
341                 elif (ref.flags & 7) == 7:
342                         self.setRoot(ref)
343                 elif self.bouquet_mark_edit:
344                         self.doMark()
345                 else:
346                         self.session.nav.playService(ref)
347                         self.saveChannel()
348                         self.close()
349
350         #called from infoBar
351         def zap(self):
352                 self.session.nav.playService(self["list"].getCurrent())
353                 self.saveChannel()
354
355         def moveUp(self):
356                 self["list"].moveUp()
357
358         def moveDown(self):
359                 self["list"].moveDown()
360
361         def doContext(self):
362                 self.session.open(ChannelContextMenu, self)
363
364         def toggleMoveMode(self):
365                 if self.movemode:
366                         if self.entry_marked:
367                                 self.channelSelected() # unmark current entry
368                         self.movemode = False
369                         self.mutableList.flushChanges() # FIXME add check if changes was made
370                         self.mutableList = None
371                 else:
372                         self.mutableList = self.getMutableList()
373                         self.movemode = True
374
375         def showFavourites(self):
376                 self.setRoot(self.bouquet_root)
377
378         def saveRoot(self, root):
379                 if root is not None:
380                         config.tv.lastroot.value = root.toString()
381                         config.tv.lastroot.save()
382
383         def saveChannel(self):
384                 ref = self.session.nav.getCurrentlyPlayingServiceReference()
385                 if ref is not None:
386                         refstr = ref.toString()
387                 else:
388                         refstr = ""
389                 config.tv.lastservice.value = refstr
390                 config.tv.lastservice.save()