*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
}
}
// 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;
{
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;
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++)
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()) {
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");
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()));
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);
}
// 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);
}
}
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"));
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;
}
}
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)
}
-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) {
// 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;
{
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;
private:
int m_target;
-
+ QString m_command;
protected:
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;
QGraphicsRectItem *m_safeRect;
int m_width;
int m_height;
- QStringList m_targets;
private slots:
void buildButton();
#include <KFileItem>
#include <QHBoxLayout>
+#include <QDomDocument>
DvdWizardVob::DvdWizardVob(QWidget *parent) :
QWizardPage(parent)
return false;
}
+bool DvdWizardVob::useChapters() const
+{
+ return m_view.use_chapters->isChecked();
+}
+
void DvdWizardVob::setUrl(const QString &url)
{
m_view.vob_1->setPath(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();
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;
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;
in = m_activeTimeline->inPoint();
out = m_activeTimeline->outPoint();
}
+
KTemporaryFile temp;
temp.setAutoRemove(false);
temp.setSuffix(".westley");
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();
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();
+ }
+ }
+ }
}
}
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);
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 {
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))
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)
{
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));
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();