[MerlinSkinThemes] - add support for globals
[enigma2-plugins.git] / serienfilm / src / MovieSelection.py
1 # -*- coding: utf-8 -*-
2 from Screens.Screen import Screen
3 from Components.Button import Button
4 from Components.ActionMap import HelpableActionMap, ActionMap
5 from Components.MenuList import MenuList
6 from MovieList import MovieList
7 from Components.DiskInfo import DiskInfo
8 from Components.Pixmap import Pixmap
9 from Components.Label import Label
10 from Components.PluginComponent import plugins
11 from Components.config import config, ConfigSubsection, ConfigText, ConfigInteger, ConfigLocations, ConfigSet
12 from Components.Sources.ServiceEvent import ServiceEvent
13 from Components.UsageConfig import defaultMoviePath
14
15 from Plugins.Plugin import PluginDescriptor
16
17 from Screens.MessageBox import MessageBox
18 from Screens.ChoiceBox import ChoiceBox
19 from Screens.LocationBox import MovieLocationBox
20 from Screens.HelpMenu import HelpableScreen
21
22 from Tools.Directories import *
23 from Tools.BoundFunction import boundFunction
24
25 from enigma import eServiceReference, eServiceCenter, eTimer, eSize, iServiceInformation
26 from SerienFilm import EpiSepCfg
27
28 config.movielist.sfmoviesort = ConfigInteger(default=MovieList.SORT_RECORDED)
29 config.movielist.sflisttype = ConfigInteger(default=MovieList.LISTTYPE_MINIMAL)
30 config.movielist.sftimes = ConfigInteger(default=MovieList.SHOW_DURATION | MovieList.SHOW_DIRECTORIES)
31 config.movielist.sftitle_episode_separator = ConfigText(default=_(": "))
32
33 def setPreferredTagEditor(te):
34         global preferredTagEditor
35         try:
36                 if preferredTagEditor == None:
37                         preferredTagEditor = te
38                         print "Preferred tag editor changed to ", preferredTagEditor
39                 else:
40                         print "Preferred tag editor already set to ", preferredTagEditor
41                         print "ignoring ", te
42         except:
43                 preferredTagEditor = te
44                 print "Preferred tag editor set to ", preferredTagEditor
45
46 def getPreferredTagEditor():
47         global preferredTagEditor
48         return preferredTagEditor
49
50 setPreferredTagEditor(None)
51
52 class MovieContextMenu(Screen):
53         def __init__(self, session, csel, service):
54 #               print("[SF-Plugin] SF:MovieContextMenu init")
55                 Screen.__init__(self, session)
56                 self.csel = csel
57                 self.service = service
58
59                 self["actions"] = ActionMap(["OkCancelActions"],
60                         {
61                                 "ok": self.okbuttonClick,
62                                 "cancel": self.cancelClick
63                         })
64
65                 menu = [(_("delete..."), self.delete)]
66                 menu.extend([(p.description, boundFunction(self.execPlugin, p)) for p in plugins.getPlugins(PluginDescriptor.WHERE_MOVIELIST)])
67
68                 if config.movielist.sfmoviesort.value == MovieList.SORT_ALPHANUMERIC:
69                         menu.append((_("sort by date  (quick toggle by key 0)"), boundFunction(self.sortBy, MovieList.SORT_RECORDED)))
70                 else:
71                         menu.append((_("alphabetic sort  (quick toggle by key 0)"), boundFunction(self.sortBy, MovieList.SORT_ALPHANUMERIC)))
72
73                 menu.extend((
74                         (_("list style elaborately"), boundFunction(self.listType, MovieList.LISTTYPE_ORIGINAL)),
75                         (_("list style compact with service  (quick toggle by key 8)"), boundFunction(self.listType, MovieList.LISTTYPE_COMPACT_SERVICE)),
76                         (_("list style compact with tags  (quick toggle by key 8)"), boundFunction(self.listType, MovieList.LISTTYPE_COMPACT_TAGS)),
77                         (_("list style single line  (key = service, 8 = tags)"), boundFunction(self.listType, MovieList.LISTTYPE_MINIMAL))
78                 ))
79                 if config.movielist.sftimes.value & MovieList.SHOW_RECORDINGTIME:
80                         menu.append((_("hide recordingtime"), boundFunction(self.showTimes, MovieList.SHOW_RECORDINGTIME)))
81                 else:
82                         menu.append((_("show recordingtime"), boundFunction(self.showTimes, MovieList.SHOW_RECORDINGTIME)))
83                 if config.movielist.sftimes.value & MovieList.SHOW_DURATION:
84                         menu.append((_("hide duration"), boundFunction(self.showTimes, MovieList.SHOW_DURATION)))
85                 else:
86                         menu.append((_("show duration"), boundFunction(self.showTimes, MovieList.SHOW_DURATION)))
87                 menu.append((_("Configuration of the title:episode separator"), boundFunction(self.sfconfigure, None)))
88                 if config.movielist.sftimes.value & MovieList.SHOW_DIRECTORIES:
89                         menu.append((_("hide the red real directories"), boundFunction(self.showTimes, MovieList.SHOW_DIRECTORIES)))
90                 else:
91                         menu.append((_("show real directories in red"), boundFunction(self.showTimes, MovieList.SHOW_DIRECTORIES)))
92
93                 self["menu"] = MenuList(menu)
94
95         def okbuttonClick(self):
96                 self["menu"].getCurrent()[1]()
97
98         def cancelClick(self):
99                 self.close(False)
100
101         def sortBy(self, newType):
102                 config.movielist.sfmoviesort.value = newType
103                 self.csel.setSortType(newType)
104                 if not self.csel["list"].sortLists():   # no reload required if sflists sorted
105                         self.csel.reloadList()
106                 self.close()
107
108         def listType(self, newType):
109                 config.movielist.sflisttype.value = newType
110                 self.csel.toggletype = 0
111                 self.csel.setListType(newType)
112                 self.close()
113
114         def showTimes(self, newType):
115 #               print "[SF-Plugin] MovieContextMenu:showTimes"
116                 config.movielist.sftimes.value ^= newType
117                 self.csel.setShowTimes(config.movielist.sftimes.value)
118                 if newType == MovieList.SHOW_DIRECTORIES:
119                         self.csel.reloadList()
120 #               self.csel.updateDescription()
121                 self.close()
122
123         def sfconfigured(self, arg = None):
124 #               print "[SF-Plugin] MovieContextMenu.sfconfigure: arg = >%s<" % (arg)
125                 if config.movielist.sftitle_episode_separator.value != arg:
126                         config.movielist.sftitle_episode_separator.value = arg
127                         config.movielist.sftitle_episode_separator.save()
128                         self.csel.setTitleEpiSep(arg)
129
130         def sfconfigure(self, arg):
131                 self.session.openWithCallback(self.sfconfigured, EpiSepCfg, config.movielist.sftitle_episode_separator.value)
132
133         def execPlugin(self, plugin):
134                 plugin(session=self.session, service=self.service)
135
136         def delete(self):
137                 serviceHandler = eServiceCenter.getInstance()
138                 offline = serviceHandler.offlineOperations(self.service)
139                 info = serviceHandler.info(self.service)
140                 name = info and info.getName(self.service) or _("this recording")
141                 if self.service.type == (eServiceReference.idUser | eServiceReference.idDVB) and self.service.flags == eServiceReference.canDescent:
142                         self.virtlist = self.csel["list"].getVirtDirList(name)
143                         if self.virtlist:
144                                 self.session.openWithCallback(self.deleteVirtDirConfirmed, MessageBox,
145                                         _("Do you really want to delete series\n  %s\nwith %d movies?") % (self.virtlist[0][3][3], len(self.virtlist)-1))
146                         else:
147                                 self.session.openWithCallback(self.close, MessageBox, _("Please delete the files in this Directory!"), MessageBox.TYPE_ERROR)
148                         return
149                 dsc = info and info.getInfoString(self.service, iServiceInformation.sDescription)
150                 result = False
151                 if offline is not None:
152                         # simulate first
153                         if not offline.deleteFromDisk(1):
154                                 result = True
155                 if result == True:
156                         self.session.openWithCallback(self.deleteConfirmed, MessageBox, _("Do you really want to delete %s\n%s?") % (name, dsc or ""))
157                 else:
158                         self.session.openWithCallback(self.close, MessageBox, _("You cannot delete this!"), MessageBox.TYPE_ERROR)
159
160         def deleteVirtDirConfirmed(self, confirmed):
161                 if not confirmed:
162 #                       for l in self.virtlist[1:]:
163 #                               print "[SF-Plugin] MovieSelectin:deleteVirtDirConfirmed would delete " + l[3][2]
164                         return self.close()
165                 self.csel["list"].moveTo(self.service)  # put removeService in virtual Directory
166                 for l in self.virtlist[1:]:
167 #                       print "[SF-Plugin] MovieSelectin:deleteVirtDirConfirmed deletes " + (l[3][2])
168                         self.service = l[0]
169                         self.deleteConfirmed(True)
170
171         def deleteConfirmed(self, confirmed):
172                 if not confirmed:
173                         return self.close()
174                 
175                 serviceHandler = eServiceCenter.getInstance()
176                 offline = serviceHandler.offlineOperations(self.service)
177                 result = False
178                 if offline is not None:
179                         # really delete!
180                         if not offline.deleteFromDisk(0):
181                                 result = True
182                 
183                 if result == False:
184                         self.session.openWithCallback(self.close, MessageBox, _("Delete failed!"), MessageBox.TYPE_ERROR)
185                 else:
186                         self.csel["list"].removeService(self.service)
187                         self.csel["freeDiskSpace"].update()
188                         self.close()
189
190 class SelectionEventInfo:
191         def __init__(self):
192                 print "[SF-Plugin] SF:SelectionEventInfo init"
193                 self["Service"] = ServiceEvent()
194                 self.list.connectSelChanged(self.__selectionChanged)
195                 self.timer = eTimer()
196                 self.timer_conn = self.timer.timeout.connect(self.updateEventInfo)
197                 self.onShown.append(self.__selectionChanged)
198
199         def __selectionChanged(self):
200                 if self.execing:
201                         self.timer.start(100, True)
202
203         def updateEventInfo(self):
204                 serviceref = self.getCurrent()
205                 self["Service"].newService(serviceref)
206
207 class MovieSelection(Screen, HelpableScreen, SelectionEventInfo):
208         def __init__(self, session, selectedmovie = None):
209 #               print "[SF-Plugin] SF:MovieSelection.init, PWD=%s; selmv=%s" % (config.movielist.last_videodir.value, str(selectedmovie))
210                 Screen.__init__(self, session)
211                 HelpableScreen.__init__(self)
212
213                 self.tags = [ ]
214                 if selectedmovie:
215                         self.selected_tags = config.movielist.last_selected_tags.value
216                 else:
217                         self.selected_tags = None
218                 self.selected_tags_ele = None
219                 self.toggletype = 0
220
221                 self.movemode = False
222                 self.bouquet_mark_edit = False
223
224                 self.delayTimer = eTimer()
225                 self.delayTimer_conn = self.delayTimer.timeout.connect(self.updateHDDData)
226
227                 self["waitingtext"] = Label(_("Please wait... Loading list..."))
228
229                 # create optional description border and hide immediately
230                 self["DescriptionBorder"] = Pixmap()
231                 self["DescriptionBorder"].hide()
232
233                 if not fileExists(config.movielist.last_videodir.value):
234                         config.movielist.last_videodir.value = defaultMoviePath()
235                         config.movielist.last_videodir.save()
236 #                       print "[SF-Plugin] MovieSelection.MovieSelection: save" + config.movielist.last_videodir.value
237                 self.current_ref = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + config.movielist.last_videodir.value)
238
239                 self["list"] = MovieList(None,
240                         config.movielist.sflisttype.value,
241                         config.movielist.sfmoviesort.value,
242                         config.movielist.sftimes.value,
243                         config.movielist.sftitle_episode_separator.value,
244                         self)
245
246                 self.list = self["list"]
247                 self.selectedmovie = selectedmovie
248
249                 # Need list for init
250                 SelectionEventInfo.__init__(self)
251
252                 self["key_red"] = Button(_("All"))
253                 self["key_green"] = Button("")
254                 self["key_yellow"] = Button("")
255                 self["key_blue"] = Button("")
256
257                 self["freeDiskSpace"] = self.diskinfo = DiskInfo(config.movielist.last_videodir.value, DiskInfo.FREE, update=False)
258
259                 if config.usage.setup_level.index >= 2: # expert+
260                         self["InfobarActions"] = HelpableActionMap(self, "InfobarActions", 
261                                 {
262                                         "showMovies": (self.doPathSelect, _("select the movie path")),
263                                 })
264
265
266                 self["MovieSelectionActions"] = HelpableActionMap(self, "MovieSelectionActions",
267                         {
268                                 "contextMenu": (self.doContext, _("menu")),
269                                 "showEventInfo": (self.showEventInformation, _("show event details")),
270                         })
271
272                 self["ColorActions"] = HelpableActionMap(self, "ColorActions",
273                         {
274                                 "red": (self.showAll, _("show all")),
275                                 "green": (self.showTagsFirst, _("show first selected tag")),
276                                 "yellow": (self.showTagsSecond, _("show second selected tag")),
277                                 "blue": (self.showTagsSelect, _("show tag menu")),
278                         })
279
280                 self["OkCancelActions"] = HelpableActionMap(self, "OkCancelActions",
281                         {
282                                 "cancel": (self.abort, _("exit movielist")),
283                                 "ok": (self.movieSelected, _("select movie")),
284                         })
285
286                 self["NumberActions"] = HelpableActionMap(self, "SetupActions",
287                         {
288                                 "0": (self.toggleSort, _("Toggle date / alphabetic sort mode")),
289                                 "deleteBackward": (self.moveToIndexStrt, _("Jump to listbegin")),
290                                 "deleteForward": (self.moveToIndexEnd, _("Jump to listend")),
291                                 "5": (self.toggleMinimal, _("Toggle style minimal / compact")),
292                                 "8": (self.toggleTags, _("Toggle description / tags display")),
293                         })
294
295
296                 self.onShown.append(self.go)
297                 self.onLayoutFinish.append(self.saveListsize)
298                 self.inited = False
299
300         def toggleSort(self):
301                 self["list"].toggleSort()
302
303         def toggleMinimal(self):
304                 self.toggleTags(config.movielist.sflisttype.value & MovieList.LISTTYPE_COMPACT_TAGS or MovieList.LISTTYPE_COMPACT_SERVICE)
305
306         def toggleTags(self, toggletype = MovieList.LISTTYPE_COMPACT):
307                 if self.toggletype == toggletype:
308                         self.toggletype = 0
309                 else:
310                         self.toggletype = toggletype
311                 self["list"].setListType(config.movielist.sflisttype.value ^ self.toggletype)
312
313         def moveToIndexStrt(self):
314                 self["list"].moveToIndex(0)
315
316         def moveToIndexEnd(self):
317                 self["list"].moveToIndex(-1)
318
319         def updateDescription(self):
320 #               print "[SF-Plugin] MovieSelection.updateDescription DescriptionBorder height =" + str(self["DescriptionBorder"].instance.size().height())
321                 self["DescriptionBorder"].show()
322                 self["list"].instance.resize(eSize(self.listWidth, self.listHeight-self["DescriptionBorder"].instance.size().height()))
323
324         def showEventInformation(self):
325                 from Screens.EventView import EventViewSimple
326                 from ServiceReference import ServiceReference
327                 evt = self["list"].getCurrentEvent()
328                 if evt:
329                         self.session.open(EventViewSimple, evt, ServiceReference(self.getCurrent()))
330
331         def go(self):
332                 if not self.inited:
333                 # ouch. this should redraw our "Please wait..."-text.
334                 # this is of course not the right way to do this.
335                         self.delayTimer.start(10, 1)
336                         self.inited=True
337
338         def saveListsize(self):
339                         listsize = self["list"].instance.size()
340                         self.listWidth = listsize.width()
341                         self.listHeight = listsize.height()
342                         self.updateDescription()
343
344         def updateHDDData(self):
345                 self.reloadList(self.selectedmovie)
346                 self["waitingtext"].visible = False
347
348         def moveTo(self):
349                 self["list"].moveTo(self.selectedmovie)
350
351         def getCurrent(self):
352                 return self["list"].getCurrent()
353
354         def movieSelected(self):
355                 current = self.getCurrent()
356                 if current is not None:
357                         dirname = self["list"].playDirectory(current)   # dont feed dirs to MoviePlayer
358                         if dirname is None:
359                                 self.saveconfig()
360                                 self.close(current)                     # and play movie
361                         elif dirname:
362                                 self.gotFilename(dirname)       # change to existing directory
363
364         def doContext(self):
365                 current = self.getCurrent()
366                 if current is not None:
367                         self.session.open(MovieContextMenu, self, current)
368
369         def abort(self):
370                 self.saveconfig()
371                 self.close(None)
372
373         def saveconfig(self):
374                 config.movielist.last_selected_tags.value = self.selected_tags
375                 config.movielist.sfmoviesort.save()
376                 config.movielist.sflisttype.save()
377                 config.movielist.sftimes.save()
378
379         def getTagDescription(self, tag):
380                 # TODO: access the tag database
381                 return tag
382
383         def updateTags(self):
384                 # get a list of tags available in this list
385                 self.tags = list(self["list"].tags)
386
387                 if not self.tags:
388                         # by default, we do not display any filtering options
389                         self.tag_first = ""
390                         self.tag_second = ""
391                 else:
392                         tmp = config.movielist.first_tags.value
393                         if tmp in self.tags:
394                                 self.tag_first = tmp
395                         else:
396                                 self.tag_first = "<"+_("Tag 1")+">"
397                         tmp = config.movielist.second_tags.value
398                         if tmp in self.tags:
399                                 self.tag_second = tmp
400                         else:
401                                 self.tag_second = "<"+_("Tag 2")+">"
402                 self["key_green"].text = self.tag_first
403                 self["key_yellow"].text = self.tag_second
404                 
405                 # the rest is presented in a list, available on the
406                 # fourth ("blue") button
407                 if self.tags:
408                         self["key_blue"].text = _("Tags")+"..."
409                 else:
410                         self["key_blue"].text = ""
411
412         def setListType(self, type):
413                 self["list"].setListType(type)
414
415         def setShowTimes(self, val):
416                 self["list"].setShowTimes(val)
417
418         def setSortType(self, type):
419                 self["list"].setSortType(type)
420
421         def setTitleEpiSep(self, sftitle_episode_separator):
422                 self["list"].setTitleEpiSep(sftitle_episode_separator)
423                 self.reloadList()
424
425         def reloadList(self, sel = None, home = False):
426                 if not fileExists(config.movielist.last_videodir.value):
427                         path = defaultMoviePath()
428                         config.movielist.last_videodir.value = path
429                         config.movielist.last_videodir.save()
430                         self.current_ref = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + path)
431                         self["freeDiskSpace"].path = path
432                 if sel is None:
433                         sel = self.getCurrent()
434                 self["list"].reload(self.current_ref, self.selected_tags)
435                 title = _("Recorded files...")
436                 if config.usage.setup_level.index >= 2: # expert+
437                         title += "  " + config.movielist.last_videodir.value
438                 if self.selected_tags is not None:
439                         title += " - " + ','.join(self.selected_tags)
440                 self.setTitle(title)
441                 self["list"].saveTitle(title)
442 #               print "[SF-Plugin] MovieSelection:setTitle(%s)" % (str(title))
443                 if not (sel and self["list"].moveTo(sel)):
444                         if home:
445                                 self["list"].moveToIndex(0)
446                 self.updateTags()
447                 self["freeDiskSpace"].update()
448
449         def doPathSelect(self):
450                 self.session.openWithCallback(
451                         self.gotFilename,
452                         MovieLocationBox,
453                         _("Please select the movie path..."),
454                         config.movielist.last_videodir.value
455                 )
456
457         def gotFilename(self, res):
458                 if res is not None and res is not config.movielist.last_videodir.value:
459                         if fileExists(res):
460                                 config.movielist.last_videodir.value = res
461                                 config.movielist.last_videodir.save()
462 #                               print "[SF-Plugin] MovieSelection.gotFilename: save" + res
463                                 self.current_ref = eServiceReference("2:0:1:0:0:0:0:0:0:0:" + res)
464                                 self["freeDiskSpace"].path = res
465                                 self.reloadList(home = True)
466                         else:
467                                 self.session.open(
468                                         MessageBox,
469                                         _("Directory %s nonexistent.") % (res),
470                                         type = MessageBox.TYPE_ERROR,
471                                         timeout = 5
472                                         )
473
474         def showAll(self):
475                 self.selected_tags_ele = None
476                 self.selected_tags = None
477                 self.reloadList(home = True)
478
479         def showTagsN(self, tagele):
480                 if not self.tags:
481                         self.showTagWarning()
482                 elif not tagele or (self.selected_tags and tagele.value in self.selected_tags) or not tagele.value in self.tags:
483                         self.showTagsMenu(tagele)
484                 else:
485                         self.selected_tags_ele = tagele
486                         self.selected_tags = set([tagele.value])
487                         self.reloadList(home = True)
488
489         def showTagsFirst(self):
490                 self.showTagsN(config.movielist.first_tags)
491
492         def showTagsSecond(self):
493                 self.showTagsN(config.movielist.second_tags)
494
495         def showTagsSelect(self):
496                 self.showTagsN(None)
497
498         def tagChosen(self, tag):
499                 if tag is not None:
500                         self.selected_tags = set([tag[0]])
501                         if self.selected_tags_ele:
502                                 self.selected_tags_ele.value = tag[0]
503                                 self.selected_tags_ele.save()
504                         self.reloadList(home = True)
505
506         def showTagsMenu(self, tagele):
507                 self.selected_tags_ele = tagele
508                 list = [(tag, self.getTagDescription(tag)) for tag in self.tags ]
509                 self.session.openWithCallback(self.tagChosen, ChoiceBox, title=_("Please select tag to filter..."), list = list)
510
511         def showTagWarning(self):
512                 self.session.open(MessageBox, _("No tags are set on these movies."), MessageBox.TYPE_ERROR)
513