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 qApp->processEvents();
223 m_status.error_log->clear();
224 // initialize html content
225 m_status.error_log->setText("<html></html>");
227 if (m_pageMenu->createMenu()) {
228 m_pageMenu->createButtonImages(m_selectedImage.fileName(), m_highlightedImage.fileName(), false);
229 m_pageMenu->createBackgroundImage(m_menuImageBackground.fileName(), false);
230 images->setIcon(KIcon("dialog-ok"));
231 connect(&m_menuJob, SIGNAL(finished (int, QProcess::ExitStatus)), this, SLOT(slotProcessMenuStatus(int, QProcess::ExitStatus)));
232 //kDebug() << "/// STARTING MLT VOB CREATION: "<<m_selectedImage.fileName()<<m_menuImageBackground.fileName();
233 if (!m_pageMenu->menuMovie()) {
234 // create menu vob file
235 m_vobitem = m_status.job_progress->item(1);
236 m_status.job_progress->setCurrentRow(1);
237 m_vobitem->setIcon(KIcon("system-run"));
240 args << "-profile" << m_pageVob->dvdProfile();
241 args.append(m_menuImageBackground.fileName());
243 args.append("out=100");
244 args << "-consumer" << "avformat:" + m_menuVideo.fileName()<<"properties=DVD";
245 m_menuJob.start(KdenliveSettings::rendererpath(), args);
247 // Movie as menu background, do the compositing
248 m_vobitem = m_status.job_progress->item(1);
249 m_status.job_progress->setCurrentRow(1);
250 m_vobitem->setIcon(KIcon("system-run"));
252 int menuLength = m_pageMenu->menuMovieLength();
253 if (menuLength == -1) {
254 // menu movie is invalid
255 errorMessage(i18n("Menu movie is invalid"));
256 m_status.button_start->setEnabled(true);
257 m_status.button_abort->setEnabled(false);
261 args.append("-profile");
262 args.append(m_pageVob->dvdProfile());
263 args.append(m_pageMenu->menuMoviePath());
264 args << "-track" << m_menuImageBackground.fileName();
265 args << "out=" + QString::number(menuLength);
266 args << "-transition" << "composite" << "always_active=1";
267 args << "-consumer" << "avformat:" + m_menuFinalVideo.fileName()<<"properties=DVD";
268 m_menuJob.start(KdenliveSettings::rendererpath(), args);
269 //kDebug()<<"// STARTING MENU JOB, image: "<<m_menuImageBackground.fileName()<<"\n-------------";
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;
467 // create dvdauthor xml
468 QListWidgetItem *authitem = m_status.job_progress->item(3);
469 m_status.job_progress->setCurrentRow(3);
470 authitem->setIcon(KIcon("system-run"));
471 qApp->processEvents();
472 KIO::NetAccess::mkdir(KUrl(m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"), this);
475 QDomElement auth = dvddoc.createElement("dvdauthor");
476 auth.setAttribute("dest", m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD");
477 dvddoc.appendChild(auth);
478 QDomElement vmgm = dvddoc.createElement("vmgm");
479 auth.appendChild(vmgm);
481 if (m_pageMenu->createMenu() && !m_pageVob->introMovie().isEmpty()) {
482 // Use first movie in list as intro movie
483 QDomElement menus = dvddoc.createElement("menus");
484 vmgm.appendChild(menus);
485 QDomElement pgc = dvddoc.createElement("pgc");
486 pgc.setAttribute("entry", "title");
487 menus.appendChild(pgc);
488 QDomElement menuvob = dvddoc.createElement("vob");
489 menuvob.setAttribute("file", m_pageVob->introMovie());
490 pgc.appendChild(menuvob);
491 QDomElement post = dvddoc.createElement("post");
492 QDomText call = dvddoc.createTextNode("jump titleset 1 menu;");
493 post.appendChild(call);
494 pgc.appendChild(post);
496 QDomElement titleset = dvddoc.createElement("titleset");
497 auth.appendChild(titleset);
499 if (m_pageMenu->createMenu()) {
502 QDomElement menus = dvddoc.createElement("menus");
503 titleset.appendChild(menus);
504 if (m_pageVob->dvdFormat() == PAL_WIDE || m_pageVob->dvdFormat() == NTSC_WIDE) {
505 // Add letterbox stream info
506 QDomElement subpict = dvddoc.createElement("subpicture");
507 QDomElement stream = dvddoc.createElement("stream");
508 stream.setAttribute("id", "0");
509 stream.setAttribute("mode", "widescreen");
510 subpict.appendChild(stream);
511 QDomElement stream2 = dvddoc.createElement("stream");
512 stream2.setAttribute("id", "1");
513 stream2.setAttribute("mode", "letterbox");
514 subpict.appendChild(stream2);
515 menus.appendChild(subpict);
517 QDomElement pgc = dvddoc.createElement("pgc");
518 pgc.setAttribute("entry", "root");
519 menus.appendChild(pgc);
520 QDomElement pre = dvddoc.createElement("pre");
521 pgc.appendChild(pre);
522 QDomText nametext = dvddoc.createTextNode("{g1 = 0;}");
523 pre.appendChild(nametext);
524 QDomElement menuvob = dvddoc.createElement("vob");
525 menuvob.setAttribute("file", menuMovieUrl);
526 pgc.appendChild(menuvob);
527 for (int i = 0; i < buttons.count(); i++) {
528 QDomElement button = dvddoc.createElement("button");
529 button.setAttribute("name", 'b' + QString::number(i));
530 nametext = dvddoc.createTextNode('{' + buttonsTarget.at(i) + ";}");
531 button.appendChild(nametext);
532 pgc.appendChild(button);
535 if (m_pageMenu->loopMovie()) {
536 QDomElement menuloop = dvddoc.createElement("post");
537 nametext = dvddoc.createTextNode("jump titleset 1 menu;");
538 menuloop.appendChild(nametext);
539 pgc.appendChild(menuloop);
540 } else menuvob.setAttribute("pause", "inf");
544 QDomElement titles = dvddoc.createElement("titles");
545 titleset.appendChild(titles);
546 QDomElement video = dvddoc.createElement("video");
547 titles.appendChild(video);
548 switch (m_pageVob->dvdFormat()) {
550 video.setAttribute("format", "pal");
551 video.setAttribute("aspect", "16:9");
554 video.setAttribute("format", "ntsc");
555 video.setAttribute("aspect", "16:9");
558 video.setAttribute("format", "ntsc");
559 video.setAttribute("aspect", "4:3");
562 video.setAttribute("format", "pal");
563 video.setAttribute("aspect", "4:3");
569 QStringList voburls = m_pageVob->selectedUrls();
571 for (int i = 0; i < voburls.count(); i++) {
572 if (!voburls.at(i).isEmpty()) {
574 pgc2 = dvddoc.createElement("pgc");
575 pgc2.setAttribute("pause", 0);
576 titles.appendChild(pgc2);
577 QDomElement vob = dvddoc.createElement("vob");
578 vob.setAttribute("file", voburls.at(i));
580 QStringList chaptersList = m_pageChapters->chapters(i);
581 if (!chaptersList.isEmpty()) vob.setAttribute("chapters", chaptersList.join(","));
583 pgc2.appendChild(vob);
584 if (m_pageMenu->createMenu()) {
585 QDomElement post = dvddoc.createElement("post");
587 if (i == voburls.count() - 1) call = dvddoc.createTextNode("{g1 = 0; call menu;}");
589 call = dvddoc.createTextNode("{if ( g1 eq 999 ) { call menu; } jump title " + QString::number(i + 2).rightJustified(2, '0') + ";}");
591 post.appendChild(call);
592 pgc2.appendChild(post);
598 QFile data2(m_authorFile.fileName());
599 if (data2.open(QFile::WriteOnly)) {
600 data2.write(dvddoc.toString().toUtf8());
603 /*kDebug() << "------------------";
604 kDebug() << dvddoc.toString();
605 kDebug() << "------------------";*/
608 args << "-x" << m_authorFile.fileName();
609 kDebug() << "// DVDAUTH ARGS: " << args;
611 m_dvdauthor->blockSignals(true);
612 m_dvdauthor->close();
616 m_creationLog.clear();
617 m_dvdauthor = new QProcess(this);
618 // Set VIDEO_FORMAT variable (required by dvdauthor 0.7)
619 #if QT_VERSION >= 0x040600
620 env = QProcessEnvironment::systemEnvironment();
621 env.insert("VIDEO_FORMAT", m_pageVob->dvdFormat() == PAL || m_pageVob->dvdFormat() == PAL_WIDE ? "PAL" : "NTSC");
622 m_dvdauthor->setProcessEnvironment(env);
624 QStringList env = QProcess::systemEnvironment();
625 env << QString("VIDEO_FORMAT=") + QString(m_pageVob->dvdFormat() == PAL || m_pageVob->dvdFormat() == PAL_WIDE ? "PAL" : "NTSC");
626 m_dvdauthor->setEnvironment(env);
628 connect(m_dvdauthor, SIGNAL(finished(int , QProcess::ExitStatus)), this, SLOT(slotRenderFinished(int, QProcess::ExitStatus)));
629 connect(m_dvdauthor, SIGNAL(readyReadStandardOutput()), this, SLOT(slotShowRenderInfo()));
630 m_dvdauthor->setProcessChannelMode(QProcess::MergedChannels);
631 m_dvdauthor->start("dvdauthor", args);
632 m_status.button_abort->setEnabled(true);
633 button(QWizard::FinishButton)->setEnabled(false);
636 void DvdWizard::slotProcessMenuStatus(int, QProcess::ExitStatus status)
638 if (status == QProcess::CrashExit) {
639 kDebug() << "/// RENDERING MENU vob crashed";
640 errorMessage(i18n("Rendering menu crashed"));
641 QByteArray result = m_menuJob.readAllStandardError();
642 m_vobitem->setIcon(KIcon("dialog-close"));
643 m_status.error_log->append(result);
644 m_status.error_box->setHidden(false);
645 m_status.button_start->setEnabled(true);
646 m_status.button_abort->setEnabled(false);
649 m_vobitem->setIcon(KIcon("dialog-ok"));
653 void DvdWizard::slotShowRenderInfo()
655 QString log = QString(m_dvdauthor->readAll());
656 m_status.error_log->append(log);
657 m_status.error_box->setHidden(false);
660 void DvdWizard::errorMessage(const QString &text) {
661 #if KDE_IS_VERSION(4,7,0)
662 m_isoMessage->setText(text);
663 m_isoMessage->setMessageType(KMessageWidget::Error);
664 m_isoMessage->animatedShow();
668 void DvdWizard::infoMessage(const QString &text) {
669 #if KDE_IS_VERSION(4,7,0)
670 m_isoMessage->setText(text);
671 m_isoMessage->setMessageType(KMessageWidget::Positive);
672 m_isoMessage->animatedShow();
676 void DvdWizard::slotRenderFinished(int exitCode, QProcess::ExitStatus status)
678 QListWidgetItem *authitem = m_status.job_progress->item(3);
679 if (status == QProcess::CrashExit || exitCode != 0) {
680 errorMessage(i18n("DVDAuthor process crashed"));
681 QString result(m_dvdauthor->readAllStandardError());
682 result.append("<a name=\"result\" /><br /><strong>");
683 result.append(i18n("DVDAuthor process crashed.</strong><br />"));
684 m_status.error_log->append(result);
685 m_status.error_log->scrollToAnchor("result");
686 m_status.error_box->setHidden(false);
687 m_status.error_box->setTabBarHidden(false);
688 m_status.menu_file->setPlainText(m_menuFile.readAll());
689 m_status.dvd_file->setPlainText(m_authorFile.readAll());
690 kDebug() << "DVDAuthor process crashed";
691 authitem->setIcon(KIcon("dialog-close"));
692 m_dvdauthor->close();
695 m_status.button_start->setEnabled(true);
696 m_status.button_abort->setEnabled(false);
698 button(QWizard::FinishButton)->setEnabled(true);
701 m_creationLog.append(m_dvdauthor->readAllStandardError());
702 m_dvdauthor->close();
706 // Check if DVD structure has the necessary infos
707 if (!QFile::exists(m_status.tmp_folder->url().path() + "/DVD/VIDEO_TS/VIDEO_TS.IFO")) {
708 errorMessage(i18n("DVD structure broken"));
709 m_status.error_log->append(m_creationLog + "<a name=\"result\" /><br /><strong>" + i18n("DVD structure broken"));
710 m_status.error_log->scrollToAnchor("result");
711 m_status.error_box->setHidden(false);
712 m_status.error_box->setTabBarHidden(false);
713 m_status.menu_file->setPlainText(m_menuFile.readAll());
714 m_status.dvd_file->setPlainText(m_authorFile.readAll());
715 kDebug() << "DVDAuthor process crashed";
716 authitem->setIcon(KIcon("dialog-close"));
717 m_status.button_start->setEnabled(true);
718 m_status.button_abort->setEnabled(false);
720 button(QWizard::FinishButton)->setEnabled(true);
723 authitem->setIcon(KIcon("dialog-ok"));
724 qApp->processEvents();
726 args << "-dvd-video" << "-v" << "-o" << m_status.iso_image->url().path() << m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD";
729 m_mkiso->blockSignals(true);
734 m_mkiso = new QProcess(this);
735 connect(m_mkiso, SIGNAL(finished(int , QProcess::ExitStatus)), this, SLOT(slotIsoFinished(int, QProcess::ExitStatus)));
736 connect(m_mkiso, SIGNAL(readyReadStandardOutput()), this, SLOT(slotShowIsoInfo()));
737 m_mkiso->setProcessChannelMode(QProcess::MergedChannels);
738 QListWidgetItem *isoitem = m_status.job_progress->item(4);
739 m_status.job_progress->setCurrentRow(4);
740 isoitem->setIcon(KIcon("system-run"));
741 if (!KStandardDirs::findExe("genisoimage").isEmpty()) m_mkiso->start("genisoimage", args);
742 else m_mkiso->start("mkisofs", args);
746 void DvdWizard::slotShowIsoInfo()
748 QString log = QString(m_mkiso->readAll());
749 m_status.error_log->append(log);
750 m_status.error_box->setHidden(false);
753 void DvdWizard::slotIsoFinished(int exitCode, QProcess::ExitStatus status)
755 button(QWizard::FinishButton)->setEnabled(true);
756 QListWidgetItem *isoitem = m_status.job_progress->item(4);
757 if (status == QProcess::CrashExit || exitCode != 0) {
758 errorMessage(i18n("ISO creation process crashed."));
759 QString result(m_mkiso->readAllStandardError());
760 result.append("<a name=\"result\" /><br /><strong>");
761 result.append(i18n("ISO creation process crashed."));
762 m_status.error_log->append(result);
763 m_status.error_log->scrollToAnchor("result");
764 m_status.error_box->setHidden(false);
765 m_status.error_box->setTabBarHidden(false);
766 m_status.menu_file->setPlainText(m_menuFile.readAll());
767 m_status.dvd_file->setPlainText(m_authorFile.readAll());
772 kDebug() << "Iso process crashed";
773 isoitem->setIcon(KIcon("dialog-close"));
774 m_status.button_start->setEnabled(true);
775 m_status.button_abort->setEnabled(false);
779 m_creationLog.append(m_mkiso->readAllStandardError());
782 m_status.button_start->setEnabled(true);
783 m_status.button_abort->setEnabled(false);
785 // Check if DVD iso is ok
786 QFile iso(m_status.iso_image->url().path());
787 if (!iso.exists() || iso.size() == 0) {
789 KIO::NetAccess::del(m_status.iso_image->url(), this);
791 errorMessage(i18n("DVD ISO is broken"));
792 m_status.error_log->append(m_creationLog + "<br /><a name=\"result\" /><strong>" + i18n("DVD ISO is broken") + "</strong>");
793 m_status.error_log->scrollToAnchor("result");
794 m_status.error_box->setHidden(false);
795 m_status.error_box->setTabBarHidden(false);
796 m_status.menu_file->setPlainText(m_menuFile.readAll());
797 m_status.dvd_file->setPlainText(m_authorFile.readAll());
798 isoitem->setIcon(KIcon("dialog-close"));
803 isoitem->setIcon(KIcon("dialog-ok"));
804 kDebug() << "ISO IMAGE " << m_status.iso_image->url().path() << " Successfully created";
806 kDebug() << m_creationLog;
807 infoMessage(i18n("DVD ISO image %1 successfully created.", m_status.iso_image->url().path()));
809 m_status.error_log->append("<a name=\"result\" /><strong>" + i18n("DVD ISO image %1 successfully created.", m_status.iso_image->url().path()) + "</strong>");
810 m_status.error_log->scrollToAnchor("result");
811 m_status.button_preview->setEnabled(true);
812 m_status.button_burn->setEnabled(true);
813 m_status.error_box->setHidden(false);
814 //KMessageBox::information(this, i18n("DVD ISO image %1 successfully created.", m_status.iso_image->url().path()));
819 void DvdWizard::cleanup()
821 KIO::NetAccess::del(KUrl(m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"), this);
825 void DvdWizard::slotPreview()
827 QStringList programNames;
828 programNames << "xine" << "vlc";
830 foreach(const QString &prog, programNames) {
831 exec = KStandardDirs::findExe(prog);
832 if (!exec.isEmpty()) {
836 if (exec.isEmpty()) {
837 KMessageBox::sorry(this, i18n("Previewing requires one of these applications (%1)", programNames.join(",")));
839 else QProcess::startDetached(exec, QStringList() << "dvd://" + m_status.iso_image->url().path());
842 void DvdWizard::slotBurn()
844 QAction *action = qobject_cast<QAction *>(sender());
845 QString exec = action->data().toString();
847 if (exec.endsWith("k3b")) args << "--image" << m_status.iso_image->url().path();
848 else args << "--image=" + m_status.iso_image->url().path();
849 QProcess::startDetached(exec, args);
853 void DvdWizard::slotGenerate()
856 if ((m_dvdauthor && m_dvdauthor->state() != QProcess::NotRunning) || (m_mkiso && m_mkiso->state() != QProcess::NotRunning)) return;
857 for (int i = 0; i < m_status.job_progress->count(); i++)
858 m_status.job_progress->item(i)->setIcon(KIcon());
860 if (KIO::NetAccess::exists(KUrl(m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"), KIO::NetAccess::SourceSide, this))
861 warnMessage.append(i18n("Folder %1 already exists. Overwrite?\n", m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"));
862 if (KIO::NetAccess::exists(KUrl(m_status.iso_image->url().path()), KIO::NetAccess::SourceSide, this))
863 warnMessage.append(i18n("Image file %1 already exists. Overwrite?", m_status.iso_image->url().path()));
865 if (warnMessage.isEmpty() || KMessageBox::questionYesNo(this, warnMessage) == KMessageBox::Yes) {
866 KIO::NetAccess::del(KUrl(m_status.tmp_folder->url().path(KUrl::AddTrailingSlash) + "DVD"), this);
867 QTimer::singleShot(300, this, SLOT(generateDvd()));
868 m_status.button_preview->setEnabled(false);
869 m_status.button_burn->setEnabled(false);
870 m_status.job_progress->setEnabled(true);
871 m_status.button_start->setEnabled(false);
875 void DvdWizard::slotAbort()
878 if (m_dvdauthor && m_dvdauthor->state() != QProcess::NotRunning) m_dvdauthor->terminate();
879 else if (m_mkiso && m_mkiso->state() != QProcess::NotRunning) m_mkiso->terminate();
882 void DvdWizard::slotSave()
884 KUrl url = KFileDialog::getSaveUrl(KUrl("kfiledialog:///projectfolder"), "*.kdvd", this, i18n("Save DVD Project"));
885 if (url.isEmpty()) return;
887 if (currentId() == 0) m_pageChapters->setVobFiles(m_pageVob->dvdFormat(), m_pageVob->selectedUrls(), m_pageVob->durations(), m_pageVob->chapters());
890 QDomElement dvdproject = doc.createElement("dvdproject");
891 dvdproject.setAttribute("profile", m_pageVob->dvdProfile());
892 dvdproject.setAttribute("tmp_folder", m_status.tmp_folder->url().path());
893 dvdproject.setAttribute("iso_image", m_status.iso_image->url().path());
894 dvdproject.setAttribute("intro_movie", m_pageVob->introMovie());
896 doc.appendChild(dvdproject);
897 QDomElement menu = m_pageMenu->toXml();
898 if (!menu.isNull()) dvdproject.appendChild(doc.importNode(menu, true));
899 QDomElement chaps = m_pageChapters->toXml();
900 if (!chaps.isNull()) dvdproject.appendChild(doc.importNode(chaps, true));
902 QFile file(url.path());
903 if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
904 kWarning() << "////// ERROR writing to file: " << url.path();
905 KMessageBox::error(this, i18n("Cannot write to file %1", url.path()));
909 file.write(doc.toString().toUtf8());
910 if (file.error() != QFile::NoError) {
911 KMessageBox::error(this, i18n("Cannot write to file %1", url.path()));
917 void DvdWizard::slotLoad()
919 KUrl url = KFileDialog::getOpenUrl(KUrl("kfiledialog:///projectfolder"), "*.kdvd");
920 if (url.isEmpty()) return;
922 QFile file(url.path());
923 doc.setContent(&file, false);
925 QDomElement dvdproject = doc.documentElement();
926 if (dvdproject.tagName() != "dvdproject") {
927 KMessageBox::error(this, i18n("File %1 is not a Kdenlive project file.", url.path()));
931 QString profile = dvdproject.attribute("profile");
932 m_pageVob->setProfile(profile);
934 m_status.tmp_folder->setUrl(KUrl(dvdproject.attribute("tmp_folder")));
935 m_status.iso_image->setUrl(KUrl(dvdproject.attribute("iso_image")));
936 QString intro = dvdproject.attribute("intro_movie");
937 if (!intro.isEmpty()) {
938 m_pageVob->slotAddVobFile(KUrl(intro));
939 m_pageVob->setUseIntroMovie(true);
942 QDomNodeList vobs = doc.elementsByTagName("vob");
943 for (int i = 0; i < vobs.count(); i++) {
944 QDomElement e = vobs.at(i).toElement();
945 m_pageVob->slotAddVobFile(KUrl(e.attribute("file")), e.attribute("chapters"));
947 m_pageMenu->loadXml(m_pageVob->dvdFormat(), dvdproject.firstChildElement("menu"));