Merge branch 'bug_486_add_service_event_progress_to_servicelist'
[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.MultiContent import MultiContentEntryText
14 from Components.Label import MultiColorLabel
15 from enigma import gFont, RT_HALIGN_LEFT, RT_HALIGN_RIGHT
16 from Tools.Directories import resolveFilename, SCOPE_PLUGINS
17
18 class TitleList(Screen, HelpableScreen):
19         skin = """
20                 <screen name="TitleList" position="center,center" size="560,470" title="DVD Tool" >
21                         <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
22                         <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
23                         <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
24                         <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
25                         <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;19" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
26                         <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;19" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
27                         <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;19" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
28                         <widget source="key_blue" render="Label" position="420,0" zPosition="1" size="140,40" font="Regular;19" halign="center" valign="center" backgroundColor="#18188b" transparent="1" />
29                         <widget source="title_label" render="Label" position="10,48" size="540,38" font="Regular;18" transparent="1" />
30                         <widget source="error_label" render="Label" position="10,48" size="540,296" zPosition="3" font="Regular;20" transparent="1" />
31                         <widget source="titles" render="Listbox" scrollbarMode="showOnDemand" position="10,86" size="546,296" zPosition="3" transparent="1" >
32                                 <convert type="TemplatedMultiContent">
33                                         {"template": [
34                                                         MultiContentEntryText(pos = (0, 0), size = (360, 20), font = 0, flags = RT_HALIGN_LEFT, text = 1), # index 1 Title,
35                                                         MultiContentEntryText(pos = (0, 20), size = (360, 17), font = 1, flags = RT_HALIGN_LEFT, text = 2), # index 2 description,
36                                                         MultiContentEntryText(pos = (366, 6), size = (152, 20), font = 1, flags = RT_HALIGN_RIGHT, text = 3), # index 3 channel,
37                                                         MultiContentEntryText(pos = (366, 20), size = (102, 17), font = 1, flags = RT_HALIGN_RIGHT, text = 4), # index 4 begin time,
38                                                         MultiContentEntryText(pos = (470, 20), size = (48, 20), font = 1, flags = RT_HALIGN_RIGHT, text = 5), # index 5 duration,
39                                                 ],
40                                         "fonts": [gFont("Regular", 20), gFont("Regular", 14)],
41                                         "itemHeight": 37
42                                         }
43                                 </convert>
44                         </widget>
45                         <ePixmap pixmap="skin_default/div-h.png" position="0,390" zPosition="10" size="560,2" />
46                         <ePixmap pixmap="skin_default/buttons/key_menu.png" position="10,394" size="35,25" alphatest="on" />
47                         <widget source="hint" render="Label" position="50,396" size="540,22" font="Regular;18" halign="left" />
48                         <widget name="medium_label"  position="10,420" size="540,22" font="Regular;18" halign="left" foregroundColors="#FFFFFF,#FFFF00,#FF0000" />
49                         <widget source="space_bar_single" render="Progress" position="10,446" size="270,24" borderWidth="1" zPosition="2" backgroundColor="#254f7497" />
50                         <widget source="space_label_single" render="Label" position="10,449" size="270,22" zPosition="3" font="Regular;18" halign="center" transparent="1" foregroundColor="#000000" />
51                         <widget source="space_bar_dual" render="Progress" position="10,446" size="540,24" borderWidth="1" backgroundColor="#254f7497" />
52                         <widget source="space_label_dual" render="Label" position="10,449" size="540,22" zPosition="2" font="Regular;18" halign="center" transparent="1" foregroundColor="#000000" />
53                         
54                 </screen>"""
55
56         def __init__(self, session, project = None):
57                 Screen.__init__(self, session)
58                 HelpableScreen.__init__(self)
59                 
60                 self["titleactions"] = HelpableActionMap(self, "DVDTitleList",
61                         {
62                                 "addTitle": (self.addTitle, _("Add a new title"), _("Add title")),
63                                 "titleProperties": (self.titleProperties, _("Properties of current title"), _("Title properties")),
64                                 "removeCurrentTitle": (self.removeCurrentTitle, _("Remove currently selected title"), _("Remove title")),
65                                 "settings": (self.settings, _("Collection settings"), _("Settings")),
66                                 "burnProject": (self.askBurnProject, _("Burn DVD"), _("Burn DVD")),
67                         })
68
69                 self["MovieSelectionActions"] = HelpableActionMap(self, "MovieSelectionActions",
70                         {
71                                 "contextMenu": (self.showMenu, _("menu")),
72                         })
73
74                 self["actions"] = ActionMap(["OkCancelActions"],
75                         {
76                                 "cancel": self.leave
77                         })
78
79                 self["key_red"] = StaticText()
80                 self["key_green"] = StaticText(_("Add title"))
81                 self["key_yellow"] = StaticText()
82                 self["key_blue"] = StaticText(_("Settings"))
83
84                 self["title_label"] = StaticText()
85                 self["error_label"] = StaticText()
86                 self["space_label_single"] = StaticText()
87                 self["space_label_dual"] = StaticText()
88                 self["hint"] = StaticText(_("Advanced Options"))
89                 self["medium_label"] = MultiColorLabel()
90                 self["space_bar_single"] = Progress()
91                 self["space_bar_dual"] = Progress()
92
93                 self["titles"] = List([])
94                 self.previous_size = 0
95                 if project is not None:
96                         self.project = project
97                 else:
98                         self.newProject()
99                 self.onLayoutFinish.append(self.layoutFinished)
100
101         def layoutFinished(self):
102                 self.setTitle(_("DVD Titlelist"))
103
104         def checkBackgroundJobs(self):
105                 for job in job_manager.getPendingJobs():
106                         print "type(job):", type(job)
107                         print "Process.DVDJob:", Process.DVDJob
108                         if type(job) == Process.DVDJob:
109                                 self.backgroundJob = job
110                                 return
111                 self.backgroundJob = None
112
113         def showMenu(self):
114                 menu = []
115                 self.checkBackgroundJobs()
116                 if self.backgroundJob:
117                         j = self.backgroundJob
118                         menu.append(("%s: %s (%d%%)" % (j.getStatustext(), j.name, int(100*j.progress/float(j.end))), self.showBackgroundJob))
119                 menu.append((_("DVD media toolbox"), self.toolbox))
120                 if self.project.settings.output.getValue() == "dvd":
121                         if len(self["titles"].list):
122                                 menu.append((_("Burn DVD"), self.burnProject))
123                 elif self.project.settings.output.getValue() == "iso":
124                         menu.append((_("Create DVD-ISO"), self.burnProject))
125                 menu.append((_("Burn existing image to DVD"), self.selectImage))
126                 if len(self["titles"].list):
127                         menu.append((_("Preview menu"), self.previewMenu))
128                         menu.append((_("Edit chapters of current title"), self.editTitle))
129                         menu.append((_("Reset and renumerate title names"), self.resetTitles))
130                 menu.append((_("Exit"), self.leave))
131                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
132
133         def menuCallback(self, choice):
134                 if choice:
135                         choice[1]()
136
137         def showBackgroundJob(self):
138                 job_manager.in_background = False
139                 self.session.openWithCallback(self.JobViewCB, JobView, self.backgroundJob)
140                 self.backgroundJob = None
141         
142         def titleProperties(self):
143                 if self.getCurrentTitle():
144                         self.session.openWithCallback(self.updateTitleList, TitleProperties.TitleProperties, self, self.project, self["titles"].getIndex())
145
146         def selectImage(self):
147                 self.session.openWithCallback(self.burnISO, ProjectSettings.FileBrowser, "image", self.project.settings)
148
149         def newProject(self):
150                 self.project = DVDProject.DVDProject()
151                 if self.loadTemplate():
152                         self.project.session = self.session
153                         self.settingsCB()
154
155         def addTitle(self):
156                 from Screens.MovieSelection import MovieSelection
157                 from Components.ActionMap import HelpableActionMap
158                 class DVDMovieSelection(MovieSelection):
159                         skin = """<screen name="DVDMovieSelection" position="center,center" size="560,445" title="Select a movie">
160                                 <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
161                                 <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
162                                 <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
163                                 <widget source="key_red" render="Label" position="0,0" zPosition="1" size="140,40" font="Regular;19" halign="center" valign="center" backgroundColor="#9f1313" transparent="1" />
164                                 <widget source="key_green" render="Label" position="140,0" zPosition="1" size="140,40" font="Regular;19" halign="center" valign="center" backgroundColor="#1f771f" transparent="1" />
165                                 <widget source="key_yellow" render="Label" position="280,0" zPosition="1" size="140,40" font="Regular;19" halign="center" valign="center" backgroundColor="#a08500" transparent="1" />
166                                 <widget name="waitingtext" position="0,45" size="560,395" zPosition="4" font="Regular;22" halign="center" valign="center" />
167                                 <widget name="list" position="5,40" size="550,375" zPosition="2" scrollbarMode="showOnDemand" />
168                                 <widget name="DescriptionBorder" pixmap="skin_default/border_eventinfo.png" position="0,316" zPosition="1" size="560,103" transparent="1" alphatest="on" />
169                                 <widget source="Service" render="Label" position="5,318" zPosition="1" size="480,35" font="Regular;17" foregroundColor="#cccccc">
170                                         <convert type="MovieInfo">ShortDescription</convert>
171                                 </widget>
172                                 <widget source="Service" render="Label" position="495,318" zPosition="1" size="60,22" font="Regular;17" halign="right">
173                                         <convert type="ServiceTime">Duration</convert>
174                                         <convert type="ClockToText">AsLength</convert>
175                                 </widget>
176                                 <widget source="Service" render="Label" position="380,337" zPosition="2" size="175,22" font="Regular;17" halign="right">
177                                         <convert type="MovieInfo">RecordServiceName</convert>
178                                 </widget>
179                                 <widget source="Service" render="Label" position="5,357" zPosition="1" size="550,58" font="Regular;19">
180                                         <convert type="EventName">ExtendedDescription</convert>
181                                 </widget>
182                                 <widget name="freeDiskSpace" position="10,425" size="540,20" font="Regular;19" valign="center" halign="right" />
183                         </screen>"""
184                         def __init__(self, session):
185                                 MovieSelection.__init__(self, session)
186                                 self["key_red"] = StaticText(_("Close"))
187                                 self["key_green"] = StaticText(_("Add"))
188                                 self["key_yellow"] = StaticText(_("Edit title"))
189                                 self["ColorActions"] = HelpableActionMap(self, "ColorActions",
190                                 {
191                                         "red": (self.close, _("Close title selection")),
192                                         "green": (self.insertWithoutEdit, ("insert without cutlist editor")),
193                                         "yellow": (self.movieSelected, _("Add a new title"))
194                                 })
195                         def updateTags(self):
196                                 pass
197                         def doContext(self):
198                                 print "context menu forbidden inside DVDBurn to prevent calling multiple instances"
199                         def insertWithoutEdit(self):
200                                 current = self.getCurrent()
201                                 if current is not None:
202                                         current.edit = False
203                                         self.close(current)
204                         def movieSelected(self):
205                                 current = self.getCurrent()
206                                 if current is not None:
207                                         current.edit = True
208                                         self.close(current)
209                 self.session.openWithCallback(self.selectedSource, DVDMovieSelection)
210
211         def selectedSource(self, source = None):
212                 if source is None:
213                         return None
214                 if not source.getPath().endswith(".ts"):
215                         self.session.open(MessageBox,text = _("You can only burn Dreambox recordings!"), type = MessageBox.TYPE_ERROR)
216                         return None
217                 t = self.project.addService(source)
218                 try:
219                         editor = source.edit
220                 except AttributeError:
221                         editor = True
222                 self.editTitle(t, editor)
223
224         def removeCurrentTitle(self):
225                 title = self.getCurrentTitle()
226                 self.removeTitle(title)
227         
228         def removeTitle(self, title):
229                 if title is not None:
230                         self.project.titles.remove(title)
231                         self.updateTitleList()
232
233         def toolbox(self):
234                 self.session.open(DVDToolbox.DVDToolbox)
235
236         def settings(self):
237                 self.session.openWithCallback(self.settingsCB, ProjectSettings.ProjectSettings, self.project)
238
239         def settingsCB(self, update=True):
240                 if not update:
241                         return
242                 self.updateTitleList()
243
244         def loadTemplate(self):
245                 filename = resolveFilename(SCOPE_PLUGINS)+"Extensions/DVDBurn/DreamboxDVD.ddvdp.xml"
246                 if self.project.load(filename):
247                         self["error_label"].setText("")
248                         return True
249                 else:
250                         self["error_label"].setText(self.project.error)
251                         return False
252
253         def askBurnProject(self):
254                 if len(self["titles"].list):
255                         self.session.openWithCallback(self.burnProject,MessageBox,text = _("Do you want to burn this collection to DVD medium?"), type = MessageBox.TYPE_YESNO)
256
257         def burnProject(self, answer=True):
258                 if not answer:
259                         return
260                 if self.project.settings.authormode.getValue() == "data_ts":
261                         job = Process.DVDdataJob(self.project)
262                         job_manager.AddJob(job)
263                         job_manager.in_background = False
264                         self.session.openWithCallback(self.JobViewCB, JobView, job)
265                 else:
266                         job = Process.DVDJob(self.project)
267                         job_manager.AddJob(job)
268                         job_manager.in_background = False
269                         self.session.openWithCallback(self.JobViewCB, JobView, job)
270
271         def burnISO(self, path, scope, configRef):
272                 if path:
273                         job = Process.DVDisoJob(self.project, path)
274                         job_manager.AddJob(job)
275                         job_manager.in_background = False
276                         self.session.openWithCallback(self.JobViewCB, JobView, job)
277
278         def JobViewCB(self, in_background):
279                 job_manager.in_background = in_background
280
281         def previewMenu(self):
282                 job = Process.DVDJob(self.project, menupreview=True)
283                 job_manager.in_background = False
284                 job_manager.AddJob(job)
285
286         def updateTitleList(self):
287                 list = [ ]
288                 for title in self.project.titles:
289                         list.append((title, title.properties.menutitle.getValue(), title.properties.menusubtitle.getValue(), title.DVBchannel, title.formatDVDmenuText("$D.$M.$Y, $T", 0), title.formatDVDmenuText("$l", 0)))
290                 self["titles"].list = list
291                 self.updateSize()
292                 if len(list):
293                         self["key_red"].text = _("Remove title")
294                         self["key_yellow"].text = _("Title properties")
295                         self["title_label"].text = _("Table of content for collection") + " \"" + self.project.settings.name.getValue() + "\":"
296                 else:
297                         self["key_red"].text = ""
298                         self["key_yellow"].text = ""
299                         self["title_label"].text = _("Please add titles to the compilation.")
300
301         def updateSize(self):
302                 size = self.project.size/(1024*1024)
303                 MAX_DL = self.project.MAX_DL-100
304                 MAX_SL = self.project.MAX_SL-100
305                 print "updateSize:", size, "MAX_DL:", MAX_DL, "MAX_SL:", MAX_SL
306                 if size > MAX_DL:
307                         percent = 100 * size / float(MAX_DL)
308                         self["space_label_dual"].text = "%d MB (%.2f%%)" % (size, percent)
309                         self["space_bar_dual"].value = int(percent)
310                         self["space_bar_single"].value = 100
311                         self["space_label_single"].text = ""
312                         self["medium_label"].setText(_("Exceeds dual layer medium!"))
313                         self["medium_label"].setForegroundColorNum(2)
314                         if self.previous_size < MAX_DL:
315                                 self.session.open(MessageBox,text = _("Exceeds dual layer medium!"), type = MessageBox.TYPE_ERROR)
316                 elif size > MAX_SL:
317                         percent = 100 * size / float(MAX_DL)
318                         self["space_label_dual"].text = "%d MB (%.2f%%)" % (size, percent)
319                         self["space_bar_dual"].value = int(percent)
320                         self["space_bar_single"].value = 100
321                         self["space_label_single"].text = ""
322                         self["medium_label"].setText(_("Required medium type:") + " " + _("DUAL LAYER DVD") + ", %d MB " % (MAX_DL - size) + _("free"))
323                         self["medium_label"].setForegroundColorNum(1)
324                         if self.previous_size < MAX_SL:
325                                 self.session.open(MessageBox, text = _("Your collection exceeds the size of a single layer medium, you will need a blank dual layer DVD!"), timeout = 10, type = MessageBox.TYPE_INFO)
326                 elif size < MAX_SL:
327                         percent = 100 * size / float(MAX_SL)
328                         self["space_label_single"].text = "%d MB (%.2f%%)" % (size, percent)
329                         self["space_bar_single"].value = int(percent)
330                         self["space_bar_dual"].value = 0
331                         self["space_label_dual"].text = ""
332                         self["medium_label"].setText(_("Required medium type:") + " " + _("SINGLE LAYER DVD") + ", %d MB " % (MAX_SL - size) + _("free"))
333                         self["medium_label"].setForegroundColorNum(0)
334                 self.previous_size = size
335
336         def getCurrentTitle(self):
337                 t = self["titles"].getCurrent()
338                 return t and t[0]
339
340         def editTitle(self, title = None, editor = True):
341                 t = title or self.getCurrentTitle()
342                 if t is not None:
343                         self.current_edit_title = t
344                         if editor:
345                                 self.session.openWithCallback(self.titleEditDone, TitleCutter.TitleCutter, t)
346                         else:
347                                 self.session.openWithCallback(self.titleEditDone, TitleCutter.CutlistReader, t)
348
349         def titleEditDone(self, cutlist):
350                 t = self.current_edit_title
351                 t.titleEditDone(cutlist)
352                 if t.VideoType != 0:
353                         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)
354                 else:
355                         self.updateTitleList()
356
357         def resetTitles(self):
358                 count = 0
359                 for title in self.project.titles:
360                         count += 1
361                         title.initDVDmenuText(count)
362                 self.updateTitleList()
363
364         def DVDformatCB(self, answer):
365                 t = self.current_edit_title
366                 if answer == True:
367                         self.project.settings.authormode.setValue("data_ts")
368                         self.updateTitleList()
369                 else:
370                         self.removeTitle(t)
371
372         def leave(self, close = False):
373                 if not len(self["titles"].list) or close:
374                         self.close()
375                 else:
376                         self.session.openWithCallback(self.exitCB, MessageBox,text = _("Your current collection will get lost!") + "\n" + _("Do you really want to exit?"), type = MessageBox.TYPE_YESNO)
377
378         def exitCB(self, answer):
379                 print "exitCB", answer
380                 if answer is not None and answer:
381                         self.close()