]> git.sesse.net Git - kdenlive/commitdiff
*Render dialog can now create xml files for dvd chapters based on guides (usable...
authorJean-Baptiste Mardelle <jb@kdenlive.org>
Tue, 12 May 2009 23:19:47 +0000 (23:19 +0000)
committerJean-Baptiste Mardelle <jb@kdenlive.org>
Tue, 12 May 2009 23:19:47 +0000 (23:19 +0000)
*Dvd wizard now supports chapters (through ".dvdchapter" files created by render dialog) and several buttons in menu, needs more testing...

svn path=/trunk/kdenlive/; revision=3382

src/customtrackview.cpp
src/dvdwizard.cpp
src/dvdwizardmenu.cpp
src/dvdwizardmenu.h
src/dvdwizardvob.cpp
src/dvdwizardvob.h
src/mainwindow.cpp
src/renderwidget.cpp
src/timecode.cpp
src/timecode.h

index 42d0c3dcfc48dbf1904549e9196e62292f5c2462..c42f5866566087a5954a104b45a37c2e430cd455 100644 (file)
@@ -677,11 +677,11 @@ void CustomTrackView::mousePressEvent(QMouseEvent * event)
                 }
             }
             // keep this to support multiple guides context menu in the future (?)
-                /*if (guidesCollisionList.at(0)->type() != GUIDEITEM)
-                    guidesCollisionList.removeAt(0);
+            /*if (guidesCollisionList.at(0)->type() != GUIDEITEM)
+                guidesCollisionList.removeAt(0);
             }
             if (!guidesCollisionList.isEmpty())
-                m_dragGuide = static_cast <Guide *>(guidesCollisionList.at(0));*/
+            m_dragGuide = static_cast <Guide *>(guidesCollisionList.at(0));*/
         }
 
         m_operationMode = NONE;
