Fix network test.
[vuplus_dvbapp] / lib / python / Components / MovieList.py
1 from GUIComponent import GUIComponent
2 from Tools.FuzzyDate import FuzzyTime
3 from ServiceReference import ServiceReference
4 from Components.MultiContent import MultiContentEntryText
5 from Components.config import config
6
7 from enigma import eListboxPythonMultiContent, eListbox, gFont, iServiceInformation, \
8         RT_HALIGN_LEFT, RT_HALIGN_RIGHT, eServiceReference, eServiceCenter
9
10 class MovieList(GUIComponent):
11         SORT_ALPHANUMERIC = 1
12         SORT_RECORDED = 2
13
14         LISTTYPE_ORIGINAL = 1
15         LISTTYPE_COMPACT_DESCRIPTION = 2
16         LISTTYPE_COMPACT = 3
17         LISTTYPE_MINIMAL = 4
18
19         HIDE_DESCRIPTION = 1
20         SHOW_DESCRIPTION = 2
21
22         def __init__(self, root, list_type=None, sort_type=None, descr_state=None):
23                 GUIComponent.__init__(self)
24                 self.list_type = list_type or self.LISTTYPE_ORIGINAL
25                 self.descr_state = descr_state or self.HIDE_DESCRIPTION
26                 self.sort_type = sort_type or self.SORT_RECORDED
27
28                 self.fontName = "Regular"
29                 self.fontSizesOriginal = (22,18,16)
30                 self.fontSizesCompact = (20,14)
31                 self.fontSizesMinimal = (20,16)
32                 self.itemHeights = (75,37,25)
33                 self.columnsOriginal = (180,200)
34                 self.columnsCompactDescription = (120,154,58)
35                 self.compactColumn = (75,200)
36
37                 self.l = eListboxPythonMultiContent()
38                 self.tags = set()
39                 
40                 if root is not None:
41                         self.reload(root)
42                 
43                 self.redrawList()
44                 self.l.setBuildFunc(self.buildMovieListEntry)
45                 
46                 self.onSelectionChanged = [ ]
47
48         def connectSelChanged(self, fnc):
49                 if not fnc in self.onSelectionChanged:
50                         self.onSelectionChanged.append(fnc)
51
52         def disconnectSelChanged(self, fnc):
53                 if fnc in self.onSelectionChanged:
54                         self.onSelectionChanged.remove(fnc)
55
56         def selectionChanged(self):
57                 for x in self.onSelectionChanged:
58                         x()
59
60         def setListType(self, type):
61                 self.list_type = type
62
63         def setDescriptionState(self, val):
64                 self.descr_state = val
65
66         def setSortType(self, type):
67                 self.sort_type = type
68
69         def applySkin(self, desktop, parent):
70                 def warningWrongSkinParameter(string):
71                         print "[MovieList] wrong '%s' skin parameters" % string
72                 def fontName(value):
73                         self.fontName = value
74                 def fontSizesOriginal(value):
75                         self.fontSizesOriginal = map(int, value.split(","))
76                         if len(self.fontSizesOriginal) != 3:
77                                 warningWrongSkinParameter(attrib)
78                 def fontSizesCompact(value):
79                         self.fontSizesCompact = map(int, value.split(","))
80                         if len(self.fontSizesCompact) != 2:
81                                 warningWrongSkinParameter(attrib)
82                 def fontSizesMinimal(value):
83                         self.fontSizesMinimal = map(int, value.split(","))
84                         if len(self.fontSizesMinimal) != 2:
85                                 warningWrongSkinParameter(attrib)
86                 def itemHeights(value):
87                         self.itemHeights = map(int, value.split(","))
88                         if len(self.itemHeights) != 3:
89                                 warningWrongSkinParameter(attrib)
90                 def columnsOriginal(value):
91                         self.columnsOriginal = map(int, value.split(","))
92                         if len(self.columnsOriginal) != 2:
93                                 warningWrongSkinParameter(attrib)
94                 def columnsCompactDescription(value):
95                         self.columnsCompactDescription = map(int, value.split(","))
96                         if len(self.columnsCompactDescription) != 3:
97                                 warningWrongSkinParameter(attrib)
98                 def compactColumn(value):
99                         self.compactColumn = map(int, value.split(","))
100                         if len(self.compactColumn) != 2:
101                                 warningWrongSkinParameter(attrib)
102                 for (attrib, value) in self.skinAttributes[:]:
103                         try:
104                                 locals().get(attrib)(value)
105                                 self.skinAttributes.remove((attrib, value))
106                         except:
107                                 pass
108                 self.redrawList()
109                 return GUIComponent.applySkin(self, desktop, parent)
110
111         def redrawList(self):
112                 if self.list_type == MovieList.LISTTYPE_ORIGINAL:
113                         for i in range(3):
114                                 self.l.setFont(i, gFont(self.fontName, self.fontSizesOriginal[i]))
115                         self.itemHeight = self.itemHeights[0]
116                 elif self.list_type == MovieList.LISTTYPE_COMPACT_DESCRIPTION or self.list_type == MovieList.LISTTYPE_COMPACT:
117                         self.l.setItemHeight(37)
118                         for i in range(2):
119                                 self.l.setFont(i, gFont(self.fontName, self.fontSizesCompact[i]))
120                         self.itemHeight = self.itemHeights[1]
121                 else:
122                         for i in range(2):
123                                 self.l.setFont(i, gFont(self.fontName, self.fontSizesMinimal[i]))
124                         self.itemHeight = self.itemHeights[2]
125                 self.l.setItemHeight(self.itemHeight)
126
127         #
128         # | name of movie              |
129         #
130         def buildMovieListEntry(self, serviceref, info, begin, len):
131                 if serviceref.flags & eServiceReference.mustDescent:
132                         return None
133
134                 width = self.l.getItemSize().width()
135
136                 if len <= 0: #recalc len when not already done
137                         cur_idx = self.l.getCurrentSelectionIndex()
138                         x = self.list[cur_idx]
139                         if config.usage.load_length_of_movies_in_moviellist.value:
140                                 len = x[1].getLength(x[0]) #recalc the movie length...
141                         else:
142                                 len = 0 #dont recalc movielist to speedup loading the list
143                         self.list[cur_idx] = (x[0], x[1], x[2], len) #update entry in list... so next time we don't need to recalc
144                 
145                 if len > 0:
146                         len = "%d:%02d" % (len / 60, len % 60)
147                 else:
148                         len = ""
149                 
150                 res = [ None ]
151                 
152                 txt = info.getName(serviceref)
153                 service = ServiceReference(info.getInfoString(serviceref, iServiceInformation.sServiceref))
154                 description = info.getInfoString(serviceref, iServiceInformation.sDescription)
155                 tags = info.getInfoString(serviceref, iServiceInformation.sTags)
156
157                 begin_string = ""
158                 if begin > 0:
159                         t = FuzzyTime(begin)
160                         begin_string = t[0] + ", " + t[1]
161                 ih = self.itemHeight
162                 if self.list_type == MovieList.LISTTYPE_ORIGINAL:
163                         fc, sc = self.columnsOriginal[0], self.columnsOriginal[1]
164                         ih1 = (ih * 2) / 5 # 75 -> 30
165                         ih2 = (ih * 2) / 3 # 75 -> 50
166                         res.append(MultiContentEntryText(pos=(0, 0), size=(width-fc-2, ih1), font = 0, flags = RT_HALIGN_LEFT, text=txt))
167                         if self.tags:
168                                 res.append(MultiContentEntryText(pos=(width-fc, 0), size=(fc, ih1), font = 2, flags = RT_HALIGN_RIGHT, text = tags))
169                                 if service is not None:
170                                         res.append(MultiContentEntryText(pos=(sc, ih2), size=(sc, ih2-ih1), font = 1, flags = RT_HALIGN_LEFT, text = service.getServiceName()))
171                         else:
172                                 if service is not None:
173                                         res.append(MultiContentEntryText(pos=(width-fc, 0), size=(fc, ih1), font = 2, flags = RT_HALIGN_RIGHT, text = service.getServiceName()))
174                         res.append(MultiContentEntryText(pos=(0, ih1), size=(width, ih2-ih1), font=1, flags=RT_HALIGN_LEFT, text=description))
175                         res.append(MultiContentEntryText(pos=(0, ih2), size=(sc, ih2-ih1), font=1, flags=RT_HALIGN_LEFT, text=begin_string))
176                         res.append(MultiContentEntryText(pos=(width-sc, ih2), size=(sc-2, ih2-ih1), font=1, flags=RT_HALIGN_RIGHT, text=len))
177                 elif self.list_type == MovieList.LISTTYPE_COMPACT_DESCRIPTION:
178                         ih1 = ((ih * 8) + 14) / 15 # 37 -> 20, round up
179                         fc, sc, lc = self.columnsCompactDescription[0], self.columnsCompactDescription[1], self.columnsCompactDescription[2]
180                         res.append(MultiContentEntryText(pos=(0, 0), size=(width-fc, ih1), font = 0, flags = RT_HALIGN_LEFT, text = txt))
181                         res.append(MultiContentEntryText(pos=(0, ih1), size=(width-sc-lc, ih-ih1), font=1, flags=RT_HALIGN_LEFT, text=description))
182                         res.append(MultiContentEntryText(pos=(width-fc, 6), size=(fc, ih1), font=1, flags=RT_HALIGN_RIGHT, text=begin_string))
183                         if service is not None:
184                                 res.append(MultiContentEntryText(pos=(width-sc-lc, ih1), size=(sc, ih-ih1), font = 1, flags = RT_HALIGN_RIGHT, text = service.getServiceName()))
185                         res.append(MultiContentEntryText(pos=(width-lc, ih1), size=(lc, ih1), font=1, flags=RT_HALIGN_RIGHT, text=len))
186                 elif self.list_type == MovieList.LISTTYPE_COMPACT:
187                         ih1 = ((ih * 8) + 14) / 15 # 37 -> 20, round up
188                         lc, col = self.compactColumn[0], self.compactColumn[1]
189                         res.append(MultiContentEntryText(pos=(0, 0), size=(width-lc-2, ih1), font = 0, flags = RT_HALIGN_LEFT, text = txt))
190                         if self.tags:
191                                 res.append(MultiContentEntryText(pos=(width-col, ih1), size=(col, ih-ih1), font = 1, flags = RT_HALIGN_RIGHT, text = tags))
192                                 if service is not None:
193                                         res.append(MultiContentEntryText(pos=(col, ih1), size=(col, ih-ih1), font = 1, flags = RT_HALIGN_LEFT, text = service.getServiceName()))
194                         else:
195                                 if service is not None:
196                                         res.append(MultiContentEntryText(pos=(width-col, ih1), size=(col, ih-ih1), font = 1, flags = RT_HALIGN_RIGHT, text = service.getServiceName()))
197                         res.append(MultiContentEntryText(pos=(0, ih1), size=(col, ih-ih1), font=1, flags=RT_HALIGN_LEFT, text=begin_string))
198                         res.append(MultiContentEntryText(pos=(width-lc, 0), size=(lc, ih1), font=0, flags=RT_HALIGN_RIGHT, text=len))
199                 else:
200                         assert(self.list_type == MovieList.LISTTYPE_MINIMAL)
201                         if self.descr_state == MovieList.SHOW_DESCRIPTION:
202                                 dateSize = ih * 145 / 20   # 20 -> 145
203                                 res.append(MultiContentEntryText(pos=(0, 0), size=(width-dateSize, ih), font = 0, flags = RT_HALIGN_LEFT, text = txt))
204                                 res.append(MultiContentEntryText(pos=(width-dateSize, 4), size=(dateSize, ih), font=1, flags=RT_HALIGN_RIGHT, text=begin_string))
205                         else:
206                                 lenSize = ih * 75 / 20 # 20 -> 75
207                                 res.append(MultiContentEntryText(pos=(0, 0), size=(width-lenSize-2, ih), font = 0, flags = RT_HALIGN_LEFT, text = txt))
208                                 res.append(MultiContentEntryText(pos=(width-lenSize, 0), size=(lenSize, ih), font=0, flags=RT_HALIGN_RIGHT, text=len))
209                 
210                 return res
211
212         def moveToIndex(self, index):
213                 self.instance.moveSelectionTo(index)
214
215         def getCurrentIndex(self):
216                 return self.instance.getCurrentIndex()
217
218         def getCurrentEvent(self):
219                 l = self.l.getCurrentSelection()
220                 return l and l[0] and l[1] and l[1].getEvent(l[0])
221
222         def getCurrent(self):
223                 l = self.l.getCurrentSelection()
224                 return l and l[0]
225
226         GUI_WIDGET = eListbox
227
228         def postWidgetCreate(self, instance):
229                 instance.setContent(self.l)
230                 instance.selectionChanged.get().append(self.selectionChanged)
231
232         def preWidgetRemove(self, instance):
233                 instance.setContent(None)
234                 instance.selectionChanged.get().remove(self.selectionChanged)
235
236         def reload(self, root = None, filter_tags = None):
237                 if root is not None:
238                         self.load(root, filter_tags)
239                 else:
240                         self.load(self.root, filter_tags)
241                 self.l.setList(self.list)
242
243         def removeService(self, service):
244                 for l in self.list[:]:
245                         if l[0] == service:
246                                 self.list.remove(l)
247                 self.l.setList(self.list)
248
249         def __len__(self):
250                 return len(self.list)
251
252         def load(self, root, filter_tags):
253                 # this lists our root service, then building a 
254                 # nice list
255                 
256                 self.list = [ ]
257                 self.serviceHandler = eServiceCenter.getInstance()
258                 
259                 self.root = root
260                 list = self.serviceHandler.list(root)
261                 if list is None:
262                         print "listing of movies failed"
263                         list = [ ]      
264                         return
265                 tags = set()
266                 
267                 while 1:
268                         serviceref = list.getNext()
269                         if not serviceref.valid():
270                                 break
271                         if serviceref.flags & eServiceReference.mustDescent:
272                                 continue
273                 
274                         info = self.serviceHandler.info(serviceref)
275                         if info is None:
276                                 continue
277                         begin = info.getInfo(serviceref, iServiceInformation.sTimeCreate)
278                 
279                         # convert space-seperated list of tags into a set
280                         this_tags = info.getInfoString(serviceref, iServiceInformation.sTags).split(' ')
281                         if this_tags == ['']:
282                                 this_tags = []
283                         this_tags = set(this_tags)
284                         tags |= this_tags
285                 
286                         # filter_tags is either None (which means no filter at all), or 
287                         # a set. In this case, all elements of filter_tags must be present,
288                         # otherwise the entry will be dropped.                  
289                         if filter_tags is not None and not this_tags.issuperset(filter_tags):
290                                 continue
291                 
292                         self.list.append((serviceref, info, begin, -1))
293                 
294                 if self.sort_type == MovieList.SORT_ALPHANUMERIC:
295                         self.list.sort(key=self.buildAlphaNumericSortKey)
296                 else:
297                         # sort: key is 'begin'
298                         self.list.sort(key=lambda x: -x[2])
299                 
300                 # finally, store a list of all tags which were found. these can be presented
301                 # to the user to filter the list
302                 self.tags = tags
303
304         def buildAlphaNumericSortKey(self, x):
305                 ref = x[0]
306                 info = self.serviceHandler.info(ref)
307                 name = info and info.getName(ref)
308                 return (name and name.lower() or "", -x[2])
309
310         def moveTo(self, serviceref):
311                 count = 0
312                 for x in self.list:
313                         if x[0] == serviceref:
314                                 self.instance.moveSelectionTo(count)
315                                 return True
316                         count += 1
317                 return False
318         
319         def moveDown(self):
320                 self.instance.moveSelection(self.instance.moveDown)