902968d4a03f8d168f5f8935a09a02a41171bba0
[vuplus_dvbapp] / lib / python / Components / EpgList.py
1 # -*- coding: utf-8 -*-
2 from HTMLComponent import *
3 from GUIComponent import *
4
5 from enigma import *
6 from re import *
7 from time import localtime, time
8 from ServiceReference import ServiceReference
9 from Tools.Directories import resolveFilename, SCOPE_SKIN_IMAGE
10
11 EPG_TYPE_SINGLE = 0
12 EPG_TYPE_MULTI = 1
13 EPG_TYPE_SIMILAR = 2
14
15 RT_HALIGN_LEFT = 0
16 RT_HALIGN_RIGHT = 1
17 RT_HALIGN_CENTER = 2
18 RT_HALIGN_BLOCK = 4
19
20 RT_VALIGN_TOP = 0
21 RT_VALIGN_CENTER = 8
22 RT_VALIGN_BOTTOM = 16
23
24 RT_WRAP = 32
25
26 class Rect:
27         def __init__(self, x, y, width, height):
28                 self.__left = x
29                 self.__top = y
30                 self.__width = width
31                 self.__height = height
32
33         def left(self):
34                 return self.__left
35
36         def top(self):
37                 return self.__top
38
39         def height(self):
40                 return self.__height
41
42         def width(self):
43                 return self.__width
44
45 class EPGList(HTMLComponent, GUIComponent):
46         def __init__(self, type=EPG_TYPE_SINGLE, selChangedCB=None, timer = None):
47                 self.days = [ _("Mon"), _("Tue"), _("Wed"), _("Thu"), _("Fri"), _("Sat"), _("Sun") ]
48                 self.timer = timer
49                 self.onSelChanged = [ ]
50                 if selChangedCB is not None:
51                         self.onSelChanged.append(selChangedCB)
52                 GUIComponent.__init__(self)
53                 self.type=type
54                 self.l = eListboxPythonMultiContent()
55                 if type == EPG_TYPE_SINGLE:
56                         self.l.setBuildFunc(self.buildSingleEntry)
57                 elif type == EPG_TYPE_MULTI:
58                         self.l.setBuildFunc(self.buildMultiEntry)
59                 else:
60                         assert(type == EPG_TYPE_SIMILAR)
61                         self.l.setBuildFunc(self.buildSimilarEntry)
62                 self.epgcache = eEPGCache.getInstance()
63
64         def getEventFromId(self, service, eventid):
65                 event = None
66                 if self.epgcache is not None and eventid is not None:
67                         event = self.epgcache.lookupEventId(service.ref, eventid)
68                 return event
69
70         def getCurrentChangeCount(self):
71                 if self.type == EPG_TYPE_MULTI:
72                         return self.l.getCurrentSelection()[0]
73                 return 0
74
75         def getCurrent(self):
76                 idx=0
77                 if self.type == EPG_TYPE_MULTI:
78                         idx += 1
79                 tmp = self.l.getCurrentSelection()
80                 if tmp is None:
81                         return ( None, None )
82                 eventid = tmp[idx+1]
83                 service = ServiceReference(tmp[idx])
84                 event = self.getEventFromId(service, eventid)
85                 return ( event, service )
86
87         def moveUp(self):
88                 self.instance.moveSelection(self.instance.moveUp)
89
90         def moveDown(self):
91                 self.instance.moveSelection(self.instance.moveDown)
92
93         def connectSelectionChanged(func):
94                 if not self.onSelChanged.count(func):
95                         self.onSelChanged.append(func)
96
97         def disconnectSelectionChanged(func):
98                 self.onSelChanged.remove(func)
99
100         def selectionChanged(self):
101                 for x in self.onSelChanged:
102                         if x is not None:
103                                 try:
104                                         x()
105                                 except: # FIXME!!!
106                                         print "FIXME in EPGList.selectionChanged"
107                                         pass
108
109         GUI_WIDGET = eListbox
110         
111         def postWidgetCreate(self, instance):
112                 instance.setWrapAround(True)
113                 instance.selectionChanged.get().append(self.selectionChanged)
114                 instance.setContent(self.l)
115
116         def recalcEntrySize(self):
117                 esize = self.l.getItemSize()
118                 self.l.setFont(0, gFont("Regular", 22))
119                 self.l.setFont(1, gFont("Regular", 16))
120                 width = esize.width()
121                 height = esize.height()
122                 if self.type == EPG_TYPE_SINGLE:
123                         self.weekday_rect = Rect(0, 0, width/20*2-10, height)
124                         self.datetime_rect = Rect(width/20*2, 0, width/20*5-15, height)
125                         self.descr_rect = Rect(width/20*7, 0, width/20*13, height)
126                 elif self.type == EPG_TYPE_MULTI:
127                         xpos = 0;
128                         w = width/10*3;
129                         self.service_rect = Rect(xpos, 0, w-10, height)
130                         xpos += w;
131                         w = width/10*2;
132                         self.start_end_rect = Rect(xpos, 0, w-10, height)
133                         self.progress_rect = Rect(xpos, 4, w-10, height-8)
134                         xpos += w
135                         w = width/10*5;
136                         self.descr_rect = Rect(xpos, 0, width, height)
137                 else: # EPG_TYPE_SIMILAR
138                         self.weekday_rect = Rect(0, 0, width/20*2-10, height)
139                         self.datetime_rect = Rect(width/20*2, 0, width/20*5-15, height)
140                         self.service_rect = Rect(width/20*7, 0, width/20*13, height)
141
142         def buildSingleEntry(self, service, eventId, beginTime, duration, EventName):
143                 rec=(self.timer.isInTimer(eventId, beginTime, duration, service) > ((duration/10)*8)) 
144                 r1=self.weekday_rect
145                 r2=self.datetime_rect
146                 r3=self.descr_rect
147                 res = [ None ]  # no private data needed
148                 t = localtime(beginTime)
149                 res.append((eListboxPythonMultiContent.TYPE_TEXT, r1.left(), r1.top(), r1.width(), r1.height(), 0, RT_HALIGN_RIGHT, self.days[t[6]]))
150                 res.append((eListboxPythonMultiContent.TYPE_TEXT, r2.left(), r2.top(), r2.width(), r1.height(), 0, RT_HALIGN_RIGHT, "%02d.%02d, %02d:%02d"%(t[2],t[1],t[3],t[4])))
151                 if rec:
152                         res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, r3.left(), r3.top(), 21, 21, loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'epgclock-fs8.png'))))
153                         res.append((eListboxPythonMultiContent.TYPE_TEXT, r3.left() + 25, r3.top(), r3.width(), r3.height(), 0, RT_HALIGN_LEFT, EventName))
154                 else:
155                         res.append((eListboxPythonMultiContent.TYPE_TEXT, r3.left(), r3.top(), r3.width(), r3.height(), 0, RT_HALIGN_LEFT, EventName))
156                 return res
157
158         def buildSimilarEntry(self, service, eventId, beginTime, service_name, duration):
159                 rec=(self.timer.isInTimer(eventId, beginTime, duration, service) > ((duration/10)*8)) 
160                 r1=self.weekday_rect
161                 r2=self.datetime_rect
162                 r3=self.service_rect
163                 res = [ None ]  # no private data needed
164                 t = localtime(beginTime)
165                 res.append((eListboxPythonMultiContent.TYPE_TEXT, r1.left(), r1.top(), r1.width(), r1.height(), 0, RT_HALIGN_RIGHT, self.days[t[6]]))
166                 res.append((eListboxPythonMultiContent.TYPE_TEXT, r2.left(), r2.top(), r2.width(), r1.height(), 0, RT_HALIGN_RIGHT, "%02d.%02d, %02d:%02d"%(t[2],t[1],t[3],t[4])))
167                 if rec:
168                         res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, r3.left(), r3.top(), 21, 21, loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'epgclock-fs8.png'))))
169                         res.append((eListboxPythonMultiContent.TYPE_TEXT, r3.left() + 25, r3.top(), r3.width(), r3.height(), 0, RT_HALIGN_LEFT, service_name))
170                 else:
171                         res.append((eListboxPythonMultiContent.TYPE_TEXT, r3.left(), r3.top(), r3.width(), r3.height(), 0, RT_HALIGN_LEFT, service_name))
172                 return res
173
174         def buildMultiEntry(self, changecount, service, eventId, begTime, duration, EventName, nowTime, service_name):
175                 rec=begTime and (self.timer.isInTimer(eventId, begTime, duration, service) > ((duration/10)*8))
176                 sname = service_name
177                 r1=self.service_rect
178                 r2=self.progress_rect
179                 r3=self.descr_rect
180                 r4=self.start_end_rect
181                 res = [ None ] # no private data needed
182                 re = compile('\xc2\x86.*?\xc2\x87')
183                 list = re.findall(sname)
184                 if len(list):
185                         sname=''
186                         for substr in list:
187                                 sname+=substr[2:len(substr)-2]
188                         if len(sname) == 0:
189                                 sname = service_name;
190                 if rec:
191                         res.append((eListboxPythonMultiContent.TYPE_TEXT, r1.left(), r1.top(), r1.width()-21, r1.height(), 0, RT_HALIGN_LEFT, sname))
192                         res.append((eListboxPythonMultiContent.TYPE_PIXMAP_ALPHATEST, r1.left()+r1.width()-16, r1.top(), 21, 21, loadPNG(resolveFilename(SCOPE_SKIN_IMAGE, 'epgclock-fs8.png'))))
193                 else:
194                         res.append((eListboxPythonMultiContent.TYPE_TEXT, r1.left(), r1.top(), r1.width(), r1.height(), 0, RT_HALIGN_LEFT, sname))
195                 if begTime is not None:
196                         if nowTime < begTime:
197                                 begin = localtime(begTime)
198                                 end = localtime(begTime+duration)
199 #                               print "begin", begin
200 #                               print "end", end
201                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, r4.left(), r4.top(), r4.width(), r4.height(), 1, RT_HALIGN_CENTER|RT_VALIGN_CENTER, "%02d.%02d - %02d.%02d"%(begin[3],begin[4],end[3],end[4])));
202                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, r3.left(), r3.top(), r3.width(), r3.height(), 0, RT_HALIGN_LEFT, EventName))
203                         else:
204                                 percent = (nowTime - begTime) * 100 / duration
205                                 res.append((eListboxPythonMultiContent.TYPE_PROGRESS, r2.left(), r2.top(), r2.width(), r2.height(), percent));
206                                 res.append((eListboxPythonMultiContent.TYPE_TEXT, r3.left(), r3.top(), r3.width(), r3.height(), 0, RT_HALIGN_LEFT, EventName))
207                 return res
208
209         def queryEPG(self, list, buildFunc=None):
210                 if self.epgcache is not None:
211                         if buildFunc is not None:
212                                 return self.epgcache.lookupEvent(list, buildFunc)
213                         else:
214                                 return self.epgcache.lookupEvent(list)
215                 return [ ]
216
217         def fillMultiEPG(self, services, stime=-1):
218                 t = time()
219                 test = [ '0RIBDTCN' ]
220                 for service in services:
221                         tuple = (service.ref.toString(), 0, stime)
222                         test.append( tuple )
223                 self.list = self.queryEPG(test)
224                 self.l.setList(self.list)
225                 print time() - t
226                 self.selectionChanged()
227
228         def updateMultiEPG(self, direction):
229                 t = time()
230                 test = [ 'RIBDTCN' ]
231                 for x in self.list:
232                         service = x[1]
233                         begTime = x[3]
234                         duration = x[4]
235                         if begTime is None:
236                                 begTime = 0
237                         test.append((service, direction, begTime))
238                 tmp = self.queryEPG(test)
239                 cnt=0
240                 for x in tmp:
241                         changecount = self.list[cnt][0] + direction
242                         if changecount >= 0:
243                                 if x[2] is not None:
244                                         self.list[cnt]=(changecount, x[0], x[1], x[2], x[3], x[4], x[5], x[6])
245                         cnt+=1
246                 self.l.setList(self.list)
247                 print time() - t
248                 self.selectionChanged()
249
250         def fillSingleEPG(self, service):
251                 t = time()
252                 test = [ 'RIBDT', (service.ref.toString(), 0, -1, -1) ]
253                 self.l.setList(self.queryEPG(test))
254                 print time() - t
255                 self.selectionChanged()
256
257         def sort_func(self,x,y):
258                 if x[2] < y[2]:
259                         return -1
260                 elif x[2] == y[2]:
261                         return 0
262                 else:
263                         return 1
264
265         def fillSimilarList(self, refstr, event_id):
266                 t = time()
267          # search similar broadcastings
268                 if event_id is None:
269                         return
270                 l = self.epgcache.search(('RIBND', 1024, eEPGCache.SIMILAR_BROADCASTINGS_SEARCH, refstr, event_id))
271                 if l and len(l):
272                         l.sort(self.sort_func)
273                 self.l.setList(l)
274                 self.selectionChanged()
275                 print time() - t