some service scan improovements
[enigma2.git] / lib / python / Screens / MovieSelection.py
1 from Screen import Screen
2 from Components.Button import Button
3 from Components.ActionMap import HelpableActionMap, ActionMap
4 from Components.MenuList import MenuList
5 from Components.MovieList import MovieList
6 from Components.DiskInfo import DiskInfo
7 from Components.Pixmap import Pixmap
8 from Components.Label import Label
9 from Components.PluginComponent import plugins
10 from Components.config import config, ConfigSubsection, ConfigText, ConfigInteger, ConfigLocations
11 from Components.Sources.ServiceEvent import ServiceEvent
12
13 from Plugins.Plugin import PluginDescriptor
14
15 from Screens.MessageBox import MessageBox
16 from Screens.ChoiceBox import ChoiceBox
17 from Screens.LocationBox import MovieLocationBox
18 from Screens.HelpMenu import HelpableScreen
19
20 from Tools.Directories import *
21 from Tools.BoundFunction import boundFunction
22
23 from enigma import eServiceReference, eServiceCenter, eTimer, eSize
24
25 config.movielist = ConfigSubsection()
26 config.movielist.moviesort = ConfigInteger(default=MovieList.SORT_RECORDED)
27 config.movielist.listtype = ConfigInteger(default=MovieList.LISTTYPE_ORIGINAL)
28 config.movielist.description = ConfigInteger(default=MovieList.HIDE_DESCRIPTION)
29 config.movielist.last_videodir = ConfigText(default=resolveFilename(SCOPE_HDD))
30 config.movielist.last_timer_videodir = ConfigText(default=resolveFilename(SCOPE_HDD))
31 config.movielist.videodirs = ConfigLocations(default=[resolveFilename(SCOPE_HDD)])
32
33 class MovieContextMenu(Screen):
34         def __init__(self, session, csel, service):
35                 Screen.__init__(self, session)
36                 self.csel = csel
37                 self.service = service
38
39                 self["actions"] = ActionMap(["OkCancelActions"],
40                         {
41                                 "ok": self.okbuttonClick,
42                                 "cancel": self.cancelClick
43                         })
44
45                 menu = [(_("delete..."), self.delete)]
46                 
47                 for p in plugins.getPlugins(PluginDescriptor.WHERE_MOVIELIST):
48                         menu.append((p.description, boundFunction(self.execPlugin, p)))
49                 
50                 if config.movielist.moviesort.value == MovieList.SORT_ALPHANUMERIC:
51                         menu.append((_("sort by date"), boundFunction(self.sortBy, MovieList.SORT_RECORDED)))
52                 else:
53                         menu.append((_("alphabetic sort"), boundFunction(self.sortBy, MovieList.SORT_ALPHANUMERIC)))
54                 
55                 menu.append((_("list style default"), boundFunction(self.listType, MovieList.LISTTYPE_ORIGINAL)))
56                 menu.append((_("list style compact with description"), boundFunction(self.listType, MovieList.LISTTYPE_COMPACT_DESCRIPTION)))
57                 menu.append((_("list style compact"), boundFunction(self.listType, MovieList.LISTTYPE_COMPACT)))
58                 menu.append((_("list style single line"), boundFunction(self.listType, MovieList.LISTTYPE_MINIMAL)))
59                 
60                 if config.movielist.description.value == MovieList.SHOW_DESCRIPTION:
61                         menu.append((_("hide extended description"), boundFunction(self.showDescription, MovieList.HIDE_DESCRIPTION)))
62                 else:
63                         menu.append((_("show extended description"), boundFunction(self.showDescription, MovieList.SHOW_DESCRIPTION)))
64                 self["menu"] = MenuList(menu)
65
66         def okbuttonClick(self):
67                 self["menu"].getCurrent()[1]()
68
69         def cancelClick(self):
70                 self.close(False)
71
72         def sortBy(self, newType):
73                 config.movielist.moviesort.value = newType
74                 self.csel.selectedmovie = self.csel.getCurrent()
75                 self.csel.setSortType(newType)
76                 self.csel.reloadList()
77                 self.csel.moveTo()
78                 self.close()
79
80         def listType(self, newType):
81                 config.movielist.listtype.value = newType
82                 self.csel.setListType(newType)
83                 self.csel.list.redrawList()
84                 self.close()
85
86         def showDescription(self, newType):
87                 config.movielist.description.value = newType
88                 self.csel.setDescriptionState(newType)
89                 self.csel.updateDescription()
90                 self.close()
91
92         def execPlugin(self, plugin):
93                 plugin(session=self.session, service=self.service)
94
95         def delete(self):
96                 serviceHandler = eServiceCenter.getInstance()
97                 offline = serviceHandler.offlineOperations(self.service)
98                 info = serviceHandler.info(self.service)
99                 name = info and info.getName(self.service) or _("this recording")
100                 result = False
101                 if offline is not None:
102                         # simulate first
103                         if not offline.deleteFromDisk(1):
104                                 result = True
105                 if result == True:
106                         self.session.openWithCallback(self.deleteConfirmed, MessageBox, _("Do you really want to delete %s?") % (name))
107                 else:
108                         self.session.openWithCallback(self.close, MessageBox, _("You cannot delete this!"), MessageBox.TYPE_ERROR)
109
110         def deleteConfirmed(self, confirmed):
111                 if not confirmed:
112                         return self.close()
113                 
114                 serviceHandler = eServiceCenter.getInstance()
115                 offline = serviceHandler.offlineOperations(self.service)
116                 result = False
117                 if offline is not None:
118                         # really delete!
119                         if not offline.deleteFromDisk(0):
120                                 result = True
121                 
122                 if result == False:
123                         self.session.openWithCallback(self.close, MessageBox, _("Delete failed!"), MessageBox.TYPE_ERROR)
124                 else:
125                         self.csel["list"].removeService(self.service)
126                         self.csel["freeDiskSpace"].update()
127                         self.close()
128
129 class SelectionEventInfo:
130         def __init__(self):
131                 self["Service"] = ServiceEvent()
132                 self.list.connectSelChanged(self.__selectionChanged)
133                 self.timer = eTimer()
134                 self.timer.callback.append(self.updateEventInfo)
135                 self.onShown.append(self.__selectionChanged)
136
137         def __selectionChanged(self):
138                 if self.execing and config.movielist.description.value == MovieList.SHOW_DESCRIPTION:
139                         self.timer.start(100, True)
140
141         def updateEventInfo(self):
142                 serviceref = self.getCurrent()
143                 self["Service"].newService(serviceref)
144
145 class MovieSelection(Screen, HelpableScreen, SelectionEventInfo):
146         def __init__(self, session, selectedmovie = None):
147                 Screen.__init__(self, session)
148                 HelpableScreen.__init__(self)
149
150                 self.tags = [ ]
151                 self.selected_tags = None
152
153                 self.movemode = False
154                 self.bouquet_mark_edit = False
155
156                 self.delayTimer = eTimer()
157                 self.delayTimer.callback.append(self.updateHDDData)
158
159                 self["waitingtext"] = Label(_("Please wait... Loading list..."))
160
161                 # create optional description border and hide immediately
162                 self["DescriptionBorder"] = Pixmap()
163                 self["DescriptionBorder"].hide()
164
165                 if not pathExists(config.movielist.last_videodir.value):
166                         config.movielist.last_videodir.value = resolveFilename(SCOPE_HDD)
167                         config.movielist.last_videodir.save()
168                 self.current_ref = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + config.movielist.last_videodir.value)
169
170                 self["list"] = MovieList(None,
171                         config.movielist.listtype.value,
172                         config.movielist.moviesort.value,
173                         config.movielist.description.value)
174
175                 self.list = self["list"]
176                 self.selectedmovie = selectedmovie
177
178                 # Need list for init
179                 SelectionEventInfo.__init__(self)
180
181                 self["key_red"] = Button(_("All..."))
182                 self["key_green"] = Button("")
183                 self["key_yellow"] = Button("")
184                 self["key_blue"] = Button("")
185
186                 self["freeDiskSpace"] = self.diskinfo = DiskInfo(config.movielist.last_videodir.value, DiskInfo.FREE, update=False)
187
188                 if config.usage.setup_level.index >= 2: # expert+
189                         self["InfobarActions"] = HelpableActionMap(self, "InfobarActions", 
190                                 {
191                                         "showMovies": (self.doPathSelect, _("select the movie path")),
192                                 })
193
194
195                 self["MovieSelectionActions"] = HelpableActionMap(self, "MovieSelectionActions",
196                         {
197                                 "contextMenu": (self.doContext, _("menu")),
198                                 "showEventInfo": (self.showEventInformation, _("show event details")),
199                         })
200
201                 self["ColorActions"] = HelpableActionMap(self, "ColorActions",
202                         {
203                                 "red": (self.showAll, _("show all")),
204                                 "green": (self.showTagsFirst, _("show first tag")),
205                                 "yellow": (self.showTagsSecond, _("show second tag")),
206                                 "blue": (self.showTagsMenu, _("show tag menu")),
207                         })
208
209                 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
210                         {
211                                 "cancel": (self.abort, _("exit movielist")),
212                                 "ok": (self.movieSelected, _("select movie")),
213                         })
214
215                 self.onShown.append(self.go)
216                 self.onLayoutFinish.append(self.saveListsize)
217                 self.inited = False
218
219         def updateDescription(self):
220                 if config.movielist.description.value == MovieList.SHOW_DESCRIPTION:
221                         self["DescriptionBorder"].show()
222                         self["list"].instance.resize(eSize(self.listWidth, self.listHeight-self["DescriptionBorder"].instance.size().height()))
223                 else:
224                         self["Service"].newService(None)
225                         self["DescriptionBorder"].hide()
226                         self["list"].instance.resize(eSize(self.listWidth, self.listHeight))
227
228         def showEventInformation(self):
229                 from Screens.EventView import EventViewSimple
230                 from ServiceReference import ServiceReference
231                 evt = self["list"].getCurrentEvent()
232                 if evt:
233                         self.session.open(EventViewSimple, evt, ServiceReference(self.getCurrent()))
234
235         def go(self):
236                 if not self.inited:
237                 # ouch. this should redraw our "Please wait..."-text.
238                 # this is of course not the right way to do this.
239                         self.delayTimer.start(10, 1)
240                         self.inited=True
241
242         def saveListsize(self):
243                         listsize = self["list"].instance.size()
244                         self.listWidth = listsize.width()
245                         self.listHeight = listsize.height()
246                         self.updateDescription()
247
248         def updateHDDData(self):
249                 self.reloadList()
250                 if self.selectedmovie is not None:
251                         self.moveTo()
252                 self["waitingtext"].visible = False
253                 self.updateTags()
254
255         def moveTo(self):
256                 self["list"].moveTo(self.selectedmovie)
257
258         def getCurrent(self):
259                 return self["list"].getCurrent()
260
261         def movieSelected(self):
262                 current = self.getCurrent()
263                 if current is not None:
264                         self.saveconfig()
265                         self.close(current)
266
267         def doContext(self):
268                 current = self.getCurrent()
269                 if current is not None:
270                         self.session.open(MovieContextMenu, self, current)
271
272         def abort(self):
273                 self.saveconfig()
274                 self.close(None)
275
276         def saveconfig(self):
277                 config.movielist.moviesort.save()
278                 config.movielist.listtype.save()
279                 config.movielist.description.save()
280
281         def getTagDescription(self, tag):
282                 # TODO: access the tag database
283                 return tag
284
285         def updateTags(self):
286                 # get a list of tags available in this list
287                 self.tags = list(self["list"].tags)
288                 
289                 # by default, we do not display any filtering options
290                 self.tag_first = ""
291                 self.tag_second = ""
292                 
293                 # when tags are present, however, the first two are 
294                 # directly mapped to the second, third ("green", "yellow") buttons
295                 if len(self.tags) > 0:
296                         self.tag_first = self.getTagDescription(self.tags[0])
297                 
298                 if len(self.tags) > 1:
299                         self.tag_second = self.getTagDescription(self.tags[1])
300                 
301                 self["key_green"].text = self.tag_first
302                 self["key_yellow"].text = self.tag_second
303                 
304                 # the rest is presented in a list, available on the
305                 # fourth ("blue") button
306                 if len(self.tags) > 2:
307                         self["key_blue"].text = _("Other...")
308                 else:
309                         self["key_blue"].text = ""
310
311         def setListType(self, type):
312                 self["list"].setListType(type)
313
314         def setDescriptionState(self, val):
315                 self["list"].setDescriptionState(val)
316
317         def setSortType(self, type):
318                 self["list"].setSortType(type)
319
320         def reloadList(self):
321                 if not pathExists(config.movielist.last_videodir.value):
322                         path = resolveFilename(SCOPE_HDD)
323                         config.movielist.last_videodir.value = path
324                         config.movielist.last_videodir.save()
325                         self.current_ref = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + path)
326                         self["freeDiskSpace"].path = path
327                 self["list"].reload(self.current_ref, self.selected_tags)
328                 title = _("Recorded files...")
329                 if self.selected_tags is not None:
330                         title += " - " + ','.join(self.selected_tags)
331                 if config.usage.setup_level.index >= 2: # expert+
332                         title += "  " + config.movielist.last_videodir.value
333                 self.setTitle(title)
334                 self["freeDiskSpace"].update()
335
336         def doPathSelect(self):
337                 self.session.openWithCallback(
338                         self.gotFilename,
339                         MovieLocationBox,
340                         _("Please select the movie path..."),
341                         config.movielist.last_videodir.value
342                 )
343
344         def gotFilename(self, res):
345                 if res is not None and res is not config.movielist.last_videodir.value:
346                         if pathExists(res):
347                                 config.movielist.last_videodir.value = res
348                                 config.movielist.last_videodir.save()
349                                 self.current_ref = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + res)
350                                 self["freeDiskSpace"].path = res
351                                 self.reloadList()
352                         else:
353                                 self.session.open(
354                                         MessageBox,
355                                         _("Directory %s nonexistent.") % (res),
356                                         type = MessageBox.TYPE_ERROR,
357                                         timeout = 5
358                                         )
359
360         def showAll(self):
361                 self.selected_tags = None
362                 self.reloadList()
363
364         def showTagsN(self, n):
365                 if len(self.tags) < n:
366                         self.showTagWarning()
367                 else:
368                         print "select tag #%d, %s, %s" % (n, self.tags[n - 1], ','.join(self.tags))
369                         self.selected_tags = set([self.tags[n - 1]])
370                         self.reloadList()
371
372         def showTagsFirst(self):
373                 self.showTagsN(1)
374
375         def showTagsSecond(self):
376                 self.showTagsN(2)
377
378         def tagChosen(self, tag):
379                 if tag is not None:
380                         self.selected_tags = set([tag[0]])
381                         self.reloadList()
382
383         def showTagsMenu(self):
384                 if len(self.tags) < 3:
385                         self.showTagWarning()
386                 else:
387                         list = [(tag, self.getTagDescription(tag)) for tag in self.tags ]
388                         self.session.openWithCallback(self.tagChosen, ChoiceBox, title=_("Please select keyword to filter..."), list = list)
389
390         def showTagWarning(self):
391                 # TODO
392                 self.session.open(MessageBox, _("You need to define some keywords first!\nPress the menu-key to define keywords.\nDo you want to define keywords now?"), MessageBox.TYPE_ERROR)