change disc size determination and tweak dual layer growisofs arguments
[enigma2.git] / 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.askBurnProject, _("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                         if len(self["titles"].list):
98                                 menu.append((_("Burn DVD"), self.burnProject))
99                 elif self.project.settings.output.getValue() == "iso":
100                         menu.append((_("Create DVD-ISO"), self.burnProject))
101                 menu.append((_("Burn existing image to DVD"), self.selectImage))
102                 menu.append((_("Edit chapters of current title"), self.editTitle))
103                 menu.append((_("Reset and renumerate title names"), self.resetTitles))
104                 menu.append((_("Exit"), self.leave))
105                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
106
107         def menuCallback(self, choice):
108                 if choice:
109                         choice[1]()
110
111         def showBackgroundJob(self):
112                 job_manager.in_background = False
113                 self.session.openWithCallback(self.JobViewCB, JobView, self.backgroundJob)
114                 self.backgroundJob = None
115         
116         def titleProperties(self):
117                 if self.getCurrentTitle():
118                         self.session.openWithCallback(self.updateTitleList, TitleProperties.TitleProperties, self, self.project, self["titles"].getIndex())
119
120         def selectImage(self):
121                 self.session.openWithCallback(self.burnISO, ProjectSettings.FileBrowser, "image", self.project.settings)
122
123         def newProject(self):
124                 self.project = DVDProject.DVDProject()
125                 if self.loadTemplate():
126                         self.project.session = self.session
127                         self.settingsCB()
128
129         def addTitle(self):
130                 from Screens.MovieSelection import MovieSelection
131                 from Components.Button import Button
132                 from Components.ActionMap import HelpableActionMap
133                 class MovieSelectionNoMenu(MovieSelection):
134                         def __init__(self, session):
135                                 MovieSelection.__init__(self, session)
136                                 self.skinName = "MovieSelection"
137                                 self["key_red"] = Button(_("Edit title"))
138                                 self["key_green"] = Button(_("Add"))
139                                 self["ColorActions"] = HelpableActionMap(self, "ColorActions",
140                                 {
141                                         "red": (self.movieSelected, _("Add a new title")),
142                                         "green": (self.insertWithoutEdit, ("insert without cutlist editor"))
143                                 })
144                         def updateTags(self):
145                                 pass
146                         def doContext(self):
147                                 print "context menu forbidden inside DVDBurn to prevent calling multiple instances"
148                         def insertWithoutEdit(self):
149                                 current = self.getCurrent()
150                                 if current is not None:
151                                         current.edit = False
152                                         self.close(current)
153                         def movieSelected(self):
154                                 current = self.getCurrent()
155                                 if current is not None:
156                                         current.edit = True
157                                         self.close(current)
158                 self.session.openWithCallback(self.selectedSource, MovieSelectionNoMenu)
159
160         def selectedSource(self, source):
161                 if source is None:
162                         return None
163                 t = self.project.addService(source)
164                 try:
165                         editor = source.edit
166                 except AttributeError:
167                         editor = True
168                 self.editTitle(t, editor)
169
170         def removeCurrentTitle(self):
171                 title = self.getCurrentTitle()
172                 self.removeTitle(title)
173         
174         def removeTitle(self, title):
175                 if title is not None:
176                         self.project.titles.remove(title)
177                         self.updateTitleList()
178
179         def toolbox(self):
180                 self.session.open(DVDToolbox.DVDToolbox)
181
182         def settings(self):
183                 self.session.openWithCallback(self.settingsCB, ProjectSettings.ProjectSettings, self.project)
184
185         def settingsCB(self, update=True):
186                 if not update:
187                         return
188                 self["title_label"].text = _("Table of content for collection") + " \"" + self.project.settings.name.getValue() + "\":"
189
190         def loadTemplate(self):
191                 filename = resolveFilename(SCOPE_PLUGINS)+"Extensions/DVDBurn/DreamboxDVD.ddvdp.xml"
192                 if self.project.load(filename):
193                         self["error_label"].hide()
194                         return True
195                 else:
196                         self["error_label"].text = self.project.error
197                         self["error_label"].show()
198                         return False
199
200         def askBurnProject(self):
201                 if len(self["titles"].list):
202                         self.session.openWithCallback(self.burnProject,MessageBox,text = _("Do you want to burn this collection to DVD medium?"), type = MessageBox.TYPE_YESNO)
203
204         def burnProject(self, answer=True):
205                 if not answer:
206                         return
207                 if self.project.settings.authormode.getValue() == "data_ts":
208                         job = Process.DVDdataJob(self.project)
209                         job_manager.AddJob(job)
210                         job_manager.in_background = False
211                         self.session.openWithCallback(self.JobViewCB, JobView, job)
212                 else:
213                         job = Process.DVDJob(self.project)
214                         job_manager.AddJob(job)
215                         job_manager.in_background = False
216                         self.session.openWithCallback(self.JobViewCB, JobView, job)
217
218         def burnISO(self, path, scope, configRef):
219                 if path:
220                         job = Process.DVDisoJob(self.project, path)
221                         job_manager.AddJob(job)
222                         job_manager.in_background = False
223                         self.session.openWithCallback(self.JobViewCB, JobView, job)
224
225         def JobViewCB(self, in_background):
226                 job_manager.in_background = in_background
227
228         def previewMenu(self):
229                 job = Process.DVDJob(self.project, menupreview=True)
230                 job_manager.in_background = False
231                 job_manager.AddJob(job)
232                 
233         def updateTitleList(self):
234                 res = [ ]
235                 for title in self.project.titles:
236                         a = [ title, (eListboxPythonMultiContent.TYPE_TEXT, 0, 5, 500, 25, 0, RT_HALIGN_LEFT, title.properties.menutitle.getValue())  ]
237                         res.append(a)
238                 self["titles"].list = res
239                 self.updateSize()
240                 if len(res):
241                         self["key_red"].text = _("Remove title")
242                         self["key_yellow"].text = _("Title properties")
243                 else:
244                         self["key_red"].text = ""
245                         self["key_yellow"].text = ""
246
247         def updateSize(self):
248                 size = self.project.size
249                 if size > self.project.MAX_DL:
250                         percent = 100 * size / float(self.project.MAX_DL)
251                         self["space_label"].text = "%d MB - " % size + _("exceeds dual layer medium!") + " (%.2f%% " % (100-percent) + _("free") + ")"
252                         self["space_bar"].value = int(percent)
253                         if self.previous_size < self.project.MAX_DL:
254                                 self.session.open(MessageBox,text = _("exceeds dual layer medium!"), type = MessageBox.TYPE_ERROR)
255                 elif size > self.project.MAX_SL:
256                         percent = 100 * size / float(self.project.MAX_DL)
257                         self["space_label"].text = "%d MB  " % size + _("of a DUAL layer medium used.") + " (%.2f%% " % (100-percent) + _("free") + ")"
258                         self["space_bar"].value = int(percent)
259                         if self.previous_size < self.project.MAX_SL:
260                                 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)
261                 elif size < self.project.MAX_SL:
262                         percent = 100 * size / float(self.project.MAX_SL)
263                         self["space_label"].text = "%d MB " % size + _("of a SINGLE layer medium used.") + " (%.2f%% " % (100-percent) + _("free") + ")"
264                         self["space_bar"].value = int(percent)
265                 self.previous_size = size
266
267         def getCurrentTitle(self):
268                 t = self["titles"].getCurrent()
269                 return t and t[0]
270
271         def editTitle(self, title = None, editor = True):
272                 t = title or self.getCurrentTitle()
273                 if t is not None:
274                         self.current_edit_title = t
275                         if editor:
276                                 self.session.openWithCallback(self.titleEditDone, TitleCutter.TitleCutter, t)
277                         else:
278                                 self.session.openWithCallback(self.titleEditDone, TitleCutter.CutlistReader, t)
279
280         def titleEditDone(self, cutlist):
281                 t = self.current_edit_title
282                 t.initDVDmenuText(self.project,len(self.project.titles))
283                 t.cuesheet = cutlist
284                 t.produceFinalCuesheet()
285                 if t.VideoType != 0:
286                         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)
287                 else:
288                         self.updateTitleList()
289
290         def resetTitles(self):
291                 count = 0
292                 for title in self.project.titles:
293                         count += 1
294                         title.initDVDmenuText(self.project,count)
295                 self.updateTitleList()
296
297         def DVDformatCB(self, answer):
298                 t = self.current_edit_title
299                 if answer == True:
300                         self.project.settings.authormode.setValue("data_ts")
301                         self.updateTitleList()
302                 else:
303                         self.removeTitle(t)
304
305         def leave(self):
306                 self.close()