1 /***************************************************************************
2 * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) *
4 * This program is free software; you can redistribute it and/or modify *
5 * it under the terms of the GNU General Public License as published by *
6 * the Free Software Foundation; either version 2 of the License, or *
7 * (at your option) any later version. *
9 * This program is distributed in the hope that it will be useful, *
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
12 * GNU General Public License for more details. *
14 * You should have received a copy of the GNU General Public License *
15 * along with this program; if not, write to the *
16 * Free Software Foundation, Inc., *
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA *
18 ***************************************************************************/
21 #include "dvdwizard.h"
22 #include "dvdwizardvob.h"
23 #include "kdenlivesettings.h"
24 #include "profilesdialog.h"
26 #include "monitormanager.h"
28 #include <KStandardDirs>
30 #include <KFileDialog>
31 #include <kmimetype.h>
32 #include <KIO/NetAccess>
33 #include <KMessageBox>
36 #include <QApplication>
38 #include <QDomDocument>
40 #include <QGridLayout>
43 DvdWizard::DvdWizard(const QString &url, QWidget *parent) :
47 m_burnMenu(new QMenu(this))
49 setWindowTitle(i18n("DVD Wizard"));
50 //setPixmap(QWizard::WatermarkPixmap, QPixmap(KStandardDirs::locate("appdata", "banner.png")));
51 m_pageVob = new DvdWizardVob(this);
52 m_pageVob->setTitle(i18n("Select Files For Your DVD"));
54 if (!url.isEmpty()) m_pageVob->setUrl(url);
57 m_pageChapters = new DvdWizardChapters(m_pageVob->dvdFormat(), this);
58 m_pageChapters->setTitle(i18n("DVD Chapters"));
59 addPage(m_pageChapters);
63 m_pageMenu = new DvdWizardMenu(m_pageVob->dvdFormat(), this);
64 m_pageMenu->setTitle(i18n("Create DVD Menu"));
67 QWizardPage *page4 = new QWizardPage;
68 page4->setTitle(i18n("Creating DVD Image"));
69 m_status.setupUi(page4);
70 m_status.error_box->setHidden(true);
71 m_status.error_box->setTabBarHidden(true);
72 m_status.tmp_folder->setUrl(KUrl(KdenliveSettings::currenttmpfolder()));
73 m_status.tmp_folder->setMode(KFile::Directory | KFile::ExistingOnly);
74 m_status.iso_image->setUrl(KUrl(QDir::homePath() + "/untitled.iso"));
75 m_status.iso_image->setFilter("*.iso");
76 m_status.iso_image->setMode(KFile::File);
77 m_status.iso_image->fileDialog()->setOperationMode(KFileDialog::Saving);
79 #if KDE_IS_VERSION(4,7,0)
80 m_isoMessage = new KMessageWidget;
81 QGridLayout *s = static_cast <QGridLayout*> (page4->layout());
82 s->addWidget(m_isoMessage, 5, 0, 1, -1);
88 connect(this, SIGNAL(currentIdChanged(int)), this, SLOT(slotPageChanged(int)));
89 connect(m_status.button_start, SIGNAL(clicked()), this, SLOT(slotGenerate()));
90 connect(m_status.button_abort, SIGNAL(clicked()), this, SLOT(slotAbort()));
91 connect(m_status.button_preview, SIGNAL(clicked()), this, SLOT(slotPreview()));
93 QString programName("k3b");
94 QString exec = KStandardDirs::findExe(programName);
95 if (!exec.isEmpty()) {
97 QAction *k3b = m_burnMenu->addAction(KIcon(programName), i18n("Burn with %1", programName), this, SLOT(slotBurn()));
100 programName = "brasero";
101 exec = KStandardDirs::findExe(programName);
102 if (!exec.isEmpty()) {
104 QAction *brasero = m_burnMenu->addAction(KIcon(programName), i18n("Burn with %1", programName), this, SLOT(slotBurn()));
105 brasero->setData(exec);
107 if (m_burnMenu->isEmpty()) m_burnMenu->addAction(i18n("No burning program found (K3b, Brasero)"));
108 m_status.button_burn->setMenu(m_burnMenu);
109 m_status.button_burn->setIcon(KIcon("tools-media-optical-burn"));
110 m_status.button_burn->setToolButtonStyle(Qt::ToolButtonTextBesideIcon);
111 m_status.button_preview->setIcon(KIcon("media-playback-start"));
113 setButtonText(QWizard::CustomButton1, i18n("Load"));
114 setButtonText(QWizard::CustomButton2, i18n("Save"));
115 button(QWizard::CustomButton1)->setIcon(KIcon("document-open"));
116 button(QWizard::CustomButton2)->setIcon(KIcon("document-save"));
117 connect(button(QWizard::CustomButton1), SIGNAL(clicked()), this, SLOT(slotLoad()));
118 connect(button(QWizard::CustomButton2), SIGNAL(clicked()), this, SLOT(slotSave()));
119 setOption(QWizard::HaveCustomButton1, true);
120 setOption(QWizard::HaveCustomButton2, true);
121 QList<QWizard::WizardButton> layout;
122 layout << QWizard::CustomButton1 << QWizard::CustomButton2 << QWizard::Stretch << QWizard::BackButton << QWizard::NextButton << QWizard::CancelButton << QWizard::FinishButton;
123 setButtonLayout(layout);
126 DvdWizard::~DvdWizard()
128 m_authorFile.remove();
130 m_menuVobFile.remove();
131 m_letterboxMovie.remove();
132 m_menuImageBackground.remove();
136 m_dvdauthor->blockSignals(true);
137 m_dvdauthor->close();
141 m_mkiso->blockSignals(true);
148 void DvdWizard::slotPageChanged(int page)
150 //kDebug() << "// PAGE CHGD: " << page << ", ID: " << visitedPages();
152 // Update chapters that were modified in page 1
153 m_pageChapters->stopMonitor();
154 m_pageVob->updateChapters(m_pageChapters->chaptersData());
155 } else if (page == 1) {
156 m_pageChapters->setVobFiles(m_pageVob->dvdFormat(), m_pageVob->selectedUrls(), m_pageVob->durations(), m_pageVob->chapters());
157 } else if (page == 2) {
158 m_pageChapters->stopMonitor();
159 m_pageVob->updateChapters(m_pageChapters->chaptersData());
160 m_pageMenu->setTargets(m_pageChapters->selectedTitles(), m_pageChapters->selectedTargets());
161 m_pageMenu->changeProfile(m_pageVob->dvdFormat());
167 void DvdWizard::generateDvd()
169 #if KDE_IS_VERSION(4,7,0)
170 m_isoMessage->animatedHide();
172 m_status.error_box->setHidden(true);
173 m_status.error_box->setCurrentIndex(0);
174 m_status.error_box->setTabBarHidden(true);
175 m_status.menu_file->clear();
176 m_status.dvd_file->clear();
178 m_selectedImage.setSuffix(".png");
179 //m_selectedImage.setAutoRemove(false);
180 m_selectedImage.open();
182 m_highlightedImage.setSuffix(".png");
183 //m_highlightedImage.setAutoRemove(false);
184 m_highlightedImage.open();
186 m_menuImageBackground.setSuffix(".png");
187 m_menuImageBackground.setAutoRemove(false);
188 m_menuImageBackground.open();
190 m_menuVideo.setSuffix(".vob");
191 //m_menuVideo.setAutoRemove(false);
194 m_menuFinalVideo.setSuffix(".vob");
195 //m_menuFinalVideo.setAutoRemove(false);
196 m_menuFinalVideo.open();
198 m_letterboxMovie.close();
199 m_letterboxMovie.setSuffix(".mpg");
200 m_letterboxMovie.setAutoRemove(false);
201 m_letterboxMovie.open();
205 m_menuFile.setSuffix(".xml");
206 m_menuFile.setAutoRemove(false);
209 m_menuVobFile.close();
210 m_menuVobFile.setSuffix(".mpg");
211 m_menuVobFile.setAutoRemove(false);
212 m_menuVobFile.open();
214 m_authorFile.close();
215 m_authorFile.setSuffix(".xml");
216 m_authorFile.setAutoRemove(false);
219 QListWidgetItem *images = m_status.job_progress->item(0);
220 m_status.job_progress->setCurrentRow(0);
221 images->setIcon(KIcon("system-run"));
222 m_status.error_log->clear();
223 // initialize html content
224 m_status.error_log->setText("<html></html>");
226 if (m_pageMenu->createMenu()) {
227 m_pageMenu->createButtonImages(m_selectedImage.fileName(), m_highlightedImage.fileName(), false);
228 m_pageMenu->createBackgroundImage(m_menuImageBackground.fileName(), false);
229 images->setIcon(KIcon("dialog-ok"));
230 connect(&m_menuJob, SIGNAL(finished (int, QProcess::ExitStatus)), this, SLOT(slotProcessMenuStatus(int, QProcess::ExitStatus)));
231 //kDebug() << "/// STARTING MLT VOB CREATION: "<<m_selectedImage.fileName()<<m_menuImageBackground.fileName();
232 if (!m_pageMenu->menuMovie()) {
233 // create menu vob file
234 m_vobitem = m_status.job_progress->item(1);
235 m_status.job_progress->setCurrentRow(1);
236 m_vobitem->setIcon(KIcon("system-run"));
239 args << "-profile" << m_pageVob->dvdProfile();
240 args.append(m_menuImageBackground.fileName());
242 args.append("out=100");
243 args << "-consumer" << "avformat:" + m_menuVideo.fileName()<<"properties=DVD";
244 m_menuJob.start(KdenliveSettings::rendererpath(), args);
246 // Movie as menu background, do the compositing
247 m_vobitem = m_status.job_progress->item(1);
248 m_status.job_progress->setCurrentRow(1);
249 m_vobitem->setIcon(KIcon("system-run"));
251 int menuLength = m_pageMenu->menuMovieLength();
252 if (menuLength == -1) {
253 // menu movie is invalid
254 errorMessage(i18n("Menu movie is invalid"));
255 m_status.button_start->setEnabled(true);
256 m_status.button_abort->setEnabled(false);
260 args.append("-profile");
261 args.append(m_pageVob->dvdProfile());
262 args.append(m_pageMenu->menuMoviePath());
263 args << "-track" << m_menuImageBackground.fileName();
264 args << "out=" + QString::number(menuLength);
265 args << "-transition" << "composite" << "always_active=1";
266 args << "-consumer" << "avformat:" + m_menuFinalVideo.fileName()<<"properties=DVD";
267 m_menuJob.start(KdenliveSettings::rendererpath(), args);
268 //kDebug()<<"// STARTING MENU JOB, image: "<<m_menuImageBackground.fileName()<<"\n-------------";
271 else processDvdauthor();
274 void DvdWizard::processSpumux()
276 kDebug() << "/// STARTING SPUMUX";
277 QMap <QString, QRect> buttons = m_pageMenu->buttonsInfo();
278 QStringList buttonsTarget;
279 // create xml spumux file
280 QListWidgetItem *spuitem = m_status.job_progress->item(2);
281 m_status.job_progress->setCurrentRow(2);
282 spuitem->setIcon(KIcon("system-run"));
283 qApp->processEvents();
285 QDomElement sub = doc.createElement("subpictures");
286 doc.appendChild(sub);
287 QDomElement stream = doc.createElement("stream");
288 sub.appendChild(stream);
289 QDomElement spu = doc.createElement("spu");
290 stream.appendChild(spu);
291 spu.setAttribute("force", "yes");
292 spu.setAttribute("start", "00:00:00.00");
293 //spu.setAttribute("image", m_menuImage.fileName());
294 spu.setAttribute("select", m_selectedImage.fileName());
295 spu.setAttribute("highlight", m_highlightedImage.fileName());
296 /*spu.setAttribute("autoorder", "rows");*/
298 int max = buttons.count() - 1;
300 QMapIterator<QString, QRect> it(buttons);
301 while (it.hasNext()) {
303 QDomElement but = doc.createElement("button");
304 but.setAttribute("name", 'b' + QString::number(i));
305 if (i < max) but.setAttribute("down", 'b' + QString::number(i + 1));
306 else but.setAttribute("down", "b0");
307 if (i > 0) but.setAttribute("up", 'b' + QString::number(i - 1));
308 else but.setAttribute("up", 'b' + QString::number(max));
309 QRect r = it.value();
310 //int target = it.key();
311 // TODO: solve play all button
312 //if (target == 0) target = 1;
314 // We need to make sure that the y coordinate is a multiple of 2, otherwise button may not be displayed
315 buttonsTarget.append(it.key());
317 if (y0 % 2 == 1) y0++;
318 int y1 = r.bottom() + 2;
319 if (y1 % 2 == 1) y1++;
320 but.setAttribute("x0", QString::number(r.x()));
321 but.setAttribute("y0", QString::number(y0));
322 but.setAttribute("x1", QString::number(r.right()));
323 but.setAttribute("y1", QString::number(y1));
324 spu.appendChild(but);
328 QFile data(m_menuFile.fileName());
329 if (data.open(QFile::WriteOnly)) {
330 data.write(doc.toString().toUtf8());
334 //kDebug() << " SPUMUX DATA: " << doc.toString();
337 args << "-s" << "0" << m_menuFile.fileName();
338 //kDebug() << "SPM ARGS: " << args << m_menuVideo.fileName() << m_menuVobFile.fileName();
341 QString menuMovieUrl;
343 #if QT_VERSION >= 0x040600
344 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
345 env.insert("VIDEO_FORMAT", m_pageVob->dvdFormat() == PAL || m_pageVob->dvdFormat() == PAL_WIDE ? "PAL" : "NTSC");
346 spumux.setProcessEnvironment(env);
348 QStringList env = QProcess::systemEnvironment();
349 env << QString("VIDEO_FORMAT=") + QString(m_pageVob->dvdFormat() == PAL || m_pageVob->dvdFormat() == PAL_WIDE ? "PAL" : "NTSC");
350 spumux.setEnvironment(env);
353 if (m_pageMenu->menuMovie()) spumux.setStandardInputFile(m_menuFinalVideo.fileName());
354 else spumux.setStandardInputFile(m_menuVideo.fileName());
355 spumux.setStandardOutputFile(m_menuVobFile.fileName());
356 spumux.start("spumux", args);
357 if (spumux.waitForFinished()) {
358 m_status.error_log->append(spumux.readAllStandardError());
359 if (spumux.exitStatus() == QProcess::CrashExit) {
360 //TODO: inform user via messagewidget after string freeze
361 QByteArray result = spumux.readAllStandardError();
362 spuitem->setIcon(KIcon("dialog-close"));
363 m_status.error_log->append(result);
364 m_status.error_box->setHidden(false);
365 m_status.error_box->setTabBarHidden(false);
366 m_status.menu_file->setPlainText(m_menuFile.readAll());
367 m_status.dvd_file->setPlainText(m_authorFile.readAll());
368 m_status.button_start->setEnabled(true);
369 kDebug() << "/// RENDERING SPUMUX MENU crashed";
373 kDebug() << "/// RENDERING SPUMUX MENU timed out";
374 errorMessage(i18n("Rendering job timed out"));
375 spuitem->setIcon(KIcon("dialog-close"));
376 m_status.error_log->append("<a name=\"result\" /><br /><strong>" + i18n("Menu job timed out"));
377 m_status.error_log->scrollToAnchor("result");
378 m_status.error_box->setHidden(false);
379 m_status.error_box->setTabBarHidden(false);
380 m_status.menu_file->setPlainText(m_menuFile.readAll());
381 m_status.dvd_file->setPlainText(m_authorFile.readAll());
382 m_status.button_start->setEnabled(true);
385 if (m_pageVob->dvdFormat() == PAL_WIDE || m_pageVob->dvdFormat() == NTSC_WIDE) {
386 // Second step processing for 16:9 DVD, add letterbox stream
387 m_pageMenu->createButtonImages(m_selectedImage.fileName(), m_highlightedImage.fileName(), true);
388 buttons = m_pageMenu->buttonsInfo(true);
389 // Remove previous button info
390 while(!spu.firstChild().isNull()) {
391 spu.removeChild(spu.firstChild());
394 max = buttons.count() - 1;
396 QMapIterator<QString, QRect> it2(buttons);
397 while (it2.hasNext()) {
399 QDomElement but = doc.createElement("button");
400 but.setAttribute("name", 'b' + QString::number(i));
401 if (i < max) but.setAttribute("down", 'b' + QString::number(i + 1));
402 else but.setAttribute("down", "b0");
403 if (i > 0) but.setAttribute("up", 'b' + QString::number(i - 1));
404 else but.setAttribute("up", 'b' + QString::number(max));
405 QRect r = it2.value();
406 // We need to make sure that the y coordinate is a multiple of 2, otherwise button may not be displayed
407 buttonsTarget.append(it2.key());
409 if (y0 % 2 == 1) y0++;
410 int y1 = r.bottom() + 2;
411 if (y1 % 2 == 1) y1++;
412 but.setAttribute("x0", QString::number(r.x()));
413 but.setAttribute("y0", QString::number(y0));
414 but.setAttribute("x1", QString::number(r.right()));
415 but.setAttribute("y1", QString::number(y1));
416 spu.appendChild(but);
420 //kDebug() << " SPUMUX DATA: " << doc.toString();
422 if (data.open(QFile::WriteOnly)) {
423 data.write(doc.toString().toUtf8());
426 spumux.setStandardInputFile(m_menuVobFile.fileName());
427 spumux.setStandardOutputFile(m_letterboxMovie.fileName());
429 args << "-s" << "1" << m_menuFile.fileName();
430 spumux.start("spumux", args);
431 //kDebug() << "SPM ARGS LETTERBOX: " << args << m_menuVideo.fileName() << m_letterboxMovie.fileName();
432 if (spumux.waitForFinished()) {
433 m_status.error_log->append(spumux.readAllStandardError());
434 if (spumux.exitStatus() == QProcess::CrashExit) {
435 //TODO: inform user via messagewidget after string freeze
436 QByteArray result = spumux.readAllStandardError();
437 spuitem->setIcon(KIcon("dialog-close"));
438 m_status.error_log->append(result);
439 m_status.error_box->setHidden(false);
440 m_status.error_box->setTabBarHidden(false);
441 m_status.menu_file->setPlainText(m_menuFile.readAll());
442 m_status.dvd_file->setPlainText(m_authorFile.readAll());
443 m_status.button_start->setEnabled(true);
444 kDebug() << "/// RENDERING SPUMUX MENU crashed";
448 kDebug() << "/// RENDERING SPUMUX MENU timed out";
449 errorMessage(i18n("Rendering job timed out"));
450 spuitem->setIcon(KIcon("dialog-close"));
451 m_status.error_log->append("<a name=\"result\" /><br /><strong>" + i18n("Menu job timed out"));
452 m_status.error_log->scrollToAnchor("result");
453 m_status.error_box->setHidden(false);
454 m_status.error_box->setTabBarHidden(false);
455 m_status.menu_file->setPlainText(m_menuFile.readAll());
456 m_status.dvd_file->setPlainText(m_authorFile.readAll());
457 m_status.button_start->setEnabled(true);
460 menuMovieUrl = m_letterboxMovie.fileName();
462 else menuMovieUrl = m_menuVobFile.fileName();
464 spuitem->setIcon(KIcon("dialog-ok"));
465 kDebug() << "/// DONE: " << menuMovieUrl;
466 processDvdauthor(menuMovieUrl, buttons, buttonsTarget);
469 void DvdWizard::processDvdauthor(QString menuMovieUrl, QMap <QString, QRect> buttons, QStringList buttonsTarget)
471 // create dvdauthor xml
472 QListWidgetItem *authitem = m_status.job_progress->item(3);
473 m_status.job_progress->setCurrentRow(3);
474 authitem->setIcon(KIcon("system-run"));
475 qApp->processEvents();
476 KIO::NetAccess::mkdir(KUrl(m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"), this);
479 QDomElement auth = dvddoc.createElement("dvdauthor");
480 auth.setAttribute("dest", m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD");
481 dvddoc.appendChild(auth);
482 QDomElement vmgm = dvddoc.createElement("vmgm");
483 auth.appendChild(vmgm);
485 if (m_pageMenu->createMenu() && !m_pageVob->introMovie().isEmpty()) {
486 // Use first movie in list as intro movie
487 QDomElement menus = dvddoc.createElement("menus");
488 vmgm.appendChild(menus);
489 QDomElement pgc = dvddoc.createElement("pgc");
490 pgc.setAttribute("entry", "title");
491 menus.appendChild(pgc);
492 QDomElement menuvob = dvddoc.createElement("vob");
493 menuvob.setAttribute("file", m_pageVob->introMovie());
494 pgc.appendChild(menuvob);
495 QDomElement post = dvddoc.createElement("post");
496 QDomText call = dvddoc.createTextNode("jump titleset 1 menu;");
497 post.appendChild(call);
498 pgc.appendChild(post);
500 QDomElement titleset = dvddoc.createElement("titleset");
501 auth.appendChild(titleset);
503 if (m_pageMenu->createMenu()) {
506 QDomElement menus = dvddoc.createElement("menus");
507 titleset.appendChild(menus);
508 if (m_pageVob->dvdFormat() == PAL_WIDE || m_pageVob->dvdFormat() == NTSC_WIDE) {
509 // Add letterbox stream info
510 QDomElement subpict = dvddoc.createElement("subpicture");
511 QDomElement stream = dvddoc.createElement("stream");
512 stream.setAttribute("id", "0");
513 stream.setAttribute("mode", "widescreen");
514 subpict.appendChild(stream);
515 QDomElement stream2 = dvddoc.createElement("stream");
516 stream2.setAttribute("id", "1");
517 stream2.setAttribute("mode", "letterbox");
518 subpict.appendChild(stream2);
519 menus.appendChild(subpict);
521 QDomElement pgc = dvddoc.createElement("pgc");
522 pgc.setAttribute("entry", "root");
523 menus.appendChild(pgc);
524 QDomElement pre = dvddoc.createElement("pre");
525 pgc.appendChild(pre);
526 QDomText nametext = dvddoc.createTextNode("{g1 = 0;}");
527 pre.appendChild(nametext);
528 QDomElement menuvob = dvddoc.createElement("vob");
529 menuvob.setAttribute("file", menuMovieUrl);
530 pgc.appendChild(menuvob);
531 for (int i = 0; i < buttons.count(); i++) {
532 QDomElement button = dvddoc.createElement("button");
533 button.setAttribute("name", 'b' + QString::number(i));
534 nametext = dvddoc.createTextNode('{' + buttonsTarget.at(i) + ";}");
535 button.appendChild(nametext);
536 pgc.appendChild(button);
539 if (m_pageMenu->loopMovie()) {
540 QDomElement menuloop = dvddoc.createElement("post");
541 nametext = dvddoc.createTextNode("jump titleset 1 menu;");
542 menuloop.appendChild(nametext);
543 pgc.appendChild(menuloop);
544 } else menuvob.setAttribute("pause", "inf");
548 QDomElement titles = dvddoc.createElement("titles");
549 titleset.appendChild(titles);
550 QDomElement video = dvddoc.createElement("video");
551 titles.appendChild(video);
552 switch (m_pageVob->dvdFormat()) {
554 video.setAttribute("format", "pal");
555 video.setAttribute("aspect", "16:9");
558 video.setAttribute("format", "ntsc");
559 video.setAttribute("aspect", "16:9");
562 video.setAttribute("format", "ntsc");
563 video.setAttribute("aspect", "4:3");
566 video.setAttribute("format", "pal");
567 video.setAttribute("aspect", "4:3");
573 QStringList voburls = m_pageVob->selectedUrls();
575 for (int i = 0; i < voburls.count(); i++) {
576 if (!voburls.at(i).isEmpty()) {
578 pgc2 = dvddoc.createElement("pgc");
579 pgc2.setAttribute("pause", 0);
580 titles.appendChild(pgc2);
581 QDomElement vob = dvddoc.createElement("vob");
582 vob.setAttribute("file", voburls.at(i));
584 QStringList chaptersList = m_pageChapters->chapters(i);
585 if (!chaptersList.isEmpty()) vob.setAttribute("chapters", chaptersList.join(","));
587 pgc2.appendChild(vob);
588 if (m_pageMenu->createMenu()) {
589 QDomElement post = dvddoc.createElement("post");
591 if (i == voburls.count() - 1) call = dvddoc.createTextNode("{g1 = 0; call menu;}");
593 call = dvddoc.createTextNode("{if ( g1 eq 999 ) { call menu; } jump title " + QString::number(i + 2).rightJustified(2, '0') + ";}");
595 post.appendChild(call);
596 pgc2.appendChild(post);
602 QFile data2(m_authorFile.fileName());
603 if (data2.open(QFile::WriteOnly)) {
604 data2.write(dvddoc.toString().toUtf8());
607 /*kDebug() << "------------------";
608 kDebug() << dvddoc.toString();
609 kDebug() << "------------------";*/
612 args << "-x" << m_authorFile.fileName();
613 kDebug() << "// DVDAUTH ARGS: " << args;
615 m_dvdauthor->blockSignals(true);
616 m_dvdauthor->close();
620 m_creationLog.clear();
621 m_dvdauthor = new QProcess(this);
622 // Set VIDEO_FORMAT variable (required by dvdauthor 0.7)
623 #if QT_VERSION >= 0x040600
624 QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
625 env.insert("VIDEO_FORMAT", m_pageVob->dvdFormat() == PAL || m_pageVob->dvdFormat() == PAL_WIDE ? "PAL" : "NTSC");
626 m_dvdauthor->setProcessEnvironment(env);
628 QStringList env = QProcess::systemEnvironment();
629 env << QString("VIDEO_FORMAT=") + QString(m_pageVob->dvdFormat() == PAL || m_pageVob->dvdFormat() == PAL_WIDE ? "PAL" : "NTSC");
630 m_dvdauthor->setEnvironment(env);
632 connect(m_dvdauthor, SIGNAL(finished(int , QProcess::ExitStatus)), this, SLOT(slotRenderFinished(int, QProcess::ExitStatus)));
633 connect(m_dvdauthor, SIGNAL(readyReadStandardOutput()), this, SLOT(slotShowRenderInfo()));
634 m_dvdauthor->setProcessChannelMode(QProcess::MergedChannels);
635 m_dvdauthor->start("dvdauthor", args);
636 m_status.button_abort->setEnabled(true);
637 button(QWizard::FinishButton)->setEnabled(false);
640 void DvdWizard::slotProcessMenuStatus(int, QProcess::ExitStatus status)
642 if (status == QProcess::CrashExit) {
643 kDebug() << "/// RENDERING MENU vob crashed";
644 errorMessage(i18n("Rendering menu crashed"));
645 QByteArray result = m_menuJob.readAllStandardError();
646 m_vobitem->setIcon(KIcon("dialog-close"));
647 m_status.error_log->append(result);
648 m_status.error_box->setHidden(false);
649 m_status.button_start->setEnabled(true);
650 m_status.button_abort->setEnabled(false);
653 m_vobitem->setIcon(KIcon("dialog-ok"));
657 void DvdWizard::slotShowRenderInfo()
659 QString log = QString(m_dvdauthor->readAll());
660 m_status.error_log->append(log);
661 m_status.error_box->setHidden(false);
664 void DvdWizard::errorMessage(const QString &text) {
665 #if KDE_IS_VERSION(4,7,0)
666 m_isoMessage->setText(text);
667 m_isoMessage->setMessageType(KMessageWidget::Error);
668 m_isoMessage->animatedShow();
672 void DvdWizard::infoMessage(const QString &text) {
673 #if KDE_IS_VERSION(4,7,0)
674 m_isoMessage->setText(text);
675 m_isoMessage->setMessageType(KMessageWidget::Positive);
676 m_isoMessage->animatedShow();
680 void DvdWizard::slotRenderFinished(int exitCode, QProcess::ExitStatus status)
682 QListWidgetItem *authitem = m_status.job_progress->item(3);
683 if (status == QProcess::CrashExit || exitCode != 0) {
684 errorMessage(i18n("DVDAuthor process crashed"));
685 QString result(m_dvdauthor->readAllStandardError());
686 result.append("<a name=\"result\" /><br /><strong>");
687 result.append(i18n("DVDAuthor process crashed.</strong><br />"));
688 m_status.error_log->append(result);
689 m_status.error_log->scrollToAnchor("result");
690 m_status.error_box->setHidden(false);
691 m_status.error_box->setTabBarHidden(false);
692 m_status.menu_file->setPlainText(m_menuFile.readAll());
693 m_status.dvd_file->setPlainText(m_authorFile.readAll());
694 kDebug() << "DVDAuthor process crashed";
695 authitem->setIcon(KIcon("dialog-close"));
696 m_dvdauthor->close();
699 m_status.button_start->setEnabled(true);
700 m_status.button_abort->setEnabled(false);
702 button(QWizard::FinishButton)->setEnabled(true);
705 m_creationLog.append(m_dvdauthor->readAllStandardError());
706 m_dvdauthor->close();
710 // Check if DVD structure has the necessary infos
711 if (!QFile::exists(m_status.tmp_folder->url().path() + "/DVD/VIDEO_TS/VIDEO_TS.IFO")) {
712 errorMessage(i18n("DVD structure broken"));
713 m_status.error_log->append(m_creationLog + "<a name=\"result\" /><br /><strong>" + i18n("DVD structure broken"));
714 m_status.error_log->scrollToAnchor("result");
715 m_status.error_box->setHidden(false);
716 m_status.error_box->setTabBarHidden(false);
717 m_status.menu_file->setPlainText(m_menuFile.readAll());
718 m_status.dvd_file->setPlainText(m_authorFile.readAll());
719 kDebug() << "DVDAuthor process crashed";
720 authitem->setIcon(KIcon("dialog-close"));
721 m_status.button_start->setEnabled(true);
722 m_status.button_abort->setEnabled(false);
724 button(QWizard::FinishButton)->setEnabled(true);
727 authitem->setIcon(KIcon("dialog-ok"));
728 qApp->processEvents();
730 args << "-dvd-video" << "-v" << "-o" << m_status.iso_image->url().path() << m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD";
733 m_mkiso->blockSignals(true);
738 m_mkiso = new QProcess(this);
739 connect(m_mkiso, SIGNAL(finished(int , QProcess::ExitStatus)), this, SLOT(slotIsoFinished(int, QProcess::ExitStatus)));
740 connect(m_mkiso, SIGNAL(readyReadStandardOutput()), this, SLOT(slotShowIsoInfo()));
741 m_mkiso->setProcessChannelMode(QProcess::MergedChannels);
742 QListWidgetItem *isoitem = m_status.job_progress->item(4);
743 m_status.job_progress->setCurrentRow(4);
744 isoitem->setIcon(KIcon("system-run"));
745 if (!KStandardDirs::findExe("genisoimage").isEmpty()) m_mkiso->start("genisoimage", args);
746 else m_mkiso->start("mkisofs", args);
750 void DvdWizard::slotShowIsoInfo()
752 QString log = QString(m_mkiso->readAll());
753 m_status.error_log->append(log);
754 m_status.error_box->setHidden(false);
757 void DvdWizard::slotIsoFinished(int exitCode, QProcess::ExitStatus status)
759 button(QWizard::FinishButton)->setEnabled(true);
760 QListWidgetItem *isoitem = m_status.job_progress->item(4);
761 if (status == QProcess::CrashExit || exitCode != 0) {
762 errorMessage(i18n("ISO creation process crashed."));
763 QString result(m_mkiso->readAllStandardError());
764 result.append("<a name=\"result\" /><br /><strong>");
765 result.append(i18n("ISO creation process crashed."));
766 m_status.error_log->append(result);
767 m_status.error_log->scrollToAnchor("result");
768 m_status.error_box->setHidden(false);
769 m_status.error_box->setTabBarHidden(false);
770 m_status.menu_file->setPlainText(m_menuFile.readAll());
771 m_status.dvd_file->setPlainText(m_authorFile.readAll());
776 kDebug() << "Iso process crashed";
777 isoitem->setIcon(KIcon("dialog-close"));
778 m_status.button_start->setEnabled(true);
779 m_status.button_abort->setEnabled(false);
783 m_creationLog.append(m_mkiso->readAllStandardError());
786 m_status.button_start->setEnabled(true);
787 m_status.button_abort->setEnabled(false);
789 // Check if DVD iso is ok
790 QFile iso(m_status.iso_image->url().path());
791 if (!iso.exists() || iso.size() == 0) {
793 KIO::NetAccess::del(m_status.iso_image->url(), this);
795 errorMessage(i18n("DVD ISO is broken"));
796 m_status.error_log->append(m_creationLog + "<br /><a name=\"result\" /><strong>" + i18n("DVD ISO is broken") + "</strong>");
797 m_status.error_log->scrollToAnchor("result");
798 m_status.error_box->setHidden(false);
799 m_status.error_box->setTabBarHidden(false);
800 m_status.menu_file->setPlainText(m_menuFile.readAll());
801 m_status.dvd_file->setPlainText(m_authorFile.readAll());
802 isoitem->setIcon(KIcon("dialog-close"));
807 isoitem->setIcon(KIcon("dialog-ok"));
808 kDebug() << "ISO IMAGE " << m_status.iso_image->url().path() << " Successfully created";
810 kDebug() << m_creationLog;
811 infoMessage(i18n("DVD ISO image %1 successfully created.", m_status.iso_image->url().path()));
813 m_status.error_log->append("<a name=\"result\" /><strong>" + i18n("DVD ISO image %1 successfully created.", m_status.iso_image->url().path()) + "</strong>");
814 m_status.error_log->scrollToAnchor("result");
815 m_status.button_preview->setEnabled(true);
816 m_status.button_burn->setEnabled(true);
817 m_status.error_box->setHidden(false);
818 //KMessageBox::information(this, i18n("DVD ISO image %1 successfully created.", m_status.iso_image->url().path()));
823 void DvdWizard::cleanup()
825 KIO::NetAccess::del(KUrl(m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"), this);
829 void DvdWizard::slotPreview()
831 QStringList programNames;
832 programNames << "xine" << "vlc";
834 foreach(const QString &prog, programNames) {
835 exec = KStandardDirs::findExe(prog);
836 if (!exec.isEmpty()) {
840 if (exec.isEmpty()) {
841 KMessageBox::sorry(this, i18n("Previewing requires one of these applications (%1)", programNames.join(",")));
843 else QProcess::startDetached(exec, QStringList() << "dvd://" + m_status.iso_image->url().path());
846 void DvdWizard::slotBurn()
848 QAction *action = qobject_cast<QAction *>(sender());
849 QString exec = action->data().toString();
851 if (exec.endsWith("k3b")) args << "--image" << m_status.iso_image->url().path();
852 else args << "--image=" + m_status.iso_image->url().path();
853 QProcess::startDetached(exec, args);
857 void DvdWizard::slotGenerate()
860 if ((m_dvdauthor && m_dvdauthor->state() != QProcess::NotRunning) || (m_mkiso && m_mkiso->state() != QProcess::NotRunning)) return;
861 for (int i = 0; i < m_status.job_progress->count(); i++)
862 m_status.job_progress->item(i)->setIcon(KIcon());
864 if (KIO::NetAccess::exists(KUrl(m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"), KIO::NetAccess::SourceSide, this))
865 warnMessage.append(i18n("Folder %1 already exists. Overwrite?\n", m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"));
866 if (KIO::NetAccess::exists(KUrl(m_status.iso_image->url().path()), KIO::NetAccess::SourceSide, this))
867 warnMessage.append(i18n("Image file %1 already exists. Overwrite?", m_status.iso_image->url().path()));
869 if (warnMessage.isEmpty() || KMessageBox::questionYesNo(this, warnMessage) == KMessageBox::Yes) {
870 KIO::NetAccess::del(KUrl(m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"), this);
871 QTimer::singleShot(300, this, SLOT(generateDvd()));
872 m_status.button_preview->setEnabled(false);
873 m_status.button_burn->setEnabled(false);
874 m_status.job_progress->setEnabled(true);
875 m_status.button_start->setEnabled(false);
879 void DvdWizard::slotAbort()
882 if (m_dvdauthor && m_dvdauthor->state() != QProcess::NotRunning) m_dvdauthor->terminate();
883 else if (m_mkiso && m_mkiso->state() != QProcess::NotRunning) m_mkiso->terminate();
886 void DvdWizard::slotSave()
888 KUrl url = KFileDialog::getSaveUrl(KUrl("kfiledialog:///projectfolder"), "*.kdvd", this, i18n("Save DVD Project"));
889 if (url.isEmpty()) return;
891 if (currentId() == 0) m_pageChapters->setVobFiles(m_pageVob->dvdFormat(), m_pageVob->selectedUrls(), m_pageVob->durations(), m_pageVob->chapters());
894 QDomElement dvdproject = doc.createElement("dvdproject");
895 dvdproject.setAttribute("profile", m_pageVob->dvdProfile());
896 dvdproject.setAttribute("tmp_folder", m_status.tmp_folder->url().path());
897 dvdproject.setAttribute("iso_image", m_status.iso_image->url().path());
898 dvdproject.setAttribute("intro_movie", m_pageVob->introMovie());
900 doc.appendChild(dvdproject);
901 QDomElement menu = m_pageMenu->toXml();
902 if (!menu.isNull()) dvdproject.appendChild(doc.importNode(menu, true));
903 QDomElement chaps = m_pageChapters->toXml();
904 if (!chaps.isNull()) dvdproject.appendChild(doc.importNode(chaps, true));
906 QFile file(url.path());
907 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
908 kWarning() << "////// ERROR writing to file: " << url.path();
909 KMessageBox::error(this, i18n("Cannot write to file %1", url.path()));
913 file.write(doc.toString().toUtf8());
914 if (file.error() != QFile::NoError) {
915 KMessageBox::error(this, i18n("Cannot write to file %1", url.path()));
921 void DvdWizard::slotLoad()
923 KUrl url = KFileDialog::getOpenUrl(KUrl("kfiledialog:///projectfolder"), "*.kdvd");
924 if (url.isEmpty()) return;
926 QFile file(url.path());
927 doc.setContent(&file, false);
929 QDomElement dvdproject = doc.documentElement();
930 if (dvdproject.tagName() != "dvdproject") {
931 KMessageBox::error(this, i18n("File %1 is not a Kdenlive project file.", url.path()));
935 QString profile = dvdproject.attribute("profile");
936 m_pageVob->setProfile(profile);
938 m_status.tmp_folder->setUrl(KUrl(dvdproject.attribute("tmp_folder")));
939 m_status.iso_image->setUrl(KUrl(dvdproject.attribute("iso_image")));
940 QString intro = dvdproject.attribute("intro_movie");
941 if (!intro.isEmpty()) {
942 m_pageVob->slotAddVobFile(KUrl(intro));
943 m_pageVob->setUseIntroMovie(true);
946 QDomNodeList vobs = doc.elementsByTagName("vob");
947 for (int i = 0; i < vobs.count(); i++) {
948 QDomElement e = vobs.at(i).toElement();
949 m_pageVob->slotAddVobFile(KUrl(e.attribute("file")), e.attribute("chapters"));
951 m_pageMenu->loadXml(m_pageVob->dvdFormat(), dvdproject.firstChildElement("menu"));