X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;ds=sidebyside;f=src%2Frenderwidget.cpp;h=175f0f2f91d03a0e2bffade17a34e95cf356ec2d;hb=1f91eb9e679b2aa34658289e5cac37f6a6b7fcd3;hp=e1c6ddad83a2fab84ed6ef423c06fe90cbb6eb4a;hpb=dc2ee8838848f4ef4cb16866f72d3704e018948e;p=kdenlive diff --git a/src/renderwidget.cpp b/src/renderwidget.cpp index e1c6ddad..175f0f2f 100644 --- a/src/renderwidget.cpp +++ b/src/renderwidget.cpp @@ -19,11 +19,19 @@ #include +#include +#include +#include +#include +#include +#include #include #include #include #include +#include +#include #include "kdenlivesettings.h" #include "renderwidget.h" @@ -35,9 +43,12 @@ const int StandardRole = GroupRole + 2; const int RenderRole = GroupRole + 3; const int ParamsRole = GroupRole + 4; const int EditableRole = GroupRole + 5; +const int MetaGroupRole = GroupRole + 6; +const int ExtraRole = GroupRole + 7; -RenderWidget::RenderWidget(QWidget * parent): QDialog(parent) { +RenderWidget::RenderWidget(const QString &projectfolder, QWidget * parent): QDialog(parent), m_projectFolder(projectfolder) { m_view.setupUi(this); + setWindowTitle(i18n("Rendering")); m_view.buttonDelete->setIcon(KIcon("trash-empty")); m_view.buttonDelete->setToolTip(i18n("Delete profile")); m_view.buttonDelete->setEnabled(false); @@ -55,13 +66,46 @@ RenderWidget::RenderWidget(QWidget * parent): QDialog(parent) { m_view.buttonInfo->setDown(true); } else m_view.advanced_params->hide(); + m_view.rescale_size->setInputMask("0099\\x0099"); + m_view.rescale_size->setText("320x240"); + + + QMenu *renderMenu = new QMenu(i18n("Start Rendering"), this); + QAction *renderAction = renderMenu->addAction(KIcon("file-new"), i18n("Render to File")); + connect(renderAction, SIGNAL(triggered()), this, SLOT(slotExport())); + QAction *scriptAction = renderMenu->addAction(KIcon("file-new"), i18n("Generate Script")); + connect(scriptAction, SIGNAL(triggered()), this, SLOT(slotGenerateScript())); + + m_view.buttonStart->setMenu(renderMenu); + m_view.buttonStart->setPopupMode(QToolButton::MenuButtonPopup); + m_view.buttonStart->setDefaultAction(renderAction); + m_view.buttonStart->setToolButtonStyle(Qt::ToolButtonTextOnly); + m_view.abort_job->setEnabled(false); + m_view.start_script->setEnabled(false); + m_view.delete_script->setEnabled(false); + + + parseProfiles(); + parseScriptFiles(); + + connect(m_view.start_script, SIGNAL(clicked()), this, SLOT(slotStartScript())); + connect(m_view.delete_script, SIGNAL(clicked()), this, SLOT(slotDeleteScript())); + connect(m_view.scripts_list, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(slotCheckScript())); + connect(m_view.running_jobs, SIGNAL(itemClicked(QTreeWidgetItem *, int)), this, SLOT(slotCheckJob())); + connect(m_view.buttonInfo, SIGNAL(clicked()), this, SLOT(showInfoPanel())); connect(m_view.buttonSave, SIGNAL(clicked()), this, SLOT(slotSaveProfile())); connect(m_view.buttonEdit, SIGNAL(clicked()), this, SLOT(slotEditProfile())); connect(m_view.buttonDelete, SIGNAL(clicked()), this, SLOT(slotDeleteProfile())); - connect(m_view.buttonStart, SIGNAL(clicked()), this, SLOT(slotExport())); + connect(m_view.abort_job, SIGNAL(clicked()), this, SLOT(slotAbortCurrentJob())); + connect(m_view.buttonClose, SIGNAL(clicked()), this, SLOT(hide())); + connect(m_view.buttonClose2, SIGNAL(clicked()), this, SLOT(hide())); + connect(m_view.buttonClose3, SIGNAL(clicked()), this, SLOT(hide())); + connect(m_view.rescale, SIGNAL(toggled(bool)), m_view.rescale_size, SLOT(setEnabled(bool))); + connect(m_view.destination_list, SIGNAL(activated(int)), this, SLOT(refreshView())); connect(m_view.out_file, SIGNAL(textChanged(const QString &)), this, SLOT(slotUpdateButtons())); + connect(m_view.out_file, SIGNAL(urlSelected(const KUrl &)), this, SLOT(slotUpdateButtons(const KUrl &))); connect(m_view.format_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshView())); connect(m_view.size_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshParams())); @@ -75,11 +119,36 @@ RenderWidget::RenderWidget(QWidget * parent): QDialog(parent) { connect(m_view.format_selection, SIGNAL(activated(int)), this, SLOT(refreshView())); m_view.buttonStart->setEnabled(false); + m_view.rescale_size->setEnabled(false); m_view.guides_box->setVisible(false); - parseProfiles(); + m_view.open_dvd->setVisible(false); + m_view.open_browser->setVisible(false); + m_view.error_box->setVisible(false); + m_view.splitter->setStretchFactor(1, 5); m_view.splitter->setStretchFactor(0, 2); + m_view.out_file->setMode(KFile::File); + + m_view.running_jobs->setHeaderLabels(QStringList() << QString() << i18n("File") << i18n("Progress")); + m_view.running_jobs->setItemDelegate(new RenderViewDelegate(this)); + + QHeaderView *header = m_view.running_jobs->header(); + QFontMetrics fm = fontMetrics(); + //header->resizeSection(0, fm.width("typical-name-for-a-torrent.torrent")); + header->setResizeMode(0, QHeaderView::Fixed); + header->resizeSection(0, 30); + header->setResizeMode(1, QHeaderView::Interactive); + header->resizeSection(1, fm.width("typical-name-for-a-file.torrent")); + header->setResizeMode(2, QHeaderView::Fixed); + header->resizeSection(1, width() * 2 / 3); + header->setResizeMode(2, QHeaderView::Interactive); + //header->setResizeMode(1, QHeaderView::Fixed); + + m_view.scripts_list->setHeaderLabels(QStringList() << i18n("Script Files")); + m_view.scripts_list->setItemDelegate(new RenderScriptDelegate(this)); + + focusFirstVisibleItem(); } @@ -95,6 +164,13 @@ void RenderWidget::showInfoPanel() { } } +void RenderWidget::setDocumentPath(const QString path) { + m_projectFolder = path; + const QString fileName = m_view.out_file->url().fileName(); + m_view.out_file->setUrl(KUrl(m_projectFolder + '/' + fileName)); + parseScriptFiles(); +} + void RenderWidget::slotUpdateGuideBox() { m_view.guides_box->setVisible(m_view.render_guide->isChecked()); } @@ -128,6 +204,21 @@ void RenderWidget::setGuides(QDomElement guidesxml, double duration) { m_view.guide_end->addItem(i18n("End"), QString::number(duration)); } +// Will be called when the user selects an output file via the file dialog. +// File extension will be added automatically. +void RenderWidget::slotUpdateButtons(KUrl url) { + if (m_view.out_file->url().isEmpty()) m_view.buttonStart->setEnabled(false); + else m_view.buttonStart->setEnabled(true); + if (url != 0) { + QListWidgetItem *item = m_view.size_list->currentItem(); + QString extension = item->data(ExtensionRole).toString(); + url = filenameWithExtension(url, extension); + m_view.out_file->setUrl(url); + } +} + +// Will be called when the user changes the output file path in the text line. +// File extension must NOT be added, would make editing impossible! void RenderWidget::slotUpdateButtons() { if (m_view.out_file->url().isEmpty()) m_view.buttonStart->setEnabled(false); else m_view.buttonStart->setEnabled(true); @@ -328,8 +419,29 @@ void RenderWidget::slotDeleteProfile() { focusFirstVisibleItem(); } +void RenderWidget::updateButtons() { + if (!m_view.size_list->currentItem() || m_view.size_list->currentItem()->isHidden()) { + m_view.buttonSave->setEnabled(false); + m_view.buttonDelete->setEnabled(false); + m_view.buttonEdit->setEnabled(false); + } else { + m_view.buttonSave->setEnabled(true); + if (m_view.size_list->currentItem()->data(EditableRole).toString().isEmpty()) { + m_view.buttonDelete->setEnabled(false); + m_view.buttonEdit->setEnabled(false); + } else { + m_view.buttonDelete->setEnabled(true); + m_view.buttonEdit->setEnabled(true); + } + } +} + + void RenderWidget::focusFirstVisibleItem() { - if (m_view.size_list->currentItem() && !m_view.size_list->currentItem()->isHidden()) return; + if (m_view.size_list->currentItem() && !m_view.size_list->currentItem()->isHidden()) { + updateButtons(); + return; + } for (uint ix = 0; ix < m_view.size_list->count(); ix++) { QListWidgetItem *item = m_view.size_list->item(ix); if (item && !item->isHidden()) { @@ -338,16 +450,42 @@ void RenderWidget::focusFirstVisibleItem() { } } if (!m_view.size_list->currentItem()) m_view.size_list->setCurrentRow(0); + updateButtons(); } -void RenderWidget::slotExport() { +void RenderWidget::slotExport(bool scriptExport) { QListWidgetItem *item = m_view.size_list->currentItem(); if (!item) return; - QFile f(m_view.out_file->url().path()); + + const QString dest = m_view.out_file->url().path(); + if (dest.isEmpty()) return; + QFile f(dest); if (f.exists()) { - if (KMessageBox::warningYesNo(this, i18n("File already exists. Do you want to overwrite it ?")) != KMessageBox::Yes) + if (KMessageBox::warningYesNo(this, i18n("Output file already exists. Do you want to overwrite it ?")) != KMessageBox::Yes) return; } + + QString scriptName; + if (scriptExport) { + bool ok; + int ix = 0; + QString scriptsFolder = m_projectFolder + "/scripts/"; + KStandardDirs::makeDir(scriptsFolder); + QString path = scriptsFolder + i18n("script") + QString::number(ix).rightJustified(3, '0', false) + ".sh"; + while (QFile::exists(path)) { + ix++; + path = scriptsFolder + i18n("script") + QString::number(ix).rightJustified(3, '0', false) + ".sh"; + } + scriptName = QInputDialog::getText(this, i18n("Create Render Script"), i18n("Script name (will be saved in: %1)", scriptsFolder), QLineEdit::Normal, KUrl(path).fileName(), &ok); + if (!ok || scriptName.isEmpty()) return; + scriptName.prepend(scriptsFolder); + QFile f(scriptName); + if (f.exists()) { + if (KMessageBox::warningYesNo(this, i18n("Script file already exists. Do you want to overwrite it ?")) != KMessageBox::Yes) + return; + } + } + QStringList overlayargs; if (m_view.tc_overlay->isChecked()) { QString filterFile = KStandardDirs::locate("appdata", "metadata.properties"); @@ -362,12 +500,75 @@ void RenderWidget::slotExport() { endPos = m_view.guide_end->itemData(m_view.guide_end->currentIndex()).toDouble(); } QString renderArgs = m_view.advanced_params->toPlainText(); - renderArgs.replace("%width", QString::number(m_profile.width)); - renderArgs.replace("%height", QString::number(m_profile.height)); + + // Adjust frame scale + int width; + int height; + if (m_view.rescale->isChecked() && m_view.rescale->isEnabled()) { + width = m_view.rescale_size->text().section('x', 0, 0).toInt(); + height = m_view.rescale_size->text().section('x', 1, 1).toInt(); + } else { + width = m_profile.width; + height = m_profile.height; + } renderArgs.replace("%dar", "@" + QString::number(m_profile.display_aspect_num) + "/" + QString::number(m_profile.display_aspect_den)); - if (m_view.force_progressive->isChecked()) renderArgs.append(" progressive=1"); - else renderArgs.append(" progressive=0"); - emit doRender(m_view.out_file->url().path(), item->data(RenderRole).toString(), overlayargs, renderArgs.simplified().split(' '), m_view.render_zone->isChecked(), m_view.play_after->isChecked(), startPos, endPos); + + // Adjust scanning + if (m_view.scanning_list->currentIndex() == 1) renderArgs.append(" progressive=1"); + else if (m_view.scanning_list->currentIndex() == 2) renderArgs.append(" progressive=0"); + + // disable audio if requested + if (!m_view.export_audio->isChecked()) + renderArgs.append(" an=1 "); + + // Check if the rendering profile is different from project profile, + // in which case we need to use the producer_comsumer from MLT + bool resizeProfile = false; + + QString std = renderArgs; + QString destination = m_view.destination_list->itemData(m_view.destination_list->currentIndex()).toString(); + if (std.contains(" s=")) { + QString subsize = std.section(" s=", 1, 1); + subsize = subsize.section(' ', 0, 0).toLower(); + const QString currentSize = QString::number(width) + 'x' + QString::number(height); + if (subsize != currentSize) resizeProfile = true; + } else if (destination != "audioonly") { + // Add current size parametrer + renderArgs.append(QString(" s=%1x%2").arg(width).arg(height)); + } + + // insert item in running jobs list + QTreeWidgetItem *renderItem; + QList existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1); + if (!existing.isEmpty()) renderItem = existing.at(0); + else renderItem = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << dest << QString()); + renderItem->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2)); + renderItem->setData(1, Qt::UserRole + 1, QTime::currentTime()); + + // 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, usefull 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 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); + } + + emit doRender(dest, item->data(RenderRole).toString(), overlayargs, renderArgs.simplified().split(' '), m_view.render_zone->isChecked(), m_view.play_after->isChecked(), startPos, endPos, resizeProfile, scriptName); + if (scriptName.isEmpty()) m_view.tabWidget->setCurrentIndex(1); + else { + QTimer::singleShot(400, this, SLOT(parseScriptFiles())); + m_view.tabWidget->setCurrentIndex(2); + } } void RenderWidget::setProfile(MltVideoProfile profile) { @@ -375,25 +576,62 @@ void RenderWidget::setProfile(MltVideoProfile profile) { //WARNING: this way to tell the video standard is a bit hackish... if (m_profile.description.contains("pal", Qt::CaseInsensitive) || m_profile.description.contains("25", Qt::CaseInsensitive) || m_profile.description.contains("50", Qt::CaseInsensitive)) m_view.format_selection->setCurrentIndex(0); else m_view.format_selection->setCurrentIndex(1); - m_view.force_progressive->setChecked(m_profile.progressive); + m_view.scanning_list->setCurrentIndex(0); refreshView(); } void RenderWidget::refreshView() { - QListWidgetItem *item = m_view.format_list->currentItem(); - if (!item) { - m_view.format_list->setCurrentRow(0); + m_view.size_list->blockSignals(true); + QListWidgetItem *sizeItem; + + QString destination; + if (m_view.destination_list->currentIndex() > 0) + 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 == "websites") m_view.open_browser->setVisible(true); + else m_view.open_browser->setVisible(false); + if (!destination.isEmpty() && QString("dvd websites audioonly").contains(destination)) + m_view.rescale->setEnabled(false); + else m_view.rescale->setEnabled(true); + // hide groups that are not in the correct destination + for (int i = 0; i < m_view.format_list->count(); i++) { + sizeItem = m_view.format_list->item(i); + if (sizeItem->data(MetaGroupRole).toString() == destination) + sizeItem->setHidden(false); + else sizeItem->setHidden(true); + } + + // activate first visible item + QListWidgetItem * item = m_view.format_list->currentItem(); + if (!item || item->isHidden()) { + for (int i = 0; i < m_view.format_list->count(); i++) { + if (!m_view.format_list->item(i)->isHidden()) { + m_view.format_list->setCurrentRow(i); + break; + } + } item = m_view.format_list->currentItem(); } if (!item) return; + int count = 0; + for (int i = 0; i < m_view.format_list->count() && count < 2; i++) { + if (!m_view.format_list->isRowHidden(i)) count++; + } + if (count > 1) m_view.format_list->setVisible(true); + else m_view.format_list->setVisible(false); QString std; QString group = item->text(); - QListWidgetItem *sizeItem; bool firstSelected = false; + const QStringList formatsList = KdenliveSettings::supportedformats(); + const QStringList vcodecsList = KdenliveSettings::videocodecs(); + const QStringList acodecsList = KdenliveSettings::audiocodecs(); + for (int i = 0; i < m_view.size_list->count(); i++) { sizeItem = m_view.size_list->item(i); - std = sizeItem->data(StandardRole).toString(); if (sizeItem->data(GroupRole) == group) { + std = sizeItem->data(StandardRole).toString(); if (!std.isEmpty()) { if (std.contains("PAL", Qt::CaseInsensitive)) sizeItem->setHidden(m_view.format_selection->currentIndex() != 0); else if (std.contains("NTSC", Qt::CaseInsensitive)) sizeItem->setHidden(m_view.format_selection->currentIndex() != 1); @@ -402,29 +640,101 @@ void RenderWidget::refreshView() { if (!firstSelected) m_view.size_list->setCurrentItem(sizeItem); firstSelected = true; } + + if (!sizeItem->isHidden()) { + // Make sure the selected profile uses an installed avformat codec / format + std = sizeItem->data(ParamsRole).toString(); + + if (!formatsList.isEmpty()) { + QString format; + if (std.startsWith("f=")) format = std.section("f=", 1, 1); + else if (std.contains(" f=")) format = std.section(" f=", 1, 1); + if (!format.isEmpty()) { + format = format.section(' ', 0, 0).toLower(); + if (!formatsList.contains(format)) { + kDebug() << "***** UNSUPPORTED F: " << format; + sizeItem->setHidden(true); + } + } + } + if (!acodecsList.isEmpty() && !sizeItem->isHidden()) { + QString format; + if (std.startsWith("acodec=")) format = std.section("acodec=", 1, 1); + else if (std.contains(" acodec=")) format = std.section(" acodec=", 1, 1); + if (!format.isEmpty()) { + format = format.section(' ', 0, 0).toLower(); + if (!acodecsList.contains(format)) { + kDebug() << "***** UNSUPPORTED ACODEC: " << format; + sizeItem->setHidden(true); + } + } + } + if (!vcodecsList.isEmpty() && !sizeItem->isHidden()) { + QString format; + if (std.startsWith("vcodec=")) format = std.section("vcodec=", 1, 1); + else if (std.contains(" vcodec=")) format = std.section(" vcodec=", 1, 1); + if (!format.isEmpty()) { + format = format.section(' ', 0, 0).toLower(); + if (!vcodecsList.contains(format)) { + kDebug() << "***** UNSUPPORTED VCODEC: " << format; + sizeItem->setHidden(true); + } + } + } + } } else sizeItem->setHidden(true); } focusFirstVisibleItem(); + m_view.size_list->blockSignals(false); + refreshParams(); +} + +KUrl RenderWidget::filenameWithExtension(KUrl url, QString extension) { + QString path; + if (!url.isEmpty()) { + path = url.path(); + int pos = path.lastIndexOf('.') + 1; + if (pos == 0) path.append('.' + extension); + else path = path.left(pos) + extension; + } else { + path = m_projectFolder + "/untitled." + extension; + } + return KUrl(path); } + void RenderWidget::refreshParams() { QListWidgetItem *item = m_view.size_list->currentItem(); - if (!item) return; + if (!item || item->isHidden()) { + m_view.advanced_params->clear(); + m_view.buttonStart->setEnabled(false); + return; + } QString params = item->data(ParamsRole).toString(); QString extension = item->data(ExtensionRole).toString(); m_view.advanced_params->setPlainText(params); - m_view.advanced_params->setToolTip(params); - KUrl url = m_view.out_file->url(); - if (!url.isEmpty()) { - QString path = url.path(); - int pos = path.lastIndexOf('.') + 1; - if (pos == 0) path.append('.') + extension; - else path = path.left(pos) + extension; - m_view.out_file->setUrl(KUrl(path)); + QString destination = m_view.destination_list->itemData(m_view.destination_list->currentIndex()).toString(); + if (params.contains(" s=") || destination == "audioonly") { + // profile has a fixed size, do not allow resize + m_view.rescale->setEnabled(false); + m_view.rescale_size->setEnabled(false); } else { - m_view.out_file->setUrl(KUrl(QDir::homePath() + "/untitled." + extension)); + m_view.rescale->setEnabled(true); + m_view.rescale_size->setEnabled(true); } + KUrl url = filenameWithExtension(m_view.out_file->url(), extension); + m_view.out_file->setUrl(url); +// if (!url.isEmpty()) { +// QString path = url.path(); +// int pos = path.lastIndexOf('.') + 1; +// if (pos == 0) path.append('.' + extension); +// else path = path.left(pos) + extension; +// m_view.out_file->setUrl(KUrl(path)); +// } else { +// m_view.out_file->setUrl(KUrl(QDir::homePath() + "/untitled." + extension)); +// } + m_view.out_file->setFilter("*." + extension); if (item->data(EditableRole).toString().isEmpty()) { m_view.buttonDelete->setEnabled(false); @@ -433,11 +743,14 @@ void RenderWidget::refreshParams() { m_view.buttonDelete->setEnabled(true); m_view.buttonEdit->setEnabled(true); } + m_view.buttonStart->setEnabled(true); } void RenderWidget::parseProfiles(QString group, QString profile) { m_view.size_list->clear(); m_view.format_list->clear(); + m_view.destination_list->clear(); + m_view.destination_list->addItem(KIcon("video-x-generic"), i18n("File rendering")); QString exportFile = KStandardDirs::locate("appdata", "export/profiles.xml"); parseFile(exportFile, false); exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml"); @@ -472,17 +785,39 @@ void RenderWidget::parseFile(QString exportFile, bool editable) { QString renderer; QString params; QString standard; + KIcon icon; QListWidgetItem *item; while (!groups.item(i).isNull()) { documentElement = groups.item(i).toElement(); + QDomNode gname = documentElement.elementsByTagName("groupname").at(0); + QString metagroupName; + QString metagroupId; + if (!gname.isNull()) { + metagroupName = gname.firstChild().nodeValue(); + metagroupId = gname.toElement().attribute("id"); + if (!metagroupName.isEmpty() && !m_view.destination_list->contains(metagroupName)) { + if (metagroupId == "dvd") icon = KIcon("media-optical"); + else if (metagroupId == "audioonly") icon = KIcon("audio-x-generic"); + else if (metagroupId == "websites") icon = KIcon("applications-internet"); + else if (metagroupId == "mediaplayers") icon = KIcon("applications-multimedia"); + else if (metagroupId == "lossless") icon = KIcon("drive-harddisk"); + m_view.destination_list->addItem(icon, i18n(metagroupName.toUtf8().data()), metagroupId); + } + } groupName = documentElement.attribute("name", QString::null); extension = documentElement.attribute("extension", QString::null); renderer = documentElement.attribute("renderer", QString::null); - if (m_view.format_list->findItems(groupName, Qt::MatchExactly).isEmpty()) - new QListWidgetItem(groupName, m_view.format_list); + if (m_view.format_list->findItems(groupName, Qt::MatchExactly).isEmpty()) { + item = new QListWidgetItem(groupName, m_view.format_list); + item->setData(MetaGroupRole, metagroupId); + } QDomNode n = groups.item(i).firstChild(); while (!n.isNull()) { + if (n.toElement().tagName() != "profile") { + n = n.nextSibling(); + continue; + } profileElement = n.toElement(); profileName = profileElement.attribute("name"); standard = profileElement.attribute("standard"); @@ -491,10 +826,12 @@ void RenderWidget::parseFile(QString exportFile, bool editable) { if (!prof_extension.isEmpty()) extension = prof_extension; item = new QListWidgetItem(profileName, m_view.size_list); item->setData(GroupRole, groupName); + item->setData(MetaGroupRole, metagroupId); item->setData(ExtensionRole, extension); item->setData(RenderRole, renderer); item->setData(StandardRole, standard); item->setData(ParamsRole, params); + if (profileElement.hasAttribute("url")) item->setData(ExtraRole, profileElement.attribute("url")); if (editable) item->setData(EditableRole, "true"); n = n.nextSibling(); } @@ -503,8 +840,148 @@ void RenderWidget::parseFile(QString exportFile, bool editable) { } } +void RenderWidget::setRenderJob(const QString &dest, int progress) { + QTreeWidgetItem *item; + QList existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1); + if (!existing.isEmpty()) item = existing.at(0); + else item = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << dest << QString()); + item->setData(2, Qt::UserRole, progress); + if (progress == 0) { + item->setIcon(0, KIcon("system-run")); + item->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2)); + item->setData(1, Qt::UserRole + 1, QTime::currentTime()); + slotCheckJob(); + } else { + QTime startTime = item->data(1, Qt::UserRole + 1).toTime(); + int seconds = startTime.secsTo(QTime::currentTime());; + const QString t = i18n("Estimated time %1", QTime().addSecs(seconds * (100 - progress) / progress).toString("hh:mm:ss")); + item->setData(1, Qt::UserRole, t); + } +} + +void RenderWidget::setRenderStatus(const QString &dest, int status, const QString &error) { + QTreeWidgetItem *item; + QList existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1); + if (!existing.isEmpty()) item = existing.at(0); + else item = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << dest << QString()); + if (status == -1) { + // Job finished successfully + item->setIcon(0, KIcon("dialog-ok")); + item->setData(2, Qt::UserRole, 100); + QTime startTime = item->data(1, Qt::UserRole + 1).toTime(); + int seconds = startTime.secsTo(QTime::currentTime()); + const QTime tm = QTime().addSecs(seconds); + const QString t = i18n("Rendering finished in %1", tm.toString("hh:mm:ss")); + item->setData(1, Qt::UserRole, t); + QString itemGroup = item->data(0, Qt::UserRole).toString(); + if (itemGroup == "dvd") { + emit openDvdWizard(item->text(1), item->data(0, Qt::UserRole + 1).toString()); + } else if (itemGroup == "websites") { + QString url = item->data(0, Qt::UserRole + 1).toString(); + if (!url.isEmpty()) KRun *openBrowser = new KRun(url, this); + } + } else if (status == -2) { + // Rendering crashed + item->setData(1, Qt::UserRole, i18n("Rendering crashed")); + item->setIcon(0, KIcon("dialog-close")); + item->setData(2, Qt::UserRole, 100); + m_view.error_log->append(i18n("Rendering of %1 crashed
", dest)); + m_view.error_log->append(error); + m_view.error_log->append("
"); + m_view.error_box->setVisible(true); + } else if (status == -3) { + // User aborted job + item->setData(1, Qt::UserRole, i18n("Rendering aborted")); + item->setIcon(0, KIcon("dialog-cancel")); + item->setData(2, Qt::UserRole, 100); + } + slotCheckJob(); +} + +void RenderWidget::slotAbortCurrentJob() { + QTreeWidgetItem *current = m_view.running_jobs->currentItem(); + if (current) emit abortProcess(current->text(1)); +} + +void RenderWidget::slotCheckJob() { + bool activate = false; + QTreeWidgetItem *current = m_view.running_jobs->currentItem(); + if (current) { + int percent = current->data(2, Qt::UserRole).toInt(); + if (percent < 100) activate = true; + } + m_view.abort_job->setEnabled(activate); +} + +void RenderWidget::parseScriptFiles() { + QStringList scriptsFilter; + scriptsFilter << "*.sh"; + m_view.scripts_list->clear(); + + QTreeWidgetItem *item; + // List the project scripts + QStringList scriptFiles = QDir(m_projectFolder + "/scripts").entryList(scriptsFilter, QDir::Files); + for (int i = 0; i < scriptFiles.size(); ++i) { + KUrl scriptpath(m_projectFolder + "/scripts/" + scriptFiles.at(i)); + item = new QTreeWidgetItem(m_view.scripts_list, QStringList() << scriptpath.fileName()); + QString target; + QFile file(scriptpath.path()); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + while (!file.atEnd()) { + QByteArray line = file.readLine(); + if (line.startsWith("TARGET=")) { + target = QString(line).section("TARGET=", 1); + target.remove(QChar('"')); + break; + } + } + file.close(); + } + item->setSizeHint(0, QSize(m_view.scripts_list->columnWidth(0), fontMetrics().height() * 2)); + item->setData(0, Qt::UserRole, target); + item->setData(0, Qt::UserRole + 1, scriptpath.path()); + } + bool activate = false; + QTreeWidgetItemIterator it(m_view.scripts_list); + if (*it) { + kDebug() << "// FOUND SCRIPT ITEM:" << (*it)->text(0); + // Selecting item does not work, why ??? + m_view.scripts_list->setCurrentItem(*it); + (*it)->setSelected(true); + activate = true; + } + kDebug() << "SELECTED SCRIPTS: " << m_view.scripts_list->selectedItems().count(); + m_view.start_script->setEnabled(activate); + m_view.delete_script->setEnabled(activate); +} +void RenderWidget::slotCheckScript() { + bool activate = false; + QTreeWidgetItemIterator it(m_view.scripts_list); + if (*it) activate = true; + m_view.start_script->setEnabled(activate); + m_view.delete_script->setEnabled(activate); +} -#include "renderwidget.moc" +void RenderWidget::slotStartScript() { + QTreeWidgetItem *item = m_view.scripts_list->currentItem(); + if (item) { + QString path = item->data(0, Qt::UserRole + 1).toString(); + QProcess::startDetached(path); + m_view.tabWidget->setCurrentIndex(1); + } +} +void RenderWidget::slotDeleteScript() { + QTreeWidgetItem *item = m_view.scripts_list->currentItem(); + if (item) { + QString path = item->data(0, Qt::UserRole + 1).toString(); + KIO::NetAccess::del(path + ".westley", this); + KIO::NetAccess::del(path, this); + parseScriptFiles(); + } +} +void RenderWidget::slotGenerateScript() { + slotExport(true); +} \ No newline at end of file