@@ -3509,7 +3509,7 @@ int CustomTrackView::hasGuide(int pos, int offset)
 {
     for (int i = 0; i < m_guides.count(); i++) {
         int guidePos = m_guides.at(i)->position().frames(m_document->fps());
-        if (qAbs(guidePos - pos) < offset) return guidePos;
+        if (qAbs(guidePos - pos) <= offset) return guidePos;
         else if (guidePos > pos) return -1;
     }
     return -1;
index 1daf23d0abc62809793edfd4317531e7c0bd1c6f..4f8711454fcfa39abe834bd24c51e9d05ad4e843 100644 (file)
@@ -111,11 +111,11 @@ DvdWizard::~DvdWizard()
 
 void DvdWizard::slotPageChanged(int page)
 {
-    kDebug() << "// PAGE CHGD: " << page;
+    kDebug() << "// PAGE CHGD: " << page;
     if (page == 1) {
-        m_pageMenu->setTargets(m_pageVob->selectedUrls());
+        m_pageMenu->setTargets(m_pageVob->selectedTitles(), m_pageVob->selectedTargets());
     } else if (page == 2) {
-        m_pageMenu->buttonsInfo();
+        //m_pageMenu->buttonsInfo();
     } else if (page == 3) {
         // clear job icons
         for (int i = 0; i < m_status.job_progress->count(); i++)
@@ -182,7 +182,7 @@ void DvdWizard::generateDvd()
     QListWidgetItem *images =  m_status.job_progress->item(0);
     images->setIcon(KIcon("system-run"));
     qApp->processEvents();
-    QMap <int, QRect> buttons = m_pageMenu->buttonsInfo();
+    QMap <QString, QRect> buttons = m_pageMenu->buttonsInfo();
     QStringList buttonsTarget;
 
     if (m_pageMenu->createMenu()) {
@@ -258,7 +258,7 @@ void DvdWizard::generateDvd()
 
         int max = buttons.count() - 1;
         int i = 0;
-        QMapIterator<int, QRect> it(buttons);
+        QMapIterator<QString, QRect> it(buttons);
         while (it.hasNext()) {
             it.next();
             QDomElement but = doc.createElement("button");
@@ -268,10 +268,10 @@ void DvdWizard::generateDvd()
             if (i > 0) but.setAttribute("up", 'b' + QString::number(i - 1));
             else but.setAttribute("up", 'b' + QString::number(max));
             QRect r = it.value();
-            int target = it.key();
+            //int target = it.key();
             // TODO: solve play all button
-            if (target == 0) target = 1;
-            buttonsTarget.append(QString::number(target));
+            //if (target == 0) target = 1;
+            buttonsTarget.append(it.key());
             but.setAttribute("x0", QString::number(r.x()));
             but.setAttribute("y0", QString::number(r.y()));
             but.setAttribute("x1", QString::number(r.right()));
@@ -363,7 +363,7 @@ void DvdWizard::generateDvd()
         for (int i = 0; i < buttons.count(); i++) {
             QDomElement button = dvddoc.createElement("button");
             button.setAttribute("name", 'b' + QString::number(i));
-            QDomText nametext = dvddoc.createTextNode("jump title " + buttonsTarget.at(i) + ';');
+            QDomText nametext = dvddoc.createTextNode("jump " + buttonsTarget.at(i) + ';');
             button.appendChild(nametext);
             pgc.appendChild(button);
         }
@@ -393,6 +393,23 @@ void DvdWizard::generateDvd()
             // Add vob entry
             QDomElement vob = dvddoc.createElement("vob");
             vob.setAttribute("file", voburls.at(i));
+            if (m_pageVob->useChapters()) {
+                // Add chapters
+                if (QFile::exists(voburls.at(i) + ".dvdchapter")) {
+                    QFile file(voburls.at(i) + ".dvdchapter");
+                    if (file.open(QIODevice::ReadOnly)) {
+                        QDomDocument doc;
+                        doc.setContent(&file);
+                        file.close();
+                        QDomNodeList chapters = doc.elementsByTagName("chapter");
+                        QStringList chaptersList;
+                        for (int j = 0; j < chapters.count(); j++) {
+                            chaptersList.append(chapters.at(j).toElement().attribute("time"));
+                        }
+                        if (!chaptersList.isEmpty()) vob.setAttribute("chapters", chaptersList.join(","));
+                    }
+                }
+            }
             pgc2.appendChild(vob);
         }
     }
index fefa8e80e412e2993506b9c090b72b4ac18114a4..68a69a73fd89ca9c2e5ea744bef2429e896b60af 100644 (file)
@@ -37,8 +37,8 @@ DvdWizardMenu::DvdWizardMenu(const QString &profile, QWidget *parent) :
     m_view.delete_button->setIcon(KIcon("trash-empty"));
 
     // TODO: re-enable add button options
-    m_view.add_button->setVisible(false);
-    m_view.delete_button->setVisible(false);
+    /*m_view.add_button->setVisible(false);
+    m_view.delete_button->setVisible(false);*/
 
     m_view.menu_profile->addItems(QStringList() << i18n("PAL") << i18n("NTSC"));
 
@@ -167,7 +167,7 @@ void DvdWizardMenu::setButtonTarget(int ix)
     for (int i = 0; i < list.count(); i++) {
         if (list.at(i)->type() == QGraphicsItem::UserType + 1) {
             DvdButton *button = static_cast < DvdButton* >(list.at(i));
-            button->setTarget(ix);
+            button->setTarget(ix, m_view.target_list->itemData(ix).toString());
             break;
         }
     }
@@ -263,16 +263,13 @@ void DvdWizardMenu::updatePreview()
     m_safeRect->setRect(safeW, safeH, m_width - 2 * safeW, m_height - 2 * safeH);
 }
 
-void DvdWizardMenu::setTargets(QStringList /*list*/)
+void DvdWizardMenu::setTargets(QStringList list, QStringList targetlist)
 {
-    m_targets = QStringList() << i18n("Play All");
-    // TODO: re-enable different targets
-    /*
-    if (list.count() > 1) {
-    m_targets += list;
+    m_view.target_list->clear();
+    m_view.target_list->addItem(i18n("Play All"), "title 1");
+    for (int i = 0; i < list.count(); i++) {
+        m_view.target_list->addItem(list.at(i), targetlist.at(i));
     }
-    m_view.target_list->clear();*/
-    m_view.target_list->addItems(m_targets);
 }
 
 void DvdWizardMenu::checkBackgroundType(int ix)
@@ -450,9 +447,9 @@ QString DvdWizardMenu::menuMoviePath() const
 }
 
 
-QMap <int, QRect> DvdWizardMenu::buttonsInfo()
+QMap <QString, QRect> DvdWizardMenu::buttonsInfo()
 {
-    QMap <int, QRect> info;
+    QMap <QString, QRect> info;
     QList<QGraphicsItem *> list = m_scene->items();
     for (int i = 0; i < list.count(); i++) {
         if (list.at(i)->type() == QGraphicsItem::UserType + 1) {
@@ -461,7 +458,7 @@ QMap <int, QRect> DvdWizardMenu::buttonsInfo()
             // Make sure y1 is not odd (requested by spumux)
             if (r.height() % 2 == 1) r.setHeight(r.height() + 1);
             if (r.y() % 2 == 1) r.setY(r.y() - 1);
-            info.insertMulti(button->target(), r);
+            info.insertMulti(button->command(), r);
         }
     }
     return info;
index 01a0c73ba25a9846e6ce101bdbb8c499f38bfd9c..ef37af245a5444419bcae2b253e68811439cfeab 100644 (file)
@@ -56,14 +56,18 @@ class DvdButton : public QGraphicsTextItem
 {
 
 public:
-    DvdButton(const QString & text): QGraphicsTextItem(text), m_target(0) {}
+    DvdButton(const QString & text): QGraphicsTextItem(text), m_target(0), m_command(QString("title 1")) {}
     enum { Type = UserType + 1 };
-    void setTarget(int t) {
+    void setTarget(int t, QString c) {
         m_target = t;
+        m_command = c;
     }
     int target() const {
         return m_target;
     }
+    QString command() const {
+        return m_command;
+    }
     int type() const {
         // Enable the use of qgraphicsitem_cast with this item.
         return Type;
@@ -71,7 +75,7 @@ public:
 
 private:
     int m_target;
-
+    QString m_command;
 
 protected:
 
@@ -112,8 +116,8 @@ public:
     bool createMenu() const;
     void createBackgroundImage(const QString &img1);
     void createButtonImages(const QString &img1, const QString &img2, const QString &img3);
-    void setTargets(QStringList list);
-    QMap <int, QRect> buttonsInfo();
+    void setTargets(QStringList list, QStringList targetlist);
+    QMap <QString, QRect> buttonsInfo();
     bool menuMovie() const;
     QString menuMoviePath() const;
     bool isPalMenu() const;
@@ -127,7 +131,6 @@ private:
     QGraphicsRectItem *m_safeRect;
     int m_width;
     int m_height;
-    QStringList m_targets;
 
 private slots:
     void buildButton();
index a9dbfc67ebd0dddd3ba794bf8fb9063f853ac9fd..c49d116ef6197d994cd036c5bb1621bede86b8c9 100644 (file)
@@ -25,6 +25,7 @@
 #include <KFileItem>
 
 #include <QHBoxLayout>
+#include <QDomDocument>
 
 DvdWizardVob::DvdWizardVob(QWidget *parent) :
         QWizardPage(parent)
@@ -69,6 +70,11 @@ bool DvdWizardVob::isComplete() const
     return false;
 }
 
+bool DvdWizardVob::useChapters() const
+{
+    return m_view.use_chapters->isChecked();
+}
+
 void DvdWizardVob::setUrl(const QString &url)
 {
     m_view.vob_1->setPath(url);
@@ -77,15 +83,76 @@ void DvdWizardVob::setUrl(const QString &url)
 QStringList DvdWizardVob::selectedUrls() const
 {
     QStringList result;
+    QString path;
+    QList<KUrlRequester *> allUrls = m_view.vob_list->findChildren<KUrlRequester *>();
+    for (int i = 0; i < allUrls.count(); i++) {
+        path = allUrls.at(i)->url().path();
+        if (!path.isEmpty()) {
+            result.append(path);
+        }
+    }
+    return result;
+}
+
+QStringList DvdWizardVob::selectedTitles() const
+{
+    QStringList result;
+    QString path;
     QList<KUrlRequester *> allUrls = m_view.vob_list->findChildren<KUrlRequester *>();
     for (int i = 0; i < allUrls.count(); i++) {
-        if (!allUrls.at(i)->url().path().isEmpty()) {
-            result.append(allUrls.at(i)->url().path());
+        path = allUrls.at(i)->url().path();
+        if (!path.isEmpty()) {
+            result.append(path);
+            if (useChapters() && QFile::exists(path + ".dvdchapter")) {
+                // insert chapters as targets
+                QFile file(path + ".dvdchapter");
+                if (file.open(QIODevice::ReadOnly)) {
+                    QDomDocument doc;
+                    doc.setContent(&file);
+                    file.close();
+                    QDomNodeList chapters = doc.elementsByTagName("chapter");
+                    QStringList chaptersList;
+                    for (int j = 0; j < chapters.count(); j++) {
+                        result.append(QString::number(j) + " - " + chapters.at(j).toElement().attribute("title") + " " + chapters.at(j).toElement().attribute("time"));
+                    }
+                }
+
+            }
+        }
+    }
+    return result;
+}
+
+QStringList DvdWizardVob::selectedTargets() const
+{
+    QStringList result;
+    QString path;
+    QList<KUrlRequester *> allUrls = m_view.vob_list->findChildren<KUrlRequester *>();
+    for (int i = 0; i < allUrls.count(); i++) {
+        path = allUrls.at(i)->url().path();
+        if (!path.isEmpty()) {
+            result.append("title " + QString::number(i));
+            if (useChapters() && QFile::exists(path + ".dvdchapter")) {
+                // insert chapters as targets
+                QFile file(path + ".dvdchapter");
+                if (file.open(QIODevice::ReadOnly)) {
+                    QDomDocument doc;
+                    doc.setContent(&file);
+                    file.close();
+                    QDomNodeList chapters = doc.elementsByTagName("chapter");
+                    QStringList chaptersList;
+                    for (int j = 0; j < chapters.count(); j++) {
+                        result.append("title " + QString::number(i + 1) + " chapter " + QString::number(j + 1));
+                    }
+                }
+
+            }
         }
     }
     return result;
 }
 
+
 QString DvdWizardVob::introMovie() const
 {
     if (!m_view.use_intro->isChecked()) return QString();
index 5544133c3ae0851593b2173f9b21efe58840b69c..0ce4a29752f946c51dca96110f1ce38bd6b44893 100644 (file)
@@ -40,8 +40,11 @@ public:
     virtual ~DvdWizardVob();
     virtual bool isComplete() const;
     QStringList selectedUrls() const;
+    QStringList selectedTitles() const;
+    QStringList selectedTargets() const;
     void setUrl(const QString &url);
     QString introMovie() const;
+    bool useChapters() const;
 
 private:
     Ui::DvdWizardVob_UI m_view;
index 8161941e18988ae2c5eb2c8cd0f2c00f8bc9be14..7750bc5773231d42c2e4ab4a8fd47d5fef0ceb25 100644 (file)
@@ -1567,6 +1567,7 @@ void MainWindow::slotDoRender(const QStringList args, const QStringList overlay_
     double guideEnd = args.at(6).toDouble();
     bool resizeProfile = args.at(7).toInt();
     QString scriptExport = args.at(8);
+    bool createChapterFile = args.at(9).toInt();
 
     if (dest.isEmpty()) return;
     int in = 0;
@@ -1576,6 +1577,7 @@ void MainWindow::slotDoRender(const QStringList args, const QStringList overlay_
         in = m_activeTimeline->inPoint();
         out = m_activeTimeline->outPoint();
     }
+
     KTemporaryFile temp;
     temp.setAutoRemove(false);
     temp.setSuffix(".westley");
@@ -1643,11 +1645,11 @@ void MainWindow::slotDoRender(const QStringList args, const QStringList overlay_
                 return;
             }
 
-            QTextStream out(&file);
-            out << "#! /bin/sh" << "\n" << "\n";
-            out << "SOURCE=" << "\"" + scriptExport + ".westley\"" << "\n";
-            out << "TARGET=" << "\"" + dest + "\"" << "\n";
-            out << renderer << " " << args.join(" ") << "\n" << "\n";
+            QTextStream outStream(&file);
+            outStream << "#! /bin/sh" << "\n" << "\n";
+            outStream << "SOURCE=" << "\"" + scriptExport + ".westley\"" << "\n";
+            outStream << "TARGET=" << "\"" + dest + "\"" << "\n";
+            outStream << renderer << " " << args.join(" ") << "\n" << "\n";
             if (file.error() != QFile::NoError) {
                 KMessageBox::error(this, i18n("Cannot write to file %1", scriptExport));
                 file.close();
@@ -1656,6 +1658,50 @@ void MainWindow::slotDoRender(const QStringList args, const QStringList overlay_
             file.close();
             QFile::setPermissions(scriptExport, file.permissions() | QFile::ExeUser);
         }
+
+        if (createChapterFile) {
+            QDomDocument doc;
+            QDomElement chapters = doc.createElement("chapters");
+            doc.appendChild(chapters);
+
+            QDomElement guidesxml = m_activeDocument->guidesXml();
+            if (!zoneOnly) out = (int) GenTime(m_activeDocument->projectDuration()).frames(m_activeDocument->fps());
+
+            QDomNodeList nodes = guidesxml.elementsByTagName("guide");
+            for (int i = 0; i < nodes.count(); i++) {
+                QDomElement e = nodes.item(i).toElement();
+                if (!e.isNull()) {
+                    QString comment = e.attribute("comment");
+                    int time = (int) GenTime(e.attribute("time").toDouble()).frames(m_activeDocument->fps());
+                    if (time >= in && time < out) {
+                       if (zoneOnly) time = time - in;
+                        QDomElement chapter = doc.createElement("chapter");
+                        chapters.appendChild(chapter);
+                        chapter.setAttribute("title", comment);
+                        chapter.setAttribute("time", Timecode::getStringTimecode(time, m_activeDocument->fps()));
+                    }
+                }
+            }
+            if (chapters.childNodes().count() > 0) {
+                if (m_activeTimeline->projectView()->hasGuide(out, 0) == -1) {
+                    // Always insert a guide in pos 0
+                    QDomElement chapter = doc.createElement("chapter");
+                    chapters.insertBefore(chapter, QDomNode());
+                    chapter.setAttribute("title", i18n("Start"));
+                    chapter.setAttribute("time", "0");
+                }
+                // save chapters file
+                QFile file(dest + ".dvdchapter");
+                if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+                    kWarning() << "//////  ERROR writing DVD CHAPTER file: " << dest + ".dvdchapter";
+                } else {
+                    file.write(doc.toString().toUtf8());
+                    if (file.error() != QFile::NoError)
+                        kWarning() << "//////  ERROR writing DVD CHAPTER file: " << dest + ".dvdchapter";
+                    file.close();
+                }
+            }
+        }
     }
 }
 
index fe582db823dc92e95e0fc039ad7378f867925d2f..d31b8195036299afc151707e6959d8fb4cf7ff5d 100644 (file)
@@ -141,6 +141,7 @@ RenderWidget::RenderWidget(const QString &projectfolder, QWidget * parent) :
     m_view.rescale_size->setEnabled(false);
     m_view.guides_box->setVisible(false);
     m_view.open_dvd->setVisible(false);
+    m_view.create_chapter->setVisible(false);
     m_view.open_browser->setVisible(false);
     m_view.error_box->setVisible(false);
 
@@ -671,26 +672,34 @@ void RenderWidget::slotExport(bool scriptExport)
     renderParameters << QString::number(m_view.render_zone->isChecked()) << QString::number(m_view.play_after->isChecked());
     renderParameters << QString::number(startPos) << QString::number(endPos) << QString::number(resizeProfile);
     renderParameters << scriptName;
-    renderItem->setData(1, Qt::UserRole + 3, renderParameters);
 
     // Set rendering type
     QString group = m_view.size_list->currentItem()->data(MetaGroupRole).toString();
-    if (group == "dvd" && m_view.open_dvd->isChecked()) {
-        renderItem->setData(0, Qt::UserRole, group);
-        if (renderArgs.contains("profile=")) {
-            // rendering profile contains an MLT profile, so pass it to the running jog item, useful for dvd
-            QString prof = renderArgs.section("profile=", 1, 1);
-            prof = prof.section(' ', 0, 0);
-            kDebug() << "// render profile: " << prof;
-            renderItem->setData(0, Qt::UserRole + 1, prof);
+    if (group == "dvd") {
+        renderParameters << QString::number(m_view.create_chapter->isChecked());
+        if (m_view.open_dvd->isChecked()) {
+            renderItem->setData(0, Qt::UserRole, group);
+            if (renderArgs.contains("profile=")) {
+                // rendering profile contains an MLT profile, so pass it to the running jog item, useful for dvd
+                QString prof = renderArgs.section("profile=", 1, 1);
+                prof = prof.section(' ', 0, 0);
+                kDebug() << "// render profile: " << prof;
+                renderItem->setData(0, Qt::UserRole + 1, prof);
+            }
+        }
+    } else {
+        renderParameters << QString::number(false);
+        if (group == "websites" && m_view.open_browser->isChecked()) {
+            renderItem->setData(0, Qt::UserRole, group);
+            // pass the url
+            QString url = m_view.size_list->currentItem()->data(ExtraRole).toString();
+            renderItem->setData(0, Qt::UserRole + 1, url);
         }
-    } else if (group == "websites" && m_view.open_browser->isChecked()) {
-        renderItem->setData(0, Qt::UserRole, group);
-        // pass the url
-        QString url = m_view.size_list->currentItem()->data(ExtraRole).toString();
-        renderItem->setData(0, Qt::UserRole + 1, url);
     }
 
+
+    renderItem->setData(1, Qt::UserRole + 3, renderParameters);
+
     checkRenderStatus();
     if (scriptName.isEmpty()) m_view.tabWidget->setCurrentIndex(1);
     else {
@@ -736,8 +745,13 @@ void RenderWidget::refreshView()
         destination = m_view.destination_list->itemData(m_view.destination_list->currentIndex()).toString();
 
 
-    if (destination == "dvd") m_view.open_dvd->setVisible(true);
-    else m_view.open_dvd->setVisible(false);
+    if (destination == "dvd") {
+        m_view.open_dvd->setVisible(true);
+        m_view.create_chapter->setVisible(true);
+    } else {
+        m_view.open_dvd->setVisible(false);
+        m_view.create_chapter->setVisible(false);
+    }
     if (destination == "websites") m_view.open_browser->setVisible(true);
     else m_view.open_browser->setVisible(false);
     if (!destination.isEmpty() && QString("dvd websites audioonly").contains(destination))
index 40e7b198d3fb2cd4f3ac8bdb165489cb4d45eff7..cc429252ca8eace7a3c3d5237a6b0adbae2c638a 100644 (file)
@@ -96,6 +96,26 @@ QString Timecode::getTimecodeFromFrames(int frames)
     return getTimecodeHH_MM_SS_FF(frames);
 }
 
+
+//static
+QString Timecode::getStringTimecode(int frames, const double &fps)
+{
+    // Returns the timecode in an hh:mm:ss format
+    int seconds = frames / (int) floor(fps + 0.5);
+    int minutes = seconds / 60;
+    seconds = seconds % 60;
+    int hours = minutes / 60;
+    minutes = minutes % 60;
+    QString text;
+    text.append(QString::number(hours).rightJustified(2, '0', false));
+    text.append(':');
+    text.append(QString::number(minutes).rightJustified(2, '0', false));
+    text.append(':');
+    text.append(QString::number(seconds).rightJustified(2, '0', false));
+    return text;
+}
+
+
 //static
 QString Timecode::getEasyTimecode(const GenTime & time, const double &fps)
 {
@@ -161,7 +181,6 @@ QString Timecode::getTimecodeHH_MM_SS_FF(int frames) const
     minutes = minutes % 60;
 
     QString text;
-
     text.append(QString::number(hours).rightJustified(2, '0', false));
     text.append(':');
     text.append(QString::number(minutes).rightJustified(2, '0', false));
index 00eae56aae0824fd2ccc885ba0584c7a8db70141..15c8167d7d74151f3302bc4901eb17d706c360c6 100644 (file)
@@ -51,6 +51,7 @@ public:
     QString getTimecode(const GenTime & time, double fps) const;
     int getFrameCount(const QString duration, double fps) const;
     static QString getEasyTimecode(const GenTime & time, const double &fps);
+    static QString getStringTimecode(int frames, const double &fps);
     QString getTimecodeFromFrames(int frames);
     int fps();