catch full medium error, implement loading of project files, allow creating dvds...
[enigma2.git] / lib / python / Plugins / Extensions / DVDBurn / TitleList.py
1 import DVDProject, TitleList, TitleCutter
2
3 from Screens.Screen import Screen
4 from Screens.ChoiceBox import ChoiceBox
5 from Screens.InputBox import InputBox
6 from Screens.MessageBox import MessageBox
7 from Screens.HelpMenu import HelpableScreen
8 from Components.ActionMap import HelpableActionMap, ActionMap
9 from Components.Sources.List import List
10 from Components.Sources.StaticText import StaticText
11 from Components.Sources.Progress import Progress
12 from Components.FileList import FileList
13 from enigma import eListboxPythonMultiContent, gFont, RT_HALIGN_LEFT
14 from Tools.Directories import resolveFilename, SCOPE_PLAYLIST
15
16 class WaitBox(MessageBox):
17         def __init__(self, session, callback):
18                 MessageBox.__init__(self, session, text=_("please wait, loading picture..."), type = MessageBox.TYPE_INFO)
19                 self.skinName = "MessageBox"
20                 self.CB = callback
21                 self.onShown.append(self.runCB)
22
23         def ok(self):
24                 pass
25
26         def runCB(self):
27                 from enigma import eTimer
28                 self.delayTimer = eTimer()
29                 self.delayTimer.callback.append(self.CB)
30                 self.delayTimer.start(10,1)
31
32 class FileBrowser(Screen, HelpableScreen):
33         skin = """
34         <screen name="FileBrowser" position="100,100" size="520,376" title="DVD File Browser" >
35                 <widget name="filelist" position="0,0" size="520,376" scrollbarMode="showOnDemand" />
36         </screen>"""
37         def __init__(self, session, currDir = None, projectBrowser = False):
38                 Screen.__init__(self, session)
39                 HelpableScreen.__init__(self)
40                 self.projectBrowser = projectBrowser
41                 if not currDir:
42                         currDir = "/"
43
44                 if projectBrowser:
45                         self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(ddvdp\.xml)")
46                 else:
47                         self.filelist = FileList(currDir, matchingPattern = "(?i)^.*\.(jpeg|jpg|jpe|png|bmp)")
48                 self["filelist"] = self.filelist
49
50                 self["FilelistActions"] = ActionMap(["OkCancelActions"],
51                         {
52                                 "ok": self.ok,
53                                 "cancel": self.exit
54                         })
55
56         def ok(self):
57                 if self.filelist.canDescent():
58                         self.filelist.descent()
59                 else:
60                         ret = self["filelist"].getCurrentDirectory() + self["filelist"].getFilename()
61                         self.close(ret,self.projectBrowser)
62
63         def exit(self):
64                 self.close(None)
65
66
67 class TitleList(Screen):
68         skin = """
69                 <screen position="90,83" size="560,445" title="DVD Tool" >
70                     <ePixmap pixmap="skin_default/buttons/red.png" position="0,0" size="140,40" alphatest="on" />
71                     <ePixmap pixmap="skin_default/buttons/green.png" position="140,0" size="140,40" alphatest="on" />
72                     <ePixmap pixmap="skin_default/buttons/yellow.png" position="280,0" size="140,40" alphatest="on" />
73                     <ePixmap pixmap="skin_default/buttons/blue.png" position="420,0" size="140,40" alphatest="on" />
74                     <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" />
75                     <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" />
76                     <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" />
77                     <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" />
78                     <widget source="title_label" render="Label" position="6,48" size="540,38" font="Regular;18" />
79                     <widget source="titles" render="Listbox" scrollbarMode="showOnDemand" position="10,86" size="540,312">
80                         <convert type="StaticMultiList" />
81                     </widget>
82                     <widget source="space_bar" render="Progress" position="10,410" size="540,26" borderWidth="1" backgroundColor="#254f7497" />
83                     <widget source="space_label" render="Label" position="40,414" size="480,22" zPosition="2" font="Regular;18" halign="center" transparent="1" foregroundColor="#000000" />
84                 </screen>"""
85
86         def __init__(self, session, project = None):
87                 Screen.__init__(self, session)
88                 
89                 self["titleactions"] = HelpableActionMap(self, "DVDTitleList",
90                         {
91                                 "addTitle": (self.addTitle, _("Add a new title"), _("Add title")),
92                                 "editTitle": (self.editTitle, _("Edit chapters of current title"), _("Edit title")),
93                                 "removeCurrentTitle": (self.removeCurrentTitle, _("Remove currently selected title"), _("Remove title")),
94                                 "saveProject": (self.saveProject, _("Save current collection to disk"), _("Save")),
95                                 "burnProject": (self.burnProject, _("Burn DVD"), _("Burn DVD")),
96                         })
97
98                 self["MovieSelectionActions"] = HelpableActionMap(self, "MovieSelectionActions",
99                         {
100                                 "contextMenu": (self.showMenu, _("menu")),
101                         })
102
103                 self["key_red"] = StaticText(_("Add title"))
104                 self["key_green"] = StaticText(_("Edit title"))
105                 self["key_yellow"] = StaticText(_("Remove title"))
106                 self["key_blue"] = StaticText(_("Save"))
107
108                 self["title_label"] = StaticText()
109                 self["space_label"] = StaticText()
110                 self["space_bar"] = Progress()
111
112                 self["actions"] = ActionMap(["OkCancelActions"],
113                         {
114                                 "cancel": self.leave
115                         })
116
117                 #Action("addTitle", self.addTitle)
118                 
119                 if project is not None:
120                         self.project = project
121                 else:
122                         self.newProject()
123
124                 self["titles"] = List(list = [ ], enableWrapAround = True, item_height=30, fonts = [gFont("Regular", 20)])
125                 self.updateTitleList()
126                 self.updateCollectionName()
127                                 
128                 #self["addTitle"] = ActionButton("titleactions", "addTitle")
129                 #self["editTitle"] = ActionButton("titleactions", "editTitle")
130                 #self["removeCurrentTitle"] = ActionButton("titleactions", "removeCurrentTitle")
131                 #self["saveProject"] = ActionButton("titleactions", "saveProject")
132                 #self["burnProject"] = ActionButton("titleactions", "burnProject")
133                 
134         def showMenu(self):
135                 menu = []
136                 menu.append((_("Add a new title"), "addtitle"));
137                 menu.append((_("Remove title"), "removetitle"));
138                 menu.append((_("Edit chapters of current title"), "edittitle"));
139                 menu.append((_("Set collection name"), "setname"));
140                 menu.append((_("Set menu background"), "setbackground"));
141                 menu.append((_("Save current collection to disk"), "save"));
142                 menu.append((_("Load saved collection from disk"), "load"));
143                 menu.append((_("Preview menu"), "previewMenu"));
144                 menu.append((_("Burn DVD"), "burn"));
145                 self.session.openWithCallback(self.menuCallback, ChoiceBox, title="", list=menu)
146
147         def menuCallback(self, choice):
148                 if choice is None:
149                         return
150
151                 if choice[1] == "removetitle":
152                         self.removeCurrentTitle()
153                 elif choice[1] == "addtitle":
154                         self.addTitle()
155                 elif choice[1] == "edittitle":
156                         self.editTitle()
157                 elif choice[1] == "setname":
158                         self.setName()
159                 elif choice[1] == "setbackground":
160                         self.showFileBrowser(False)
161                 elif choice[1] == "save":
162                         self.saveProject()
163                 elif choice[1] == "load":
164                         self.showFileBrowser(True)
165                 elif choice[1] == "previewMenu":
166                         self.previewMenu()
167                 elif choice[1] == "burn":
168                         self.burnProject()
169
170         def setName(self):
171                 self.session.openWithCallback(self.setNameCallback, InputBox, title=_("Set collection name"), text=self.project.name, maxSize=False, visible_width = 56)
172                 
173         def setNameCallback(self, name):
174                 if name is not None:
175                         self.project.name = name
176                         self.updateCollectionName()
177
178         def newProject(self):
179                 self.project = DVDProject.DVDProject()
180                 if self.loadProject():
181                         self.project.session = self.session
182                         self.updateCollectionName()
183
184         def updateCollectionName(self):
185                 self["title_label"].text = _("Table of content for collection") + " \"" + self.project.name + "\":"
186
187         def addTitle(self):
188                 from Screens.MovieSelection import MovieSelection
189                 class MovieSelectionNoMenu(MovieSelection):
190                         def __init__(self, session):
191                                 MovieSelection.__init__(self, session)
192                                 self.skinName = "MovieSelection"
193
194                         def doContext(self):
195                                 print "context menu forbidden inside DVDBurn to prevent calling multiple instances"
196                                 
197                 self.session.openWithCallback(self.selectedSource, MovieSelectionNoMenu)
198
199         def selectedSource(self, source):
200                 if source is None:
201                         return None
202                 t = self.project.addService(source)
203                 self.editTitle(t, readOnly=True)
204
205         def removeCurrentTitle(self):
206                 title = self.getCurrentTitle()
207                 if title is not None:
208                         self.project.titles.remove(title)
209                         self.updateTitleList()
210
211         def saveProject(self):
212                 self.project.saveProject(resolveFilename(SCOPE_PLAYLIST))
213
214         def loadProject(self, filename=None):
215                 if not filename:
216                         filename = resolveFilename(SCOPE_PLAYLIST)+"DreamboxDVDtemplate.ddvdp.xml"
217                 if self.project.loadProject(filename):
218                         return True
219                 else:
220                         try:
221                                 self.session.open(MessageBox,self.project.error,MessageBox.TYPE_ERROR)
222                         except:
223                                 self["title_label"].text = self.project.error
224                                 print self.project.error
225                         return False
226
227         def burnProject(self):
228                 self.project.waitboxref = self.project.session.open(WaitBox,self.burnProjectCB)
229
230         def burnProjectCB(self):
231                 import Process
232                 job = Process.Burn(self.session, self.project)
233                 from Screens.TaskView import JobView
234                 self.session.open(JobView, job)
235
236         def previewMenu(self):
237                 self.project.waitboxref = self.project.session.open(WaitBox,self.previewMenuCB)
238                 
239         def previewMenuCB(self):
240                 import Process
241                 job = Process.PreviewMenu(self.session, self.project)
242
243         def updateTitleList(self):
244                 res = [ ]
245                 totalsize = 0
246                 for title in self.project.titles:
247                         a = [ title, (eListboxPythonMultiContent.TYPE_TEXT, 0, 10, 500, 50, 0, RT_HALIGN_LEFT, title.name)  ]
248                         res.append(a)
249                         totalsize += title.estimatedDiskspace
250                 self["titles"].list = res
251                 self.updateSize(totalsize)
252                 
253         def updateSize(self, totalsize):
254                 size = int((totalsize/1024)/1024)
255                 max_SL = 4370
256                 max_DL = 7950
257                 if size > max_DL:
258                         percent = 100 * size / float(max_DL)
259                         self["space_label"].text = "%d MB - " % size + _("exceeds dual layer medium!") + " (%.2f%% " % (100-percent) + _("free") + ")"
260                         self["space_bar"].value = int(percent)
261                 elif size > max_SL:
262                         percent = 100 * size / float(max_DL)
263                         self["space_label"].text = "%d MB  " % size + _("of a DUAL layer medium used.") + " (%.2f%% " % (100-percent) + _("free") + ")"
264                         self["space_bar"].value = int(percent)
265                 elif size < max_SL:
266                         percent = 100 * size / float(max_SL)
267                         self["space_label"].text = "%d MB " % size + _("of a SINGLE layer medium used.") + " (%.2f%% " % (100-percent) + _("free") + ")"
268                         self["space_bar"].value = int(percent)
269
270         def getCurrentTitle(self):
271                 t = self["titles"].getCurrent()
272                 return t and t[0]
273
274         def editTitle(self, title = None, readOnly = False):
275                 t = title or self.getCurrentTitle()
276                 if t is not None:
277                         self.current_edit_title = t
278                         if readOnly:
279                                 self.session.openWithCallback(self.titleEditDone, TitleCutter.CutlistReader, t)
280                         else:
281                                 self.session.openWithCallback(self.titleEditDone, TitleCutter.TitleCutter, t)
282
283         def titleEditDone(self, cutlist):
284                 t = self.current_edit_title
285                 t.cuesheet = cutlist
286                 t.produceFinalCuesheet()
287                 print "title edit of %s done, resulting cutlist:" % (t.source.toString()), t.cutlist, "chaptermarks:", t.chaptermarks
288                 self.updateTitleList()
289
290         def leave(self):
291                 self.close()
292
293         def showFileBrowser(self, projectBrowser=False):
294                 if projectBrowser:
295                         currDir = resolveFilename(SCOPE_PLAYLIST)
296                 else:
297                         currDir = self.project.menubg
298                         if len(currDir) > 1:
299                                 currDir = (currDir.rstrip("/").rsplit("/",1))[0]
300                 self.session.openWithCallback(self.FileBrowserClosed, FileBrowser, currDir, projectBrowser)
301         
302         def FileBrowserClosed(self, path, projectBrowser=False):
303                 if projectBrowser:
304                         self.loadProject(path)
305                 else:
306                         self.project.menubg = path