improve usability: hide some advanced options below expert, clear out and resort...
[vuplus_dvbapp] / lib / python / Plugins / Extensions / DVDBurn / TitleList.py
1 import DVDProject, TitleList, TitleCutter, TitleProperties, ProjectSettings, DVDToolbox, Process
2 from Screens.Screen import Screen
3 from Screens.ChoiceBox import ChoiceBox
4 from Screens.InputBox import InputBox
5 from Screens.MessageBox import MessageBox
6 from Screens.HelpMenu import HelpableScreen
7 from Screens.TaskView import JobView
8 from Components.Task import job_manager
9 from Components.ActionMap import HelpableActionMap, ActionMap
10 from Components.Sources.List import List
11 from Components.Sources.StaticText import StaticText
12 from Components.Sources.Progress import Progress
13 from Components.Label import Label
14 from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT
15 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
16
17 class TitleList(Screen, HelpableScreen):
18         skin = """
19                 <screen position="90,83" size="560,445" title="DVD Tool" >
20                     <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
21                     <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
22                     <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
23                     <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
24                     <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
25                     <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
26                     <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
27                     <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;20" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
28                     <widget source="title_label" render="Label" position="10,48" size="540,38" font="Regular;18" />
29                     <widget name="error_label" position="10,48" size="540,395" zPosition="3" font="Regular;20" />
30                     <widget source="titles" render="Listbox" scrollbarMode="showOnDemand" position="10,86" size="540,312">
31                         <convert type="StaticMultiList" />
32                     </widget>
33                     <widget source="space_bar" render="Progress" position="10,410" size="540,26" borderWidth="1" backgroundColor="#254f7497" />
34                     <widget source="space_label" render="Label" position="40,414" size="480,22" zPosition="2" font="Regular;18" halign="center" transparent="1" foregroundColor="#000000" />
35                 </screen>"""
36
37         def __init__(self, session, project = None):
38                 Screen.__init__(self, session)
39                 HelpableScreen.__init__(self)
40                 
41                 self["titleactions"] = HelpableActionMap(self, "DVDTitleList",
42                         {
43                                 "addTitle": (self.addTitle, _("Add a new title"), _("Add title")),
44                                 "titleProperties": (self.titleProperties, _("Properties of current title"), _("Title properties")),
45                                 "removeCurrentTitle": (self.removeCurrentTitle, _("Remove currently selected title"), _("Remove title")),
46                                 "settings": (self.settings, _("Collection settings"), _("Settings")),
47                                 "burnProject": (self.burnProject, _("Burn DVD"), _("Burn DVD")),
48                         })
49
50                 self["MovieSelectionActions"] = HelpableActionMap(self, "MovieSelectionActions",
51                         {
52                                 "contextMenu": (self.showMenu, _("menu")),
53                         })
54
55                 self["actions"] = ActionMap(["OkCancelActions"],
56                         {
57                                 "cancel": self.leave
58                         })
59
60                 self["key_red"] = StaticText()
61                 self["key_green"] = StaticText(_("Add title"))
62                 self["key_yellow"] = StaticText()
63                 self["key_blue"] = StaticText(_("Settings"))
64
65                 self["title_label"] = StaticText()
66                 self["error_label"] = Label("")
67                 self["space_label"] = StaticText()
68                 self["space_bar"] = Progress()
69
70                 if project is not None:
71                         self.project = project
72                 else:
73                         self.newProject()
74
75                 self["titles"] = List(list = [ ], enableWrapAround = True, item_height=30, fonts = [gFont("Regular", 20)])
76                 self.updateTitleList()
77                 self.previous_size = 0
78
79         def checkBackgroundJobs(self):
80                 for job in job_manager.getPendingJobs():
81                         print "type(job):", type(job)
82                         print "Process.DVDJob:", Process.DVDJob
83                         if type(job) == Process.DVDJob:
84                                 self.backgroundJob = job
85                                 return
86                 self.backgroundJob = None
87
88         def showMenu(self):
89                 menu = []
90                 self.checkBackgroundJobs()
91                 if self.backgroundJob:
92                         j = self.backgroundJob
93                         menu.append(("%s: %s (%d%%)" % (j.getStatustext(), j.name, int(100*j.progress/float(j.end))), self.showBackgroundJob))
94                 menu.append((_("DVD media toolbox"), self.toolbox))
95                 menu.append((_("Preview menu"), self.previewMenu))
96                 if self.project.settings.output.getValue() == "dvd":
97                         menu.append((_("Burn DVD"), self.burnProject))
98                 elif self.project.settings.output.getValue() == "iso":
99                         menu.append((_("Create DVD-ISO"), self.burnProject))
100                 menu.append((_("Burn existing image to DVD"), self.selectImage))
101                 menu.append((_("Edit chapters of current title"), self.editTitle))
102                 menu.append((_("Reset and renumerate title names"), self.resetTitles))
103                 menu.append((_("Exit"), self.leave))
104                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
105
106         def menuCallback(self, choice):
107                 if choice:
108                         choice[1]()
109
110         def showBackgroundJob(self):
111                 job_manager.in_background = False
112                 self.session.openWithCallback(self.JobViewCB, JobView, self.backgroundJob)
113                 self.backgroundJob = None
114         
115         def titleProperties(self):
116                 if self.getCurrentTitle():
117                         self.session.openWithCallback(self.updateTitleList, TitleProperties.TitleProperties, self, self.project, self["titles"].getIndex())
118
119         def selectImage(self):
120                 self.session.openWithCallback(self.burnISO, ProjectSettings.FileBrowser, "image", self.project.settings)
121
122         def newProject(self):
123                 self.project = DVDProject.DVDProject()
124                 if self.loadTemplate():
125                         self.project.session = self.session
126                         self.settingsCB()
127
128         def addTitle(self):
129                 from Screens.MovieSelection import MovieSelection
130                 from Components.Button import Button
131                 from Components.ActionMap import HelpableActionMap
132                 class MovieSelectionNoMenu(MovieSelection):
133                         def __init__(self, session):
134                                 MovieSelection.__init__(self, session)
135                                 self.skinName = "MovieSelection"
136                                 self["key_red"] = Button(_("Edit title"))
137                                 self["key_green"] = Button(_("Add"))
138                                 self["ColorActions"] = HelpableActionMap(self, "ColorActions",
139                                 {
140                                         "red": (self.movieSelected, _("Add a new title")),
141                                         "green": (self.insertWithoutEdit, ("insert without cutlist editor"))
142                                 })
143                         def updateTags(self):
144                                 pass
145                         def doContext(self):
146                                 print "context menu forbidden inside DVDBurn to prevent calling multiple instances"
147                         def insertWithoutEdit(self):
148                                 current = self.getCurrent()
149                                 if current is not None:
150                                         current.edit = False
151                                         self.close(current)
152                         def movieSelected(self):
153                                 current = self.getCurrent()
154                                 if current is not None:
155                                         current.edit = True
156                                         self.close(current)
157                 self.session.openWithCallback(self.selectedSource, MovieSelectionNoMenu)
158
159         def selectedSource(self, source):
160                 if source is None:
161                         return None
162                 t = self.project.addService(source)
163                 try:
164                         editor = source.edit
165                 except AttributeError:
166                         editor = True
167                 self.editTitle(t, editor)
168
169         def removeCurrentTitle(self):
170                 title = self.getCurrentTitle()
171                 self.removeTitle(title)
172         
173         def removeTitle(self, title):
174                 if title is not None:
175                         self.project.titles.remove(title)
176                         self.updateTitleList()
177
178         def toolbox(self):
179                 self.session.open(DVDToolbox.DVDToolbox)
180
181         def settings(self):
182                 self.session.openWithCallback(self.settingsCB, ProjectSettings.ProjectSettings, self.project)
183
184         def settingsCB(self, update=True):
185                 if not update:
186                         return
187                 self["title_label"].text = _("Table of content for collection") + " \"" + self.project.settings.name.getValue() + "\":"
188
189         def loadTemplate(self):
190                 filename = resolveFilename(SCOPE_PLUGINS)+"Extensions/DVDBurn/DreamboxDVD.ddvdp.xml"
191                 if self.project.load(filename):
192                         self["error_label"].hide()
193                         return True
194                 else:
195                         self["error_label"].text = self.project.error
196                         self["error_label"].show()
197                         return False
198
199         def burnProject(self):
200                 if self.project.settings.authormode.getValue() == "data_ts":
201                         job = Process.DVDdataJob(self.project)
202                         job_manager.AddJob(job)
203                         job_manager.in_background = False
204                         self.session.openWithCallback(self.JobViewCB, JobView, job)
205                 else:
206                         job = Process.DVDJob(self.project)
207                         job_manager.AddJob(job)
208                         job_manager.in_background = False
209                         self.session.openWithCallback(self.JobViewCB, JobView, job)
210
211         def burnISO(self, path, scope):
212                 if path:
213                         job = Process.DVDisoJob(self.project, path)
214                         job_manager.AddJob(job)
215                         job_manager.in_background = False
216                         self.session.openWithCallback(self.JobViewCB, JobView, job)
217
218         def JobViewCB(self, in_background):
219                 job_manager.in_background = in_background
220
221         def previewMenu(self):
222                 job = Process.DVDJob(self.project, menupreview=True)
223                 job_manager.in_background = False
224                 job_manager.AddJob(job)
225                 
226         def updateTitleList(self):
227                 res = [ ]
228                 totalsize = 0
229                 for title in self.project.titles:
230                         a = [ title, (eListboxPythonMultiContent.TYPE_TEXT, 0, 5, 500, 25, 0, RT_HALIGN_LEFT, title.properties.menutitle.getValue())  ]
231                         res.append(a)
232                         totalsize += title.estimatedDiskspace
233                 self["titles"].list = res
234                 self.updateSize(totalsize)
235                 if len(res):
236                         self["key_red"].text = _("Remove title")
237                         self["key_yellow"].text = _("Title properties")
238                 else:
239                         self["key_red"].text = ""
240                         self["key_yellow"].text = ""
241
242         def updateSize(self, totalsize):
243                 size = int((totalsize/1024)/1024)
244                 max_SL = 4370
245                 max_DL = 7950
246                 if size > max_DL:
247                         percent = 100 * size / float(max_DL)
248                         self["space_label"].text = "%d MB - " % size + _("exceeds dual layer medium!") + " (%.2f%% " % (100-percent) + _("free") + ")"
249                         self["space_bar"].value = int(percent)
250                         if self.previous_size < max_DL:
251                                 self.session.open(MessageBox,text = _("exceeds dual layer medium!"), type = MessageBox.TYPE_ERROR)
252                 elif size > max_SL:
253                         percent = 100 * size / float(max_DL)
254                         self["space_label"].text = "%d MB  " % size + _("of a DUAL layer medium used.") + " (%.2f%% " % (100-percent) + _("free") + ")"
255                         self["space_bar"].value = int(percent)
256                         if self.previous_size < max_SL:
257                                 self.session.open(MessageBox,text = _("Your collection exceeds the size of a single layer medium, you will need a blank dual layer DVD!"), type = MessageBox.TYPE_INFO)
258                 elif size < max_SL:
259                         percent = 100 * size / float(max_SL)
260                         self["space_label"].text = "%d MB " % size + _("of a SINGLE layer medium used.") + " (%.2f%% " % (100-percent) + _("free") + ")"
261                         self["space_bar"].value = int(percent)
262                 self.previous_size = size
263
264         def getCurrentTitle(self):
265                 t = self["titles"].getCurrent()
266                 return t and t[0]
267
268         def editTitle(self, title = None, editor = True):
269                 t = title or self.getCurrentTitle()
270                 if t is not None:
271                         self.current_edit_title = t
272                         if editor:
273                                 self.session.openWithCallback(self.titleEditDone, TitleCutter.TitleCutter, t)
274                         else:
275                                 self.session.openWithCallback(self.titleEditDone, TitleCutter.CutlistReader, t)
276
277         def titleEditDone(self, cutlist):
278                 t = self.current_edit_title
279                 t.initDVDmenuText(self.project,len(self.project.titles))
280                 t.cuesheet = cutlist
281                 t.produceFinalCuesheet()
282                 if t.VideoType != 0:
283                         self.session.openWithCallback(self.DVDformatCB,MessageBox,text = _("The DVD standard doesn't support H.264 (HDTV) video streams. Do you want to create a Dreambox format data DVD (which will not play in stand-alone DVD players) instead?"), type = MessageBox.TYPE_YESNO)
284                 else:
285                         self.updateTitleList()
286
287         def resetTitles(self):
288                 count = 0
289                 for title in self.project.titles:
290                         count += 1
291                         title.initDVDmenuText(self.project,count)
292                 self.updateTitleList()
293
294         def DVDformatCB(self, answer):
295                 t = self.current_edit_title
296                 if answer == True:
297                         self.project.settings.authormode.setValue("data_ts")
298                         self.updateTitleList()
299                 else:
300                         self.removeTitle(t)
301
302         def leave(self):
303                 self.close()