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