]> git.sesse.net Git - kdenlive/blob - src/renderwidget.cpp
Make sure icons have small size with non KDE window manager
[kdenlive] / src / renderwidget.cpp
1 /***************************************************************************
2  *   Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
3  *                                                                         *
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.                                   *
8  *                                                                         *
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.                          *
13  *                                                                         *
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  ***************************************************************************/
19
20
21 #include "renderwidget.h"
22 #include "kdenlivesettings.h"
23 #include "ui_saveprofile_ui.h"
24 #include "timecode.h"
25 #include "profilesdialog.h"
26
27 #include <KStandardDirs>
28 #include <KDebug>
29 #include <KMessageBox>
30 #include <KComboBox>
31 #include <KRun>
32 #include <KIO/NetAccess>
33 #include <KColorScheme>
34 #include <KNotification>
35 #include <KStartupInfo>
36
37 #include <QDomDocument>
38 #include <QItemDelegate>
39 #include <QTreeWidgetItem>
40 #include <QListWidgetItem>
41 #include <QHeaderView>
42 #include <QMenu>
43 #include <QInputDialog>
44 #include <QProcess>
45 #include <QDBusConnectionInterface>
46 #include <QDBusInterface>
47 #include <QThread>
48 #include <QScriptEngine>
49
50 const int GroupRole = Qt::UserRole;
51 const int ExtensionRole = GroupRole + 1;
52 const int StandardRole = GroupRole + 2;
53 const int RenderRole = GroupRole + 3;
54 const int ParamsRole = GroupRole + 4;
55 const int EditableRole = GroupRole + 5;
56 const int MetaGroupRole = GroupRole + 6;
57 const int ExtraRole = GroupRole + 7;
58 const int BitratesRole = GroupRole + 8;
59 const int DefaultBitrateRole = GroupRole + 9;
60 const int AudioBitratesRole = GroupRole + 10;
61 const int DefaultAudioBitrateRole = GroupRole + 11;
62
63 // Running job status
64 const int WAITINGJOB = 0;
65 const int RUNNINGJOB = 1;
66 const int FINISHEDJOB = 2;
67
68
69 RenderWidget::RenderWidget(const QString &projectfolder, bool enableProxy, MltVideoProfile profile, QWidget * parent) :
70         QDialog(parent),
71         m_projectFolder(projectfolder),
72         m_profile(profile),
73         m_blockProcessing(false)
74 {
75     m_view.setupUi(this);
76     int size = style()->pixelMetric(QStyle::PM_SmallIconSize);
77     QSize iconSize(size, size);
78     
79     setWindowTitle(i18n("Rendering"));
80     m_view.buttonDelete->setIconSize(iconSize);
81     m_view.buttonEdit->setIconSize(iconSize);
82     m_view.buttonSave->setIconSize(iconSize);
83     m_view.buttonInfo->setIconSize(iconSize);
84     m_view.buttonFavorite->setIconSize(iconSize);
85     
86     m_view.buttonDelete->setIcon(KIcon("trash-empty"));
87     m_view.buttonDelete->setToolTip(i18n("Delete profile"));
88     m_view.buttonDelete->setEnabled(false);
89
90     m_view.buttonEdit->setIcon(KIcon("document-properties"));
91     m_view.buttonEdit->setToolTip(i18n("Edit profile"));
92     m_view.buttonEdit->setEnabled(false);
93
94     m_view.buttonSave->setIcon(KIcon("document-new"));
95     m_view.buttonSave->setToolTip(i18n("Create new profile"));
96
97     m_view.buttonInfo->setIcon(KIcon("help-about"));
98     m_view.hide_log->setIcon(KIcon("go-down"));
99
100     m_view.buttonFavorite->setIcon(KIcon("favorites"));
101     m_view.buttonFavorite->setToolTip(i18n("Copy profile to favorites"));
102     
103     m_view.advanced_params->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5);
104     
105     m_view.buttonRender->setEnabled(false);
106     m_view.buttonGenerateScript->setEnabled(false);
107     m_view.rescale_box->setEnabled(false);
108     m_view.guides_box->setVisible(false);
109     m_view.open_dvd->setVisible(false);
110     m_view.create_chapter->setVisible(false);
111     m_view.open_browser->setVisible(false);
112     m_view.error_box->setVisible(false);
113     m_view.tc_type->setEnabled(false);
114     m_view.checkTwoPass->setEnabled(false);
115     
116     if (KdenliveSettings::showrenderparams()) {
117         m_view.buttonInfo->setDown(true);
118     } else m_view.advanced_params->hide();
119     
120     m_view.proxy_render->setHidden(!enableProxy);
121
122     KColorScheme scheme(palette().currentColorGroup(), KColorScheme::Window, KSharedConfig::openConfig(KdenliveSettings::colortheme()));
123     QColor bg = scheme.background(KColorScheme::NegativeBackground).color();
124     m_view.errorBox->setStyleSheet(QString("QGroupBox { background-color: rgb(%1, %2, %3); border-radius: 5px;}; ").arg(bg.red()).arg(bg.green()).arg(bg.blue()));
125     int height = QFontInfo(font()).pixelSize();
126     m_view.errorIcon->setPixmap(KIcon("dialog-warning").pixmap(height, height));
127     m_view.errorBox->setHidden(true);
128
129 #if KDE_IS_VERSION(4,7,0)
130     m_infoMessage = new KMessageWidget;
131     QGridLayout *s =  static_cast <QGridLayout*> (m_view.tab->layout());
132     s->addWidget(m_infoMessage, 16, 0, 1, -1);
133     m_infoMessage->setCloseButtonVisible(false);
134     m_infoMessage->hide();
135 #endif
136
137     m_view.encoder_threads->setMaximum(QThread::idealThreadCount());
138     m_view.encoder_threads->setValue(KdenliveSettings::encodethreads());
139     connect(m_view.encoder_threads, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateEncodeThreads(int)));
140
141     m_view.rescale_keep->setChecked(KdenliveSettings::rescalekeepratio());
142     connect(m_view.rescale_width, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateRescaleWidth(int)));
143     connect(m_view.rescale_height, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateRescaleHeight(int)));
144     m_view.rescale_keep->setIcon(KIcon("insert-link"));
145     m_view.rescale_keep->setToolTip(i18n("Preserve aspect ratio"));
146     connect(m_view.rescale_keep, SIGNAL(clicked()), this, SLOT(slotSwitchAspectRatio()));
147
148     connect(m_view.buttonRender, SIGNAL(clicked()), this, SLOT(slotPrepareExport()));
149     connect(m_view.buttonGenerateScript, SIGNAL(clicked()), this, SLOT(slotGenerateScript()));
150
151     m_view.abort_job->setEnabled(false);
152     m_view.start_script->setEnabled(false);
153     m_view.delete_script->setEnabled(false);
154
155     m_view.format_list->setAlternatingRowColors(true);
156     m_view.size_list->setAlternatingRowColors(true);
157
158     connect(m_view.export_audio, SIGNAL(stateChanged(int)), this, SLOT(slotUpdateAudioLabel(int)));
159     m_view.export_audio->setCheckState(Qt::PartiallyChecked);
160
161     parseProfiles();
162     parseScriptFiles();
163     m_view.running_jobs->setUniformRowHeights(false);
164     m_view.scripts_list->setUniformRowHeights(false);
165     connect(m_view.start_script, SIGNAL(clicked()), this, SLOT(slotStartScript()));
166     connect(m_view.delete_script, SIGNAL(clicked()), this, SLOT(slotDeleteScript()));
167     connect(m_view.scripts_list, SIGNAL(itemSelectionChanged()), this, SLOT(slotCheckScript()));
168     connect(m_view.running_jobs, SIGNAL(itemSelectionChanged()), this, SLOT(slotCheckJob()));
169     connect(m_view.running_jobs, SIGNAL(itemDoubleClicked(QTreeWidgetItem *, int)), this, SLOT(slotPlayRendering(QTreeWidgetItem *, int)));
170
171     connect(m_view.buttonInfo, SIGNAL(clicked()), this, SLOT(showInfoPanel()));
172
173     connect(m_view.buttonSave, SIGNAL(clicked()), this, SLOT(slotSaveProfile()));
174     connect(m_view.buttonEdit, SIGNAL(clicked()), this, SLOT(slotEditProfile()));
175     connect(m_view.buttonDelete, SIGNAL(clicked()), this, SLOT(slotDeleteProfile()));
176     connect(m_view.buttonFavorite, SIGNAL(clicked()), this, SLOT(slotCopyToFavorites()));
177
178     connect(m_view.abort_job, SIGNAL(clicked()), this, SLOT(slotAbortCurrentJob()));
179     connect(m_view.start_job, SIGNAL(clicked()), this, SLOT(slotStartCurrentJob()));
180     connect(m_view.clean_up, SIGNAL(clicked()), this, SLOT(slotCLeanUpJobs()));
181     connect(m_view.hide_log, SIGNAL(clicked()), this, SLOT(slotHideLog()));
182
183     connect(m_view.buttonClose, SIGNAL(clicked()), this, SLOT(hide()));
184     connect(m_view.buttonClose2, SIGNAL(clicked()), this, SLOT(hide()));
185     connect(m_view.buttonClose3, SIGNAL(clicked()), this, SLOT(hide()));
186     connect(m_view.rescale, SIGNAL(toggled(bool)), m_view.rescale_box, SLOT(setEnabled(bool)));
187     connect(m_view.destination_list, SIGNAL(activated(int)), this, SLOT(refreshCategory()));
188     connect(m_view.out_file, SIGNAL(textChanged(const QString &)), this, SLOT(slotUpdateButtons()));
189     connect(m_view.out_file, SIGNAL(urlSelected(const KUrl &)), this, SLOT(slotUpdateButtons(const KUrl &)));
190     connect(m_view.format_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshView()));
191     connect(m_view.size_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshParams()));
192
193     connect(m_view.size_list, SIGNAL(itemDoubleClicked(QListWidgetItem *)), this, SLOT(slotEditItem(QListWidgetItem *)));
194
195     connect(m_view.render_guide, SIGNAL(clicked(bool)), this, SLOT(slotUpdateGuideBox()));
196     connect(m_view.render_zone, SIGNAL(clicked(bool)), this, SLOT(slotUpdateGuideBox()));
197     connect(m_view.render_full, SIGNAL(clicked(bool)), this, SLOT(slotUpdateGuideBox()));
198
199     connect(m_view.guide_end, SIGNAL(activated(int)), this, SLOT(slotCheckStartGuidePosition()));
200     connect(m_view.guide_start, SIGNAL(activated(int)), this, SLOT(slotCheckEndGuidePosition()));
201
202     connect(m_view.tc_overlay, SIGNAL(toggled(bool)), m_view.tc_type, SLOT(setEnabled(bool)));
203
204     m_view.splitter->setStretchFactor(1, 5);
205     m_view.splitter->setStretchFactor(0, 2);
206
207     m_view.out_file->setMode(KFile::File);
208
209     m_view.running_jobs->setHeaderLabels(QStringList() << QString() << i18n("File") << i18n("Progress"));
210     m_jobsDelegate = new RenderViewDelegate(this);
211     m_view.running_jobs->setItemDelegate(m_jobsDelegate);
212
213     QHeaderView *header = m_view.running_jobs->header();
214     header->setResizeMode(0, QHeaderView::Fixed);
215     header->resizeSection(0, 30);
216     header->setResizeMode(1, QHeaderView::Interactive);
217     header->setResizeMode(2, QHeaderView::Fixed);
218     header->resizeSection(1, width() * 2 / 3 - 15);
219     header->setResizeMode(2, QHeaderView::Interactive);
220     //header->setResizeMode(1, QHeaderView::Fixed);
221
222
223     m_view.scripts_list->setHeaderLabels(QStringList() << QString() << i18n("Script Files"));
224     m_scriptsDelegate = new RenderViewDelegate(this);
225     m_view.scripts_list->setItemDelegate(m_scriptsDelegate);
226     header = m_view.scripts_list->header();
227     header->setResizeMode(0, QHeaderView::Fixed);
228     header->resizeSection(0, 30);
229
230     // Find path for Kdenlive renderer
231     m_renderer = QCoreApplication::applicationDirPath() + QString("/kdenlive_render");
232     if (!QFile::exists(m_renderer)) {
233         m_renderer = KStandardDirs::findExe("kdenlive_render");
234         if (m_renderer.isEmpty()) m_renderer = KStandardDirs::locate("exe", "kdenlive_render");
235         if (m_renderer.isEmpty()) m_renderer = "kdenlive_render";
236     }
237
238     QDBusConnectionInterface* interface = QDBusConnection::sessionBus().interface();
239     if (!interface || (!interface->isServiceRegistered("org.kde.ksmserver") && !interface->isServiceRegistered("org.gnome.SessionManager")))
240         m_view.shutdown->setEnabled(false);
241
242     focusFirstVisibleItem();
243     adjustSize();
244 }
245
246 QSize RenderWidget::sizeHint() const
247 {
248     // Make sure the widget has minimum size on opening
249     return QSize(200, 200);
250 }
251
252 RenderWidget::~RenderWidget()
253 {
254     m_view.running_jobs->blockSignals(true);
255     m_view.scripts_list->blockSignals(true);
256     m_view.running_jobs->clear();
257     m_view.scripts_list->clear();
258     delete m_jobsDelegate;
259     delete m_scriptsDelegate;
260 #if KDE_IS_VERSION(4,7,0)
261     delete m_infoMessage;
262 #endif
263 }
264
265 void RenderWidget::slotEditItem(QListWidgetItem *item)
266 {
267     QString edit = item->data(EditableRole).toString();
268     if (edit.isEmpty() || !edit.endsWith("customprofiles.xml")) slotSaveProfile();
269     else slotEditProfile();
270 }
271
272 void RenderWidget::showInfoPanel()
273 {
274     if (m_view.advanced_params->isVisible()) {
275         m_view.advanced_params->setVisible(false);
276         m_view.buttonInfo->setDown(false);
277         KdenliveSettings::setShowrenderparams(false);
278     } else {
279         m_view.advanced_params->setVisible(true);
280         m_view.buttonInfo->setDown(true);
281         KdenliveSettings::setShowrenderparams(true);
282     }
283 }
284
285 void RenderWidget::setDocumentPath(const QString &path)
286 {
287     if (m_view.out_file->url().directory() == KUrl(m_projectFolder).directory()) {
288         const QString fileName = m_view.out_file->url().fileName();
289         m_view.out_file->setUrl(KUrl(path + fileName));
290     }
291     m_projectFolder = path;
292     parseScriptFiles();
293
294 }
295
296 void RenderWidget::slotUpdateGuideBox()
297 {
298     m_view.guides_box->setVisible(m_view.render_guide->isChecked());
299 }
300
301 void RenderWidget::slotCheckStartGuidePosition()
302 {
303     if (m_view.guide_start->currentIndex() > m_view.guide_end->currentIndex())
304         m_view.guide_start->setCurrentIndex(m_view.guide_end->currentIndex());
305 }
306
307 void RenderWidget::slotCheckEndGuidePosition()
308 {
309     if (m_view.guide_end->currentIndex() < m_view.guide_start->currentIndex())
310         m_view.guide_end->setCurrentIndex(m_view.guide_start->currentIndex());
311 }
312
313 void RenderWidget::setGuides(QDomElement guidesxml, double duration)
314 {
315     m_view.guide_start->clear();
316     m_view.guide_end->clear();
317     QDomNodeList nodes = guidesxml.elementsByTagName("guide");
318     if (nodes.count() > 0) {
319         m_view.guide_start->addItem(i18n("Beginning"), "0");
320         m_view.render_guide->setEnabled(true);
321         m_view.create_chapter->setEnabled(true);
322     } else {
323         m_view.render_guide->setEnabled(false);
324         m_view.create_chapter->setEnabled(false);
325     }
326     double fps = (double) m_profile.frame_rate_num / m_profile.frame_rate_den;
327     for (int i = 0; i < nodes.count(); i++) {
328         QDomElement e = nodes.item(i).toElement();
329         if (!e.isNull()) {
330             GenTime pos = GenTime(e.attribute("time").toDouble());
331             const QString guidePos = Timecode::getStringTimecode(pos.frames(fps), fps);
332             m_view.guide_start->addItem(e.attribute("comment") + '/' + guidePos, e.attribute("time").toDouble());
333             m_view.guide_end->addItem(e.attribute("comment") + '/' + guidePos, e.attribute("time").toDouble());
334         }
335     }
336     if (nodes.count() > 0)
337         m_view.guide_end->addItem(i18n("End"), QString::number(duration));
338 }
339
340 /**
341  * Will be called when the user selects an output file via the file dialog.
342  * File extension will be added automatically.
343  */
344 void RenderWidget::slotUpdateButtons(KUrl url)
345 {
346     if (m_view.out_file->url().isEmpty()) {
347         m_view.buttonGenerateScript->setEnabled(false);
348         m_view.buttonRender->setEnabled(false);
349     } else {
350         updateButtons(); // This also checks whether the selected format is available
351     }
352     if (url != 0) {
353         QListWidgetItem *item = m_view.size_list->currentItem();
354         if (!item) {
355             m_view.buttonRender->setEnabled(false);
356             m_view.buttonGenerateScript->setEnabled(false);
357             return;
358         }
359         QString extension = item->data(ExtensionRole).toString();
360         url = filenameWithExtension(url, extension);
361         m_view.out_file->setUrl(url);
362     }
363 }
364
365 /**
366  * Will be called when the user changes the output file path in the text line.
367  * File extension must NOT be added, would make editing impossible!
368  */
369 void RenderWidget::slotUpdateButtons()
370 {
371     if (m_view.out_file->url().isEmpty()) {
372         m_view.buttonRender->setEnabled(false);
373         m_view.buttonGenerateScript->setEnabled(false);
374     } else {
375         updateButtons(); // This also checks whether the selected format is available
376     }
377 }
378
379 void RenderWidget::slotSaveProfile()
380 {
381     //TODO: update to correctly use metagroups
382     Ui::SaveProfile_UI ui;
383     QDialog *d = new QDialog(this);
384     ui.setupUi(d);
385
386     for (int i = 0; i < m_view.destination_list->count(); i++)
387         ui.destination_list->addItem(m_view.destination_list->itemIcon(i), m_view.destination_list->itemText(i), m_view.destination_list->itemData(i, Qt::UserRole));
388
389     ui.destination_list->setCurrentIndex(m_view.destination_list->currentIndex());
390     QString dest = ui.destination_list->itemData(ui.destination_list->currentIndex(), Qt::UserRole).toString();
391
392     QString customGroup = m_view.format_list->currentItem()->text();
393     if (customGroup.isEmpty()) customGroup = i18nc("Group Name", "Custom");
394     ui.group_name->setText(customGroup);
395
396     QStringList arguments = m_view.advanced_params->toPlainText().split(" ", QString::SkipEmptyParts);
397     ui.parameters->setText(arguments.join(" "));
398     ui.extension->setText(m_view.size_list->currentItem()->data(ExtensionRole).toString());
399     ui.profile_name->setFocus();
400
401     if (d->exec() == QDialog::Accepted && !ui.profile_name->text().simplified().isEmpty()) {
402         QString newProfileName = ui.profile_name->text().simplified();
403         QString newGroupName = ui.group_name->text().simplified();
404         if (newGroupName.isEmpty()) newGroupName = i18nc("Group Name", "Custom");
405         QString newMetaGroupId = ui.destination_list->itemData(ui.destination_list->currentIndex(), Qt::UserRole).toString();
406
407         QDomDocument doc;
408         QDomElement profileElement = doc.createElement("profile");
409         profileElement.setAttribute("name", newProfileName);
410         profileElement.setAttribute("category", newGroupName);
411         profileElement.setAttribute("destinationid", newMetaGroupId);
412         profileElement.setAttribute("extension", ui.extension->text().simplified());
413         QString args = ui.parameters->toPlainText().simplified();
414         profileElement.setAttribute("args", args);
415         if (args.contains("%bitrate")) {
416             // profile has a variable bitrate
417             profileElement.setAttribute("defaultbitrate", m_view.comboBitrates->currentText());
418             QStringList bitrateValues;
419             for (int i = 0; i < m_view.comboBitrates->count(); i++)
420                 bitrateValues << m_view.comboBitrates->itemText(i);
421             profileElement.setAttribute("bitrates", bitrateValues.join(","));
422         }
423         if (args.contains("%audiobitrate")) {
424             // profile has a variable bitrate
425             profileElement.setAttribute("defaultaudiobitrate", m_view.comboAudioBitrates->currentText());
426             QStringList bitrateValues;
427             for (int i = 0; i < m_view.comboAudioBitrates->count(); i++)
428                 bitrateValues << m_view.comboAudioBitrates->itemText(i);
429             profileElement.setAttribute("audiobitrates", bitrateValues.join(","));
430         }
431         doc.appendChild(profileElement);
432         saveProfile(doc.documentElement());
433
434         parseProfiles(newMetaGroupId, newGroupName, newProfileName);
435     }
436     delete d;
437 }
438
439
440 void RenderWidget::saveProfile(QDomElement newprofile)
441 {
442     QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
443     QDomDocument doc;
444     QFile file(exportFile);
445     doc.setContent(&file, false);
446     file.close();
447     QDomElement documentElement;
448     QDomElement profiles = doc.documentElement();
449     if (profiles.isNull() || profiles.tagName() != "profiles") {
450         doc.clear();
451         profiles = doc.createElement("profiles");
452         profiles.setAttribute("version", 1);
453         doc.appendChild(profiles);
454     }
455     int version = profiles.attribute("version", 0).toInt();
456     if (version < 1) {
457         kDebug() << "// OLD profile version";
458         doc.clear();
459         profiles = doc.createElement("profiles");
460         profiles.setAttribute("version", 1);
461         doc.appendChild(profiles);
462     }
463
464
465     QDomNodeList profilelist = doc.elementsByTagName("profile");
466     int i = 0;
467     while (!profilelist.item(i).isNull()) {
468         // make sure a profile with same name doesn't exist
469         documentElement = profilelist.item(i).toElement();
470         QString profileName = documentElement.attribute("name");
471         if (profileName == newprofile.attribute("name")) {
472             // a profile with that same name already exists
473             bool ok;
474             QString newProfileName = QInputDialog::getText(this, i18n("Profile already exists"), i18n("This profile name already exists. Change the name if you don't want to overwrite it."), QLineEdit::Normal, profileName, &ok);
475             if (!ok) return;
476             if (profileName == newProfileName) {
477                 profiles.removeChild(profilelist.item(i));
478                 break;
479             }
480         }
481         i++;
482     }
483
484     profiles.appendChild(newprofile);
485
486     //QCString save = doc.toString().utf8();
487
488     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
489         KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
490         return;
491     }
492     QTextStream out(&file);
493     out << doc.toString();
494     if (file.error() != QFile::NoError) {
495         KMessageBox::error(this, i18n("Cannot write to file %1", exportFile));
496         file.close();
497         return;
498     }
499     file.close();
500 }
501
502 void RenderWidget::slotCopyToFavorites()
503 {
504     QListWidgetItem *item = m_view.size_list->currentItem();
505     if (!item) return;
506     QString currentGroup = m_view.format_list->currentItem()->text();
507
508     QString params = item->data(ParamsRole).toString();
509     QString extension = item->data(ExtensionRole).toString();
510     QString currentProfile = item->text();
511     QDomDocument doc;
512     QDomElement profileElement = doc.createElement("profile");
513     profileElement.setAttribute("name", currentProfile);
514     profileElement.setAttribute("category", i18nc("Category Name", "Custom"));
515     profileElement.setAttribute("destinationid", "favorites");
516     profileElement.setAttribute("extension", extension);
517     profileElement.setAttribute("args", params);
518     profileElement.setAttribute("bitrates", item->data(BitratesRole).toStringList().join(","));
519     profileElement.setAttribute("defaultbitrate", item->data(DefaultBitrateRole).toString());
520     profileElement.setAttribute("audiobitrates", item->data(AudioBitratesRole).toStringList().join(","));
521     profileElement.setAttribute("defaultaudiobitrate", item->data(DefaultAudioBitrateRole).toString());
522     doc.appendChild(profileElement);
523     saveProfile(doc.documentElement());
524     parseProfiles(m_view.destination_list->itemData(m_view.destination_list->currentIndex(), Qt::UserRole).toString(), currentGroup, currentProfile);
525 }
526
527 void RenderWidget::slotEditProfile()
528 {
529     QListWidgetItem *item = m_view.size_list->currentItem();
530     if (!item) return;
531     QString currentGroup = m_view.format_list->currentItem()->text();
532
533     QString params = item->data(ParamsRole).toString();
534     QString extension = item->data(ExtensionRole).toString();
535     QString currentProfile = item->text();
536
537     Ui::SaveProfile_UI ui;
538     QDialog *d = new QDialog(this);
539     ui.setupUi(d);
540
541     for (int i = 0; i < m_view.destination_list->count(); i++)
542         ui.destination_list->addItem(m_view.destination_list->itemIcon(i), m_view.destination_list->itemText(i), m_view.destination_list->itemData(i, Qt::UserRole));
543
544     ui.destination_list->setCurrentIndex(m_view.destination_list->currentIndex());
545     QString dest = ui.destination_list->itemData(ui.destination_list->currentIndex(), Qt::UserRole).toString();
546
547     QString customGroup = m_view.format_list->currentItem()->text();
548     if (customGroup.isEmpty()) customGroup = i18nc("Group Name", "Custom");
549     ui.group_name->setText(customGroup);
550
551     ui.profile_name->setText(currentProfile);
552     ui.extension->setText(extension);
553     ui.parameters->setText(params);
554     ui.profile_name->setFocus();
555     d->setWindowTitle(i18n("Edit Profile"));
556     if (d->exec() == QDialog::Accepted) {
557         slotDeleteProfile(false);
558         QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
559         QDomDocument doc;
560         QFile file(exportFile);
561         doc.setContent(&file, false);
562         file.close();
563         QDomElement documentElement;
564         QDomElement profiles = doc.documentElement();
565
566         if (profiles.isNull() || profiles.tagName() != "profiles") {
567             doc.clear();
568             profiles = doc.createElement("profiles");
569             profiles.setAttribute("version", 1);
570             doc.appendChild(profiles);
571         }
572
573         int version = profiles.attribute("version", 0).toInt();
574         if (version < 1) {
575             kDebug() << "// OLD profile version";
576             doc.clear();
577             profiles = doc.createElement("profiles");
578             profiles.setAttribute("version", 1);
579             doc.appendChild(profiles);
580         }
581
582         QString newProfileName = ui.profile_name->text().simplified();
583         QString newGroupName = ui.group_name->text().simplified();
584         if (newGroupName.isEmpty()) newGroupName = i18nc("Group Name", "Custom");
585         QString newMetaGroupId = ui.destination_list->itemData(ui.destination_list->currentIndex(), Qt::UserRole).toString();
586         QDomNodeList profilelist = doc.elementsByTagName("profile");
587         int i = 0;
588         while (!profilelist.item(i).isNull()) {
589             // make sure a profile with same name doesn't exist
590             documentElement = profilelist.item(i).toElement();
591             QString profileName = documentElement.attribute("name");
592             if (profileName == newProfileName) {
593                 // a profile with that same name already exists
594                 bool ok;
595                 newProfileName = QInputDialog::getText(this, i18n("Profile already exists"), i18n("This profile name already exists. Change the name if you don't want to overwrite it."), QLineEdit::Normal, newProfileName, &ok);
596                 if (!ok) return;
597                 if (profileName == newProfileName) {
598                     profiles.removeChild(profilelist.item(i));
599                     break;
600                 }
601             }
602             i++;
603         }
604
605         QDomElement profileElement = doc.createElement("profile");
606         profileElement.setAttribute("name", newProfileName);
607         profileElement.setAttribute("category", newGroupName);
608         profileElement.setAttribute("destinationid", newMetaGroupId);
609         profileElement.setAttribute("extension", ui.extension->text().simplified());
610         QString args = ui.parameters->toPlainText().simplified();
611         profileElement.setAttribute("args", args);
612         if (args.contains("%bitrate")) {
613             // profile has a variable bitrate
614             profileElement.setAttribute("defaultbitrate", m_view.comboBitrates->currentText());
615             QStringList bitrateValues;
616             for (int i = 0; i < m_view.comboBitrates->count(); i++)
617                 bitrateValues << m_view.comboBitrates->itemText(i);
618             profileElement.setAttribute("bitrates", bitrateValues.join(","));
619         }
620         if (args.contains("%audiobitrate")) {
621             // profile has a variable bitrate
622             profileElement.setAttribute("defaultaudiobitrate", m_view.comboAudioBitrates->currentText());
623             QStringList bitrateValues;
624             for (int i = 0; i < m_view.comboAudioBitrates->count(); i++)
625                 bitrateValues << m_view.comboAudioBitrates->itemText(i);
626             profileElement.setAttribute("audiobitrates", bitrateValues.join(","));
627         }
628
629         profiles.appendChild(profileElement);
630
631         //QCString save = doc.toString().utf8();
632         delete d;
633         if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
634             KMessageBox::error(this, i18n("Cannot write to file %1", exportFile));
635             return;
636         }
637         QTextStream out(&file);
638         out << doc.toString();
639         if (file.error() != QFile::NoError) {
640             KMessageBox::error(this, i18n("Cannot write to file %1", exportFile));
641             file.close();
642             return;
643         }
644         file.close();
645         parseProfiles(newMetaGroupId, newGroupName, newProfileName);
646     } else delete d;
647 }
648
649 void RenderWidget::slotDeleteProfile(bool refresh)
650 {
651     //TODO: delete a profile installed by KNewStuff the easy way
652     /*
653     QString edit = m_view.size_list->currentItem()->data(EditableRole).toString();
654     if (!edit.endsWith("customprofiles.xml")) {
655         // This is a KNewStuff installed file, process through KNS
656         KNS::Engine engine(0);
657         if (engine.init("kdenlive_render.knsrc")) {
658             KNS::Entry::List entries;
659         }
660         return;
661     }*/
662     QString currentGroup = m_view.format_list->currentItem()->text();
663     QString currentProfile = m_view.size_list->currentItem()->text();
664     QString metaGroupId = m_view.destination_list->itemData(m_view.destination_list->currentIndex(), Qt::UserRole).toString();
665
666     QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
667     QDomDocument doc;
668     QFile file(exportFile);
669     doc.setContent(&file, false);
670     file.close();
671
672     QDomElement documentElement;
673     QDomNodeList profiles = doc.elementsByTagName("profile");
674     int i = 0;
675     QString groupName;
676     QString profileName;
677     QString destination;
678
679     while (!profiles.item(i).isNull()) {
680         documentElement = profiles.item(i).toElement();
681         profileName = documentElement.attribute("name");
682         groupName = documentElement.attribute("category");
683         destination = documentElement.attribute("destinationid");
684
685         if (profileName == currentProfile && groupName == currentGroup && destination == metaGroupId) {
686             kDebug() << "// GOT it: " << profileName;
687             doc.documentElement().removeChild(profiles.item(i));
688             break;
689         }
690         i++;
691     }
692
693     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
694         KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
695         return;
696     }
697     QTextStream out(&file);
698     out << doc.toString();
699     if (file.error() != QFile::NoError) {
700         KMessageBox::error(this, i18n("Cannot write to file %1", exportFile));
701         file.close();
702         return;
703     }
704     file.close();
705     if (refresh) {
706         parseProfiles(metaGroupId, currentGroup);
707         focusFirstVisibleItem();
708     }
709 }
710
711 void RenderWidget::updateButtons()
712 {
713     if (!m_view.size_list->currentItem() || m_view.size_list->currentItem()->isHidden()) {
714         m_view.buttonSave->setEnabled(false);
715         m_view.buttonDelete->setEnabled(false);
716         m_view.buttonEdit->setEnabled(false);
717         m_view.buttonRender->setEnabled(false);
718         m_view.buttonGenerateScript->setEnabled(false);
719     } else {
720         m_view.buttonSave->setEnabled(true);
721         m_view.buttonRender->setEnabled(m_view.size_list->currentItem()->toolTip().isEmpty());
722         m_view.buttonGenerateScript->setEnabled(m_view.size_list->currentItem()->toolTip().isEmpty());
723         QString edit = m_view.size_list->currentItem()->data(EditableRole).toString();
724         if (edit.isEmpty() || !edit.endsWith("customprofiles.xml")) {
725             m_view.buttonDelete->setEnabled(false);
726             m_view.buttonEdit->setEnabled(false);
727         } else {
728             m_view.buttonDelete->setEnabled(true);
729             m_view.buttonEdit->setEnabled(true);
730         }
731     }
732 }
733
734
735 void RenderWidget::focusFirstVisibleItem()
736 {
737     if (m_view.size_list->currentItem()) {
738         updateButtons();
739         return;
740     }
741     m_view.size_list->setCurrentRow(0);
742     updateButtons();
743 }
744
745 void RenderWidget::slotPrepareExport(bool scriptExport)
746 {
747     if (!QFile::exists(KdenliveSettings::rendererpath())) {
748         KMessageBox::sorry(this, i18n("Cannot find the melt program required for rendering (part of Mlt)"));
749         return;
750     }
751     if (m_view.play_after->isChecked() && KdenliveSettings::defaultplayerapp().isEmpty()) {
752         KMessageBox::sorry(this, i18n("Cannot play video after rendering because the default video player application is not set.\nPlease define it in Kdenlive settings dialog."));
753     }
754     QString chapterFile;
755     if (m_view.create_chapter->isChecked()) chapterFile = m_view.out_file->url().path() + ".dvdchapter";
756
757     // mantisbt 1051
758     if (!KStandardDirs::makeDir(m_view.out_file->url().directory())) {
759         KMessageBox::sorry(this, i18n("The directory %1, could not be created.\nPlease make sure you have the required permissions.", m_view.out_file->url().directory()));
760         return;
761     }
762
763     emit prepareRenderingData(scriptExport, m_view.render_zone->isChecked(), chapterFile);
764 }
765
766
767 void RenderWidget::slotExport(bool scriptExport, int zoneIn, int zoneOut, const QString &playlistPath, const QString &scriptPath, bool exportAudio)
768 {
769     QListWidgetItem *item = m_view.size_list->currentItem();
770     if (!item) return;
771
772     QString dest = m_view.out_file->url().path();
773     if (dest.isEmpty()) return;
774
775     // Check whether target file has an extension.
776     // If not, ask whether extension should be added or not.
777     QString extension = item->data(ExtensionRole).toString();
778     if (!dest.endsWith(extension, Qt::CaseInsensitive)) {
779         if (KMessageBox::questionYesNo(this, i18n("File has no extension. Add extension (%1)?", extension)) == KMessageBox::Yes) {
780             dest.append("." + extension);
781         }
782     }
783
784     QFile f(dest);
785     if (f.exists()) {
786         if (KMessageBox::warningYesNo(this, i18n("Output file already exists. Do you want to overwrite it?")) != KMessageBox::Yes)
787             return;
788     }
789
790     QStringList overlayargs;
791     if (m_view.tc_overlay->isChecked()) {
792         QString filterFile = KStandardDirs::locate("appdata", "metadata.properties");
793         overlayargs << "meta.attr.timecode=1" << "meta.attr.timecode.markup=#" + QString(m_view.tc_type->currentIndex() ? "frame" : "timecode");
794         overlayargs << "-attach" << "data_feed:attr_check" << "-attach";
795         overlayargs << "data_show:" + filterFile << "_loader=1" << "dynamic=1";
796     }
797
798     QStringList render_process_args;
799
800     if (!scriptExport) render_process_args << "-erase";
801     if (KdenliveSettings::usekuiserver()) render_process_args << "-kuiserver";
802
803     // get process id
804     render_process_args << QString("-pid:%1").arg(QCoreApplication::applicationPid());
805
806     // Set locale for render process if required
807     if (QLocale().decimalPoint() != QLocale::system().decimalPoint()) {
808         render_process_args << QString("-locale:%1").arg(QLocale().name());
809     }
810
811     double guideStart = 0;
812     double guideEnd = 0;
813
814     if (m_view.render_zone->isChecked()) render_process_args << "in=" + QString::number(zoneIn) << "out=" + QString::number(zoneOut);
815     else if (m_view.render_guide->isChecked()) {
816         double fps = (double) m_profile.frame_rate_num / m_profile.frame_rate_den;
817         guideStart = m_view.guide_start->itemData(m_view.guide_start->currentIndex()).toDouble();
818         guideEnd = m_view.guide_end->itemData(m_view.guide_end->currentIndex()).toDouble();
819         render_process_args << "in=" + QString::number((int) GenTime(guideStart).frames(fps)) << "out=" + QString::number((int) GenTime(guideEnd).frames(fps));
820     }
821
822     if (!overlayargs.isEmpty()) render_process_args << "preargs=" + overlayargs.join(" ");
823
824     if (scriptExport)
825         render_process_args << "$MELT";
826     else
827         render_process_args << KdenliveSettings::rendererpath();
828     render_process_args << m_profile.path << item->data(RenderRole).toString();
829     if (m_view.play_after->isChecked()) render_process_args << KdenliveSettings::KdenliveSettings::defaultplayerapp();
830     else render_process_args << "-";
831
832     QString renderArgs = m_view.advanced_params->toPlainText().simplified();
833
834     // Adjust frame scale
835     int width;
836     int height;
837     if (m_view.rescale->isChecked() && m_view.rescale->isEnabled()) {
838         width = m_view.rescale_width->value();
839         height = m_view.rescale_height->value();
840     } else {
841         width = m_profile.width;
842         height = m_profile.height;
843     }
844
845     //renderArgs.replace("%width", QString::number((int)(m_profile.height * m_profile.display_aspect_num / (double) m_profile.display_aspect_den + 0.5)));
846     //renderArgs.replace("%height", QString::number((int)m_profile.height));
847
848     // Adjust scanning
849     if (m_view.scanning_list->currentIndex() == 1) renderArgs.append(" progressive=1");
850     else if (m_view.scanning_list->currentIndex() == 2) renderArgs.append(" progressive=0");
851
852     // disable audio if requested
853     if (!exportAudio) renderArgs.append(" an=1 ");
854
855     // Set the thread counts
856     if (!renderArgs.contains("threads=")) {
857         renderArgs.append(QString(" threads=%1").arg(KdenliveSettings::encodethreads()));
858     }
859     renderArgs.append(QString(" real_time=-%1").arg(KdenliveSettings::mltthreads()));
860
861     // Check if the rendering profile is different from project profile,
862     // in which case we need to use the producer_comsumer from MLT
863     QString std = renderArgs;
864     QString destination = m_view.destination_list->itemData(m_view.destination_list->currentIndex()).toString();
865     const QString currentSize = QString::number(width) + 'x' + QString::number(height);
866     QString subsize = currentSize;
867     if (std.startsWith("s=")) {
868         subsize = std.section(' ', 0, 0).toLower();
869         subsize = subsize.section('=', 1, 1);
870     } else if (std.contains(" s=")) {
871         subsize = std.section(" s=", 1, 1);
872         subsize = subsize.section(' ', 0, 0).toLower();
873     } else if (destination != "audioonly" && m_view.rescale->isChecked() && m_view.rescale->isEnabled()) {
874         subsize = QString(" s=%1x%2").arg(width).arg(height);
875         // Add current size parameter
876         renderArgs.append(subsize);
877     }
878     bool resizeProfile = (subsize != currentSize);
879     QStringList paramsList = renderArgs.split(" ", QString::SkipEmptyParts);
880
881     QScriptEngine sEngine;
882     sEngine.globalObject().setProperty("bitrate", m_view.comboBitrates->currentText());
883     sEngine.globalObject().setProperty("audiobitrate", m_view.comboAudioBitrates->currentText());
884     sEngine.globalObject().setProperty("dar", '@' + QString::number(m_profile.display_aspect_num) + '/' + QString::number(m_profile.display_aspect_den));
885     sEngine.globalObject().setProperty("passes", static_cast<int>(m_view.checkTwoPass->isChecked()) + 1);
886
887     for (int i = 0; i < paramsList.count(); ++i) {
888         QString paramName = paramsList.at(i).section('=', 0, 0);
889         QString paramValue = paramsList.at(i).section('=', 1, 1);
890         // If the profiles do not match we need to use the consumer tag
891         if (paramName == "mlt_profile=" && paramValue != m_profile.path) {
892             resizeProfile = true;
893         }
894         // evaluate expression
895         if (paramValue.startsWith('%')) {
896             paramValue = sEngine.evaluate(paramValue.remove(0, 1)).toString();
897             paramsList[i] = paramName + '=' + paramValue;
898         }
899         sEngine.globalObject().setProperty(paramName.toUtf8().constData(), paramValue);
900     }
901
902     if (resizeProfile)
903         render_process_args << "consumer:" + (scriptExport ? "$SOURCE" : playlistPath);
904     else
905         render_process_args <<  (scriptExport ? "$SOURCE" : playlistPath);
906     render_process_args << (scriptExport ? "$TARGET" : KUrl(dest).url());
907     render_process_args << paramsList;
908
909     QString group = m_view.size_list->currentItem()->data(MetaGroupRole).toString();
910
911     QString scriptName;
912     if (scriptExport) {
913         // Generate script file
914         QFile file(scriptPath);
915         if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
916             KMessageBox::error(this, i18n("Cannot write to file %1", scriptPath));
917             return;
918         }
919         QTextStream outStream(&file);
920         outStream << "#! /bin/sh" << "\n" << "\n";
921         outStream << "SOURCE=" << "\"" + playlistPath + "\"" << "\n";
922         outStream << "TARGET=" << "\"" + KUrl(dest).url() + "\"" << "\n";
923         outStream << "RENDERER=" << "\"" + m_renderer + "\"" << "\n";
924         outStream << "MELT=" << "\"" + KdenliveSettings::rendererpath() + "\"" << "\n";
925         outStream << "PARAMETERS=" << "\"" + render_process_args.join(" ") + "\"" << "\n";
926         outStream << "$RENDERER $PARAMETERS" << "\n" << "\n";
927         if (file.error() != QFile::NoError) {
928             KMessageBox::error(this, i18n("Cannot write to file %1", scriptPath));
929             file.close();
930             return;
931         }
932         file.close();
933         QFile::setPermissions(scriptPath, file.permissions() | QFile::ExeUser);
934
935         QTimer::singleShot(400, this, SLOT(parseScriptFiles()));
936         m_view.tabWidget->setCurrentIndex(2);
937         return;
938     }
939
940     // Save rendering profile to document
941     QMap <QString, QString> renderProps;
942     renderProps.insert("renderdestination", m_view.size_list->currentItem()->data(MetaGroupRole).toString());
943     renderProps.insert("rendercategory", m_view.size_list->currentItem()->data(GroupRole).toString());
944     renderProps.insert("renderprofile", m_view.size_list->currentItem()->text());
945     renderProps.insert("renderurl", dest);
946     renderProps.insert("renderzone", QString::number(m_view.render_zone->isChecked()));
947     renderProps.insert("renderguide", QString::number(m_view.render_guide->isChecked()));
948     renderProps.insert("renderstartguide", QString::number(m_view.guide_start->currentIndex()));
949     renderProps.insert("renderendguide", QString::number(m_view.guide_end->currentIndex()));
950     renderProps.insert("renderendguide", QString::number(m_view.guide_end->currentIndex()));
951     renderProps.insert("renderscanning", QString::number(m_view.scanning_list->currentIndex()));
952     int export_audio = 0;
953     if (m_view.export_audio->checkState() == Qt::Checked) export_audio = 2;
954     else if (m_view.export_audio->checkState() == Qt::Unchecked) export_audio = 1;
955     renderProps.insert("renderexportaudio", QString::number(export_audio));
956     renderProps.insert("renderrescale", QString::number(m_view.rescale->isChecked()));
957     renderProps.insert("renderrescalewidth", QString::number(m_view.rescale_width->value()));
958     renderProps.insert("renderrescaleheight", QString::number(m_view.rescale_height->value()));
959     renderProps.insert("rendertcoverlay", QString::number(m_view.tc_overlay->isChecked()));
960     renderProps.insert("rendertctype", QString::number(m_view.tc_type->currentIndex()));
961     renderProps.insert("renderratio", QString::number(m_view.rescale_keep->isChecked()));
962     renderProps.insert("renderplay", QString::number(m_view.play_after->isChecked()));
963     renderProps.insert("rendertwopass", QString::number(m_view.checkTwoPass->isChecked()));
964
965     emit selectedRenderProfile(renderProps);
966
967     // insert item in running jobs list
968     QTreeWidgetItem *renderItem;
969     QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1);
970     if (!existing.isEmpty()) {
971         renderItem = existing.at(0);
972         if (renderItem->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB) {
973             KMessageBox::information(this, i18n("There is already a job writing file:<br /><b>%1</b><br />Abort the job if you want to overwrite it...", dest), i18n("Already running"));
974             return;
975         }
976         renderItem->setData(1, Qt::UserRole + 4, QString());
977     } else {
978         renderItem = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << dest << QString());
979     }
980     renderItem->setData(1, Qt::UserRole + 2, WAITINGJOB);
981     renderItem->setIcon(0, KIcon("media-playback-pause"));
982     renderItem->setData(1, Qt::UserRole, i18n("Waiting..."));
983     renderItem->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
984     renderItem->setData(1, Qt::UserRole + 1, QTime::currentTime());
985
986     // Set rendering type
987     if (group == "dvd") {
988         if (m_view.open_dvd->isChecked()) {
989             renderItem->setData(0, Qt::UserRole, group);
990             if (renderArgs.contains("mlt_profile=")) {
991                 // rendering profile contains an MLT profile, so pass it to the running jog item, useful for dvd
992                 QString prof = renderArgs.section("mlt_profile=", 1, 1);
993                 prof = prof.section(' ', 0, 0);
994                 kDebug() << "// render profile: " << prof;
995                 renderItem->setData(0, Qt::UserRole + 1, prof);
996             }
997         }
998     } else {
999         if (group == "websites" && m_view.open_browser->isChecked()) {
1000             renderItem->setData(0, Qt::UserRole, group);
1001             // pass the url
1002             QString url = m_view.size_list->currentItem()->data(ExtraRole).toString();
1003             renderItem->setData(0, Qt::UserRole + 1, url);
1004         }
1005     }
1006     renderItem->setData(1, Qt::UserRole + 3, render_process_args);
1007     if (exportAudio == false) renderItem->setData(1, Qt::UserRole + 5, i18n("Video without audio track"));
1008     else  renderItem->setData(1, Qt::UserRole + 5, QString());
1009     m_view.running_jobs->setCurrentItem(renderItem);
1010     m_view.tabWidget->setCurrentIndex(1);
1011     checkRenderStatus();
1012 }
1013
1014 void RenderWidget::checkRenderStatus()
1015 {
1016     // check if we have a job waiting to render
1017     if (m_blockProcessing) return;
1018     QTreeWidgetItem *item = m_view.running_jobs->topLevelItem(0);
1019     while (item) {
1020         if (item->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB) return;
1021         item = m_view.running_jobs->itemBelow(item);
1022     }
1023     item = m_view.running_jobs->topLevelItem(0);
1024     bool waitingJob = false;
1025     while (item) {
1026         if (item->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB) {
1027             item->setData(1, Qt::UserRole + 1, QTime::currentTime());
1028             waitingJob = true;
1029             startRendering(item);
1030             break;
1031         }
1032         item = m_view.running_jobs->itemBelow(item);
1033     }
1034     if (waitingJob == false && m_view.shutdown->isChecked()) emit shutdown();
1035 }
1036
1037 void RenderWidget::startRendering(QTreeWidgetItem *item)
1038 {
1039     if (item->data(1, Qt::UserRole + 4).isNull()) {
1040         // Normal render process
1041         if (QProcess::startDetached(m_renderer, item->data(1, Qt::UserRole + 3).toStringList()) == false) {
1042             item->setData(1, Qt::UserRole + 2, FINISHEDJOB);
1043             item->setData(1, Qt::UserRole, i18n("Rendering crashed"));
1044             item->setIcon(0, KIcon("dialog-close"));
1045             item->setData(2, Qt::UserRole, 100);
1046         } else {
1047             KNotification::event("RenderStarted", i18n("Rendering <i>%1</i> started", item->text(1)), QPixmap(), this);
1048         }
1049     } else {
1050         // Script item
1051         if (QProcess::startDetached(item->data(1, Qt::UserRole + 3).toString()) == false) {
1052             item->setData(1, Qt::UserRole + 2, FINISHEDJOB);
1053             item->setData(1, Qt::UserRole, i18n("Rendering crashed"));
1054             item->setIcon(0, KIcon("dialog-close"));
1055             item->setData(2, Qt::UserRole, 100);
1056         }
1057     }
1058 }
1059
1060 int RenderWidget::waitingJobsCount() const
1061 {
1062     int count = 0;
1063     QTreeWidgetItem *item = m_view.running_jobs->topLevelItem(0);
1064     while (item) {
1065         if (item->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB) count++;
1066         item = m_view.running_jobs->itemBelow(item);
1067     }
1068     return count;
1069 }
1070
1071 void RenderWidget::setProfile(MltVideoProfile profile)
1072 {
1073     m_view.scanning_list->setCurrentIndex(0);
1074     m_view.rescale_width->setValue(KdenliveSettings::defaultrescalewidth());
1075     if (!m_view.rescale_keep->isChecked()) {
1076         m_view.rescale_height->blockSignals(true);
1077         m_view.rescale_height->setValue(KdenliveSettings::defaultrescaleheight());
1078         m_view.rescale_height->blockSignals(false);
1079     }
1080     if (m_profile != profile) {
1081         m_profile = profile;
1082         refreshView();
1083     }
1084 }
1085
1086 void RenderWidget::refreshCategory()
1087 {
1088     m_view.format_list->blockSignals(true);
1089     m_view.format_list->clear();
1090     QListWidgetItem *sizeItem;
1091
1092     QString destination;
1093     if (m_view.destination_list->currentIndex() > 0)
1094         destination = m_view.destination_list->itemData(m_view.destination_list->currentIndex()).toString();
1095
1096
1097     if (destination == "dvd") {
1098         m_view.open_dvd->setVisible(true);
1099         m_view.create_chapter->setVisible(true);
1100     } else {
1101         m_view.open_dvd->setVisible(false);
1102         m_view.create_chapter->setVisible(false);
1103     }
1104
1105     if (destination == "websites")
1106         m_view.open_browser->setVisible(true);
1107     else
1108         m_view.open_browser->setVisible(false);
1109
1110     // hide groups that are not in the correct destination
1111     for (int i = 0; i < m_renderCategory.count(); i++) {
1112         sizeItem = m_renderCategory.at(i);
1113         if (sizeItem->data(MetaGroupRole).toString() == destination) {
1114             m_view.format_list->addItem(sizeItem->clone());
1115             //kDebug() << "// SET GRP:: " << sizeItem->text() << ", METY:" << sizeItem->data(MetaGroupRole).toString();
1116         }
1117     }
1118
1119     // activate first visible item
1120     QListWidgetItem * item = m_view.format_list->currentItem();
1121     if (!item) {
1122         m_view.format_list->setCurrentRow(0);
1123         item = m_view.format_list->currentItem();
1124     }
1125     if (!item) {
1126         m_view.format_list->setEnabled(false);
1127         m_view.format_list->clear();
1128         m_view.size_list->setEnabled(false);
1129         m_view.size_list->clear();
1130         m_view.size_list->blockSignals(false);
1131         m_view.format_list->blockSignals(false);
1132         return;
1133     } else {
1134         m_view.format_list->setEnabled(true);
1135         m_view.size_list->setEnabled(true);
1136     }
1137
1138     if (m_view.format_list->count() > 1)
1139         m_view.format_list->setVisible(true);
1140     else
1141         m_view.format_list->setVisible(false);
1142     refreshView();
1143 }
1144
1145 void RenderWidget::refreshView()
1146 {
1147     if (!m_view.format_list->currentItem()) return;
1148     m_view.size_list->blockSignals(true);
1149     m_view.size_list->clear();
1150     QListWidgetItem *sizeItem;
1151     QString std;
1152     QString group = m_view.format_list->currentItem()->text();
1153     QString destination;
1154     if (m_view.destination_list->currentIndex() > 0)
1155         destination = m_view.destination_list->itemData(m_view.destination_list->currentIndex()).toString();
1156     KIcon brokenIcon("dialog-close");
1157     KIcon warningIcon("dialog-warning");
1158
1159     const QStringList formatsList = KdenliveSettings::supportedformats();
1160     const QStringList vcodecsList = KdenliveSettings::videocodecs();
1161     const QStringList acodecsList = KdenliveSettings::audiocodecs();
1162
1163     KColorScheme scheme(palette().currentColorGroup(), KColorScheme::Window);
1164     const QColor disabled = scheme.foreground(KColorScheme::InactiveText).color();
1165     const QColor disabledbg = scheme.background(KColorScheme::NegativeBackground).color();
1166
1167     double project_framerate = (double) m_profile.frame_rate_num / m_profile.frame_rate_den;
1168     for (int i = 0; i < m_renderItems.count(); i++) {
1169         sizeItem = m_renderItems.at(i);
1170         QListWidgetItem *dupItem = NULL;
1171         if ((sizeItem->data(GroupRole).toString() == group || sizeItem->data(GroupRole).toString().isEmpty()) && sizeItem->data(MetaGroupRole).toString() == destination) {
1172             std = sizeItem->data(StandardRole).toString();
1173             if (!std.isEmpty()) {
1174                 if ((std.contains("PAL", Qt::CaseInsensitive) && m_profile.frame_rate_num == 25 && m_profile.frame_rate_den == 1) ||
1175                     (std.contains("NTSC", Qt::CaseInsensitive) && m_profile.frame_rate_num == 30000 && m_profile.frame_rate_den == 1001))
1176                     dupItem = sizeItem->clone();
1177             } else {
1178                 dupItem = sizeItem->clone();
1179             }
1180
1181             if (dupItem) {
1182                 m_view.size_list->addItem(dupItem);
1183                 std = dupItem->data(ParamsRole).toString();
1184                 // Make sure the selected profile uses the same frame rate as project profile
1185                 if (std.contains("mlt_profile=")) {
1186                     QString profile = std.section("mlt_profile=", 1, 1).section(' ', 0, 0);
1187                     MltVideoProfile p = ProfilesDialog::getVideoProfile(profile);
1188                     if (p.frame_rate_den > 0) {
1189                         double profile_rate = (double) p.frame_rate_num / p.frame_rate_den;
1190                         if ((int) (1000.0 * profile_rate) != (int) (1000.0 * project_framerate)) {
1191                             dupItem->setToolTip(i18n("Frame rate (%1) not compatible with project profile (%2)", profile_rate, project_framerate));
1192                             dupItem->setIcon(brokenIcon);
1193                             dupItem->setForeground(disabled);
1194                         }
1195                     }
1196                 }
1197                 
1198                 // Make sure the selected profile uses an installed avformat codec / format
1199                 if (!formatsList.isEmpty()) {
1200                     QString format;
1201                     if (std.startsWith("f=")) format = std.section("f=", 1, 1);
1202                     else if (std.contains(" f=")) format = std.section(" f=", 1, 1);
1203                     if (!format.isEmpty()) {
1204                         format = format.section(' ', 0, 0).toLower();
1205                         if (!formatsList.contains(format)) {
1206                             kDebug() << "***** UNSUPPORTED F: " << format;
1207                             //sizeItem->setHidden(true);
1208                             //sizeItem-item>setFlags(Qt::ItemIsSelectable);
1209                             dupItem->setToolTip(i18n("Unsupported video format: %1", format));
1210                             dupItem->setIcon(brokenIcon);
1211                             dupItem->setForeground(disabled);
1212                         }
1213                     }
1214                 }
1215                 if (!acodecsList.isEmpty()) {
1216                     QString format;
1217                     if (std.startsWith("acodec=")) format = std.section("acodec=", 1, 1);
1218                     else if (std.contains(" acodec=")) format = std.section(" acodec=", 1, 1);
1219                     if (!format.isEmpty()) {
1220                         format = format.section(' ', 0, 0).toLower();
1221                         if (!acodecsList.contains(format)) {
1222                             kDebug() << "*****  UNSUPPORTED ACODEC: " << format;
1223                             //sizeItem->setHidden(true);
1224                             //sizeItem->setFlags(Qt::ItemIsSelectable);
1225                             dupItem->setToolTip(i18n("Unsupported audio codec: %1", format));
1226                             dupItem->setIcon(brokenIcon);
1227                             dupItem->setForeground(disabled);
1228                             dupItem->setBackground(disabledbg);
1229                         }
1230                     }
1231                 }
1232                 if (!vcodecsList.isEmpty()) {
1233                     QString format;
1234                     if (std.startsWith("vcodec=")) format = std.section("vcodec=", 1, 1);
1235                     else if (std.contains(" vcodec=")) format = std.section(" vcodec=", 1, 1);
1236                     if (!format.isEmpty()) {
1237                         format = format.section(' ', 0, 0).toLower();
1238                         if (!vcodecsList.contains(format)) {
1239                             kDebug() << "*****  UNSUPPORTED VCODEC: " << format;
1240                             //sizeItem->setHidden(true);
1241                             //sizeItem->setFlags(Qt::ItemIsSelectable);
1242                             dupItem->setToolTip(i18n("Unsupported video codec: %1", format));
1243                             dupItem->setIcon(brokenIcon);
1244                             dupItem->setForeground(disabled);
1245                         }
1246                     }
1247                 }
1248                 if (std.contains(" profile=") || std.startsWith("profile=")) {
1249                     // changed in MLT commit d8a3a5c9190646aae72048f71a39ee7446a3bd45
1250                     // (http://www.mltframework.org/gitweb/mlt.git?p=mltframework.org/mlt.git;a=commit;h=d8a3a5c9190646aae72048f71a39ee7446a3bd45)
1251                     dupItem->setToolTip(i18n("This render profile uses a 'profile' parameter.<br />Unless you know what you are doing you will probably have to change it to 'mlt_profile'."));
1252                     dupItem->setIcon(warningIcon);
1253                 }
1254             }
1255         }
1256     }
1257     // m_view.size_list->sortItems();
1258     focusFirstVisibleItem();
1259     m_view.size_list->setVisible(m_view.size_list->count() > 1 || m_view.format_list->count() <= 1);
1260     m_view.size_list->blockSignals(false);
1261     m_view.format_list->blockSignals(false);
1262     if (m_view.size_list->count() > 0) {
1263         refreshParams();
1264     }
1265     else {
1266         // No matching profile
1267         errorMessage(i18n("No matching profile"));
1268         m_view.advanced_params->clear();
1269     }
1270 }
1271
1272 KUrl RenderWidget::filenameWithExtension(KUrl url, QString extension)
1273 {
1274     if (url.isEmpty()) url = KUrl(m_projectFolder);
1275     QString directory = url.directory(KUrl::AppendTrailingSlash | KUrl::ObeyTrailingSlash);
1276     QString filename = url.fileName(KUrl::ObeyTrailingSlash);
1277     QString ext;
1278
1279     if (extension.at(0) == '.') ext = extension;
1280     else ext = '.' + extension;
1281
1282     if (filename.isEmpty()) filename = i18n("untitled");
1283
1284     int pos = filename.lastIndexOf('.');
1285     if (pos == 0) filename.append(ext);
1286     else {
1287         if (!filename.endsWith(ext, Qt::CaseInsensitive)) {
1288             filename = filename.left(pos) + ext;
1289         }
1290     }
1291
1292     return KUrl(directory + filename);
1293 }
1294
1295 void RenderWidget::refreshParams()
1296 {
1297     // Format not available (e.g. codec not installed); Disable start button
1298     QListWidgetItem *item = m_view.size_list->currentItem();
1299     if (!item || item->isHidden()) {
1300         if (!item) errorMessage(i18n("No matching profile"));
1301         m_view.advanced_params->clear();
1302         m_view.buttonRender->setEnabled(false);
1303         m_view.buttonGenerateScript->setEnabled(false);
1304         return;
1305     }
1306     errorMessage(item->toolTip());
1307     QString params = item->data(ParamsRole).toString();
1308     QString extension = item->data(ExtensionRole).toString();
1309     m_view.advanced_params->setPlainText(params);
1310     QString destination = m_view.destination_list->itemData(m_view.destination_list->currentIndex()).toString();
1311     if (params.contains(" s=") || params.startsWith("s=") || destination == "audioonly") {
1312         // profile has a fixed size, do not allow resize
1313         m_view.rescale->setEnabled(false);
1314         m_view.rescale_box->setEnabled(false);
1315     } else {
1316         m_view.rescale->setEnabled(true);
1317         m_view.rescale_box->setEnabled(m_view.rescale->isChecked());
1318     }
1319     KUrl url = filenameWithExtension(m_view.out_file->url(), extension);
1320     m_view.out_file->setUrl(url);
1321 //     if (!url.isEmpty()) {
1322 //         QString path = url.path();
1323 //         int pos = path.lastIndexOf('.') + 1;
1324 //  if (pos == 0) path.append('.' + extension);
1325 //         else path = path.left(pos) + extension;
1326 //         m_view.out_file->setUrl(KUrl(path));
1327 //     } else {
1328 //         m_view.out_file->setUrl(KUrl(QDir::homePath() + "/untitled." + extension));
1329 //     }
1330     m_view.out_file->setFilter("*." + extension);
1331     QString edit = item->data(EditableRole).toString();
1332     if (edit.isEmpty() || !edit.endsWith("customprofiles.xml")) {
1333         m_view.buttonDelete->setEnabled(false);
1334         m_view.buttonEdit->setEnabled(false);
1335     } else {
1336         m_view.buttonDelete->setEnabled(true);
1337         m_view.buttonEdit->setEnabled(true);
1338     }
1339
1340     // setup comboBox with bitrates
1341     m_view.comboBitrates->clear();
1342     if (params.contains("bitrate")) {
1343         m_view.comboBitrates->setEnabled(true);
1344         m_view.bitrateLabel->setEnabled(true);
1345         if ( item->data(BitratesRole).canConvert(QVariant::StringList) && item->data(BitratesRole).toStringList().count()) {
1346             QStringList bitrates = item->data(BitratesRole).toStringList();
1347             foreach (QString bitrate, bitrates)
1348                 m_view.comboBitrates->addItem(bitrate);
1349             if (item->data(DefaultBitrateRole).canConvert(QVariant::String))
1350                 m_view.comboBitrates->setCurrentIndex(bitrates.indexOf(item->data(DefaultBitrateRole).toString()));
1351         }
1352     } else {
1353         m_view.comboBitrates->setEnabled(false);
1354         m_view.bitrateLabel->setEnabled(false);
1355     }
1356
1357     // setup comboBox with audiobitrates
1358     m_view.comboAudioBitrates->clear();
1359     if (params.contains("audiobitrate")) {
1360         m_view.comboAudioBitrates->setEnabled(true);
1361         m_view.audiobitrateLabel->setEnabled(true);
1362         if ( item->data(AudioBitratesRole).canConvert(QVariant::StringList) && item->data(AudioBitratesRole).toStringList().count()) {
1363             QStringList audiobitrates = item->data(AudioBitratesRole).toStringList();
1364             foreach (QString bitrate, audiobitrates)
1365                 m_view.comboAudioBitrates->addItem(bitrate);
1366             if (item->data(DefaultAudioBitrateRole).canConvert(QVariant::String))
1367                 m_view.comboAudioBitrates->setCurrentIndex(audiobitrates.indexOf(item->data(DefaultAudioBitrateRole).toString()));
1368         }
1369     } else {
1370         m_view.comboAudioBitrates->setEnabled(false);
1371         m_view.audiobitrateLabel->setEnabled(false);
1372     }
1373     
1374     m_view.checkTwoPass->setEnabled(params.contains("passes"));
1375
1376     m_view.encoder_threads->setEnabled(!params.contains("threads="));
1377
1378     m_view.buttonRender->setEnabled(m_view.size_list->currentItem()->toolTip().isEmpty());
1379     m_view.buttonGenerateScript->setEnabled(m_view.size_list->currentItem()->toolTip().isEmpty());
1380 }
1381
1382 void RenderWidget::reloadProfiles()
1383 {
1384     parseProfiles();
1385 }
1386
1387 void RenderWidget::parseProfiles(QString meta, QString group, QString profile)
1388 {
1389     m_view.size_list->blockSignals(true);
1390     m_view.format_list->blockSignals(true);
1391     m_view.size_list->clear();
1392     m_view.format_list->clear();
1393     m_view.destination_list->clear();
1394     qDeleteAll(m_renderItems);
1395     qDeleteAll(m_renderCategory);
1396     m_renderItems.clear();
1397     m_renderCategory.clear();
1398     m_view.destination_list->addItem(KIcon("video-x-generic"), i18n("File rendering"));
1399     m_view.destination_list->addItem(KIcon("favorites"), i18n("Favorites"), "favorites");
1400     m_view.destination_list->addItem(KIcon("media-optical"), i18n("DVD"), "dvd");
1401     m_view.destination_list->addItem(KIcon("audio-x-generic"), i18n("Audio only"), "audioonly");
1402     m_view.destination_list->addItem(KIcon("applications-internet"), i18n("Web sites"), "websites");
1403     m_view.destination_list->addItem(KIcon("applications-multimedia"), i18n("Media players"), "mediaplayers");
1404     m_view.destination_list->addItem(KIcon("drive-harddisk"), i18n("Lossless / HQ"), "lossless");
1405     m_view.destination_list->addItem(KIcon("pda"), i18n("Mobile devices"), "mobile");
1406
1407     QString exportFile = KStandardDirs::locate("appdata", "export/profiles.xml");
1408     parseFile(exportFile, false);
1409
1410
1411     QString exportFolder = KStandardDirs::locateLocal("appdata", "export/");
1412     QDir directory = QDir(exportFolder);
1413     QStringList filter;
1414     filter << "*.xml";
1415     QStringList fileList = directory.entryList(filter, QDir::Files);
1416     // We should parse customprofiles.xml in last position, so that user profiles
1417     // can also override profiles installed by KNewStuff
1418     fileList.removeAll("customprofiles.xml");
1419     foreach(const QString &filename, fileList)
1420         parseFile(exportFolder + filename, true);
1421     if (QFile::exists(exportFolder + "customprofiles.xml")) parseFile(exportFolder + "customprofiles.xml", true);
1422
1423     if (!meta.isEmpty()) {
1424         m_view.destination_list->blockSignals(true);
1425         m_view.destination_list->setCurrentIndex(m_view.destination_list->findData(meta));
1426         m_view.destination_list->blockSignals(false);
1427     }
1428     refreshCategory();
1429     QList<QListWidgetItem *> child;
1430     if (!group.isEmpty()) child = m_view.format_list->findItems(group, Qt::MatchExactly);
1431     if (!child.isEmpty()) {
1432         for (int i = 0; i < child.count(); i++) {
1433             if (child.at(i)->data(MetaGroupRole).toString() == meta) {
1434                 m_view.format_list->setCurrentItem(child.at(i));
1435                 break;
1436             }
1437         }
1438     }
1439     child.clear();
1440     m_view.size_list->blockSignals(false);
1441     m_view.format_list->blockSignals(false);
1442     if (!profile.isEmpty()) child = m_view.size_list->findItems(profile, Qt::MatchExactly);
1443     if (!child.isEmpty()) m_view.size_list->setCurrentItem(child.at(0));
1444 }
1445
1446 void RenderWidget::parseFile(QString exportFile, bool editable)
1447 {
1448     kDebug() << "// Parsing file: " << exportFile;
1449     kDebug() << "------------------------------";
1450     QDomDocument doc;
1451     QFile file(exportFile);
1452     doc.setContent(&file, false);
1453     file.close();
1454     QDomElement documentElement;
1455     QDomElement profileElement;
1456     QString extension;
1457     QDomNodeList groups = doc.elementsByTagName("group");
1458     QListWidgetItem *item = NULL;
1459     const QStringList acodecsList = KdenliveSettings::audiocodecs();
1460     bool replaceVorbisCodec = false;
1461     if (acodecsList.contains("libvorbis")) replaceVorbisCodec = true;
1462     bool replaceLibfaacCodec = false;
1463     if (!acodecsList.contains("aac") && acodecsList.contains("libfaac")) replaceLibfaacCodec = true;
1464
1465
1466     if (editable || groups.count() == 0) {
1467         QDomElement profiles = doc.documentElement();
1468         if (editable && profiles.attribute("version", 0).toInt() < 1) {
1469             kDebug() << "// OLD profile version";
1470             // this is an old profile version, update it
1471             QDomDocument newdoc;
1472             QDomElement newprofiles = newdoc.createElement("profiles");
1473             newprofiles.setAttribute("version", 1);
1474             newdoc.appendChild(newprofiles);
1475             QDomNodeList profilelist = doc.elementsByTagName("profile");
1476             for (int i = 0; i < profilelist.count(); i++) {
1477                 QString category = i18nc("Category Name", "Custom");
1478                 QString extension;
1479                 QDomNode parent = profilelist.at(i).parentNode();
1480                 if (!parent.isNull()) {
1481                     QDomElement parentNode = parent.toElement();
1482                     if (parentNode.hasAttribute("name")) category = parentNode.attribute("name");
1483                     extension = parentNode.attribute("extension");
1484                 }
1485                 profilelist.at(i).toElement().setAttribute("category", category);
1486                 if (!extension.isEmpty()) profilelist.at(i).toElement().setAttribute("extension", extension);
1487                 QDomNode n = profilelist.at(i).cloneNode();
1488                 newprofiles.appendChild(newdoc.importNode(n, true));
1489             }
1490             if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
1491                 KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
1492                 return;
1493             }
1494             QTextStream out(&file);
1495             out << newdoc.toString();
1496             file.close();
1497             parseFile(exportFile, editable);
1498             return;
1499         }
1500
1501         QDomNode node = doc.elementsByTagName("profile").at(0);
1502         if (node.isNull()) {
1503             kDebug() << "// Export file: " << exportFile << " IS BROKEN";
1504             return;
1505         }
1506         int count = 1;
1507         while (!node.isNull()) {
1508             QDomElement profile = node.toElement();
1509             QString profileName = profile.attribute("name");
1510             QString standard = profile.attribute("standard");
1511             QString params = profile.attribute("args");
1512
1513             if (replaceVorbisCodec && params.contains("acodec=vorbis")) {
1514                 // replace vorbis with libvorbis
1515                 params = params.replace("vorbis", "libvorbis");
1516             }
1517             if (replaceLibfaacCodec && params.contains("acodec=aac")) {
1518                 // replace libfaac with aac
1519                 params = params.replace("aac", "libfaac");
1520             }
1521
1522             QString category = profile.attribute("category", i18nc("Category Name", "Custom"));
1523             QString dest = profile.attribute("destinationid");
1524             QString prof_extension = profile.attribute("extension");
1525             if (!prof_extension.isEmpty()) extension = prof_extension;
1526             bool exists = false;
1527             for (int j = 0; j < m_renderCategory.count(); j++) {
1528                 if (m_renderCategory.at(j)->text() == category && m_renderCategory.at(j)->data(MetaGroupRole) == dest) {
1529                     exists = true;
1530                     break;
1531                 }
1532             }
1533
1534             if (!exists) {
1535                 QListWidgetItem *itemcat = new QListWidgetItem(category);
1536                 itemcat->setData(MetaGroupRole, dest);
1537                 m_renderCategory.append(itemcat);
1538             }
1539
1540             // Check if item with same name already exists and replace it,
1541             // allowing to override default profiles
1542
1543
1544             for (int j = 0; j < m_renderItems.count(); j++) {
1545                 if (m_renderItems.at(j)->text() == profileName && m_renderItems.at(j)->data(MetaGroupRole) == dest) {
1546                     QListWidgetItem *duplicate = m_renderItems.takeAt(j);
1547                     delete duplicate;
1548                     j--;
1549                 }
1550             }
1551
1552             item = new QListWidgetItem(profileName); // , m_view.size_list
1553             //kDebug() << "// ADDINg item with name: " << profileName << ", GRP" << category << ", DEST:" << dest ;
1554             item->setData(GroupRole, category);
1555             item->setData(MetaGroupRole, dest);
1556             item->setData(ExtensionRole, extension);
1557             item->setData(RenderRole, "avformat");
1558             item->setData(StandardRole, standard);
1559             item->setData(ParamsRole, params);
1560             item->setData(BitratesRole, profile.attribute("bitrates").split(',', QString::SkipEmptyParts));
1561             item->setData(DefaultBitrateRole, profile.attribute("defaultbitrate"));
1562             item->setData(AudioBitratesRole, profile.attribute("audiobitrates").split(',', QString::SkipEmptyParts));
1563             item->setData(DefaultAudioBitrateRole, profile.attribute("defaultaudiobitrate"));
1564             if (profile.hasAttribute("url")) item->setData(ExtraRole, profile.attribute("url"));
1565             if (editable) {
1566                 item->setData(EditableRole, exportFile);
1567                 if (exportFile.endsWith("customprofiles.xml")) item->setIcon(KIcon("emblem-favorite"));
1568                 else item->setIcon(KIcon("applications-internet"));
1569             }
1570             m_renderItems.append(item);
1571             node = doc.elementsByTagName("profile").at(count);
1572             count++;
1573         }
1574         return;
1575     }
1576
1577     int i = 0;
1578     QString groupName;
1579     QString profileName;
1580
1581     QString prof_extension;
1582     QString renderer;
1583     QString params;
1584     QString standard;
1585     QString bitrates, defaultBitrate, audioBitrates, defaultAudioBitrate;
1586     KIcon icon;
1587
1588     while (!groups.item(i).isNull()) {
1589         documentElement = groups.item(i).toElement();
1590         QDomNode gname = documentElement.elementsByTagName("groupname").at(0);
1591         QString metagroupName;
1592         QString metagroupId;
1593         if (!gname.isNull()) {
1594             metagroupName = gname.firstChild().nodeValue();
1595             metagroupId = gname.toElement().attribute("id");
1596
1597             if (!metagroupName.isEmpty() && m_view.destination_list->findData(metagroupId) == -1) {
1598                 if (metagroupId == "dvd") icon = KIcon("media-optical");
1599                 else if (metagroupId == "audioonly") icon = KIcon("audio-x-generic");
1600                 else if (metagroupId == "websites") icon = KIcon("applications-internet");
1601                 else if (metagroupId == "mediaplayers") icon = KIcon("applications-multimedia");
1602                 else if (metagroupId == "lossless") icon = KIcon("drive-harddisk");
1603                 else if (metagroupId == "mobile") icon = KIcon("pda");
1604                 m_view.destination_list->addItem(icon, i18n(metagroupName.toUtf8().data()), metagroupId);
1605             }
1606         }
1607         groupName = documentElement.attribute("name", i18nc("Attribute Name", "Custom"));
1608         extension = documentElement.attribute("extension", QString());
1609         renderer = documentElement.attribute("renderer", QString());
1610         bool exists = false;
1611         for (int j = 0; j < m_renderCategory.count(); j++) {
1612             if (m_renderCategory.at(j)->text() == groupName && m_renderCategory.at(j)->data(MetaGroupRole) == metagroupId) {
1613                 exists = true;
1614                 break;
1615             }
1616         }
1617         if (!exists) {
1618             QListWidgetItem *itemcat = new QListWidgetItem(groupName); //, m_view.format_list);
1619             itemcat->setData(MetaGroupRole, metagroupId);
1620             m_renderCategory.append(itemcat);
1621         }
1622
1623         QDomNode n = groups.item(i).firstChild();
1624         while (!n.isNull()) {
1625             if (n.toElement().tagName() != "profile") {
1626                 n = n.nextSibling();
1627                 continue;
1628             }
1629             profileElement = n.toElement();
1630             profileName = profileElement.attribute("name");
1631             standard = profileElement.attribute("standard");
1632             bitrates = profileElement.attribute("bitrates");
1633             defaultBitrate = profileElement.attribute("defaultbitrate");
1634             audioBitrates = profileElement.attribute("audiobitrates");
1635             defaultAudioBitrate = profileElement.attribute("defaultaudiobitrate");
1636             params = profileElement.attribute("args");
1637
1638             if (replaceVorbisCodec && params.contains("acodec=vorbis")) {
1639                 // replace vorbis with libvorbis
1640                 params = params.replace("vorbis", "libvorbis");
1641             }
1642             if (replaceLibfaacCodec && params.contains("acodec=aac")) {
1643                 // replace libfaac with aac
1644                 params = params.replace("aac", "libfaac");
1645             }
1646
1647             prof_extension = profileElement.attribute("extension");
1648             if (!prof_extension.isEmpty()) extension = prof_extension;
1649             item = new QListWidgetItem(profileName); //, m_view.size_list);
1650             item->setData(GroupRole, groupName);
1651             item->setData(MetaGroupRole, metagroupId);
1652             item->setData(ExtensionRole, extension);
1653             item->setData(RenderRole, renderer);
1654             item->setData(StandardRole, standard);
1655             item->setData(ParamsRole, params);
1656             item->setData(BitratesRole, bitrates.split(',', QString::SkipEmptyParts));
1657             item->setData(DefaultBitrateRole, defaultBitrate);
1658             item->setData(AudioBitratesRole, audioBitrates.split(',', QString::SkipEmptyParts));
1659             item->setData(DefaultAudioBitrateRole, defaultAudioBitrate);
1660             if (profileElement.hasAttribute("url")) item->setData(ExtraRole, profileElement.attribute("url"));
1661             if (editable) item->setData(EditableRole, exportFile);
1662             m_renderItems.append(item);
1663             n = n.nextSibling();
1664         }
1665
1666         i++;
1667     }
1668 }
1669
1670 void RenderWidget::setRenderJob(const QString &dest, int progress)
1671 {
1672     QTreeWidgetItem *item;
1673     QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1);
1674     if (!existing.isEmpty()) item = existing.at(0);
1675     else {
1676         item = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << dest << QString());
1677         item->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
1678         if (progress == 0) {
1679             item->setData(1, Qt::UserRole + 2, WAITINGJOB);
1680             item->setIcon(0, KIcon("media-playback-pause"));
1681             item->setData(1, Qt::UserRole, i18n("Waiting..."));
1682         }
1683     }
1684     item->setData(2, Qt::UserRole, progress);
1685     item->setData(1, Qt::UserRole + 2, RUNNINGJOB);
1686     if (progress == 0) {
1687         item->setIcon(0, KIcon("system-run"));
1688         item->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
1689         item->setData(1, Qt::UserRole + 1, QTime::currentTime());
1690         slotCheckJob();
1691     } else {
1692         QTime startTime = item->data(1, Qt::UserRole + 1).toTime();
1693         int seconds = startTime.secsTo(QTime::currentTime());;
1694         const QString t = i18n("Estimated time %1", QTime().addSecs(seconds * (100 - progress) / progress).toString("hh:mm:ss"));
1695         item->setData(1, Qt::UserRole, t);
1696     }
1697 }
1698
1699 void RenderWidget::setRenderStatus(const QString &dest, int status, const QString &error)
1700 {
1701     QTreeWidgetItem *item;
1702     QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly, 1);
1703     if (!existing.isEmpty()) item = existing.at(0);
1704     else {
1705         item = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << dest << QString());
1706         item->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
1707     }
1708     item->setData(1, Qt::UserRole + 2, FINISHEDJOB);
1709     if (status == -1) {
1710         // Job finished successfully
1711         item->setIcon(0, KIcon("dialog-ok"));
1712         item->setData(2, Qt::UserRole, 100);
1713         QTime startTime = item->data(1, Qt::UserRole + 1).toTime();
1714         int seconds = startTime.secsTo(QTime::currentTime());
1715         const QTime tm = QTime().addSecs(seconds);
1716         const QString t = i18n("Rendering finished in %1", tm.toString("hh:mm:ss"));
1717         item->setData(1, Qt::UserRole, t);
1718         QString itemGroup = item->data(0, Qt::UserRole).toString();
1719         if (itemGroup == "dvd") {
1720             emit openDvdWizard(item->text(1), item->data(0, Qt::UserRole + 1).toString());
1721         } else if (itemGroup == "websites") {
1722             QString url = item->data(0, Qt::UserRole + 1).toString();
1723             if (!url.isEmpty()) new KRun(url, this);
1724         }
1725     } else if (status == -2) {
1726         // Rendering crashed
1727         item->setData(1, Qt::UserRole, i18n("Rendering crashed"));
1728         item->setIcon(0, KIcon("dialog-close"));
1729         item->setData(2, Qt::UserRole, 100);
1730         m_view.error_log->append(i18n("<strong>Rendering of %1 crashed</strong><br />", dest));
1731         m_view.error_log->append(error);
1732         m_view.error_log->append("<hr />");
1733         m_view.error_box->setVisible(true);
1734     } else if (status == -3) {
1735         // User aborted job
1736         item->setData(1, Qt::UserRole, i18n("Rendering aborted"));
1737         item->setIcon(0, KIcon("dialog-cancel"));
1738         item->setData(2, Qt::UserRole, 100);
1739     }
1740     slotCheckJob();
1741     checkRenderStatus();
1742 }
1743
1744 void RenderWidget::slotAbortCurrentJob()
1745 {
1746     QTreeWidgetItem *current = m_view.running_jobs->currentItem();
1747     if (current) {
1748         if (current->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB)
1749             emit abortProcess(current->text(1));
1750         else {
1751             delete current;
1752             slotCheckJob();
1753             checkRenderStatus();
1754         }
1755     }
1756 }
1757
1758 void RenderWidget::slotStartCurrentJob()
1759 {
1760     QTreeWidgetItem *current = m_view.running_jobs->currentItem();
1761     if (current && current->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB)
1762         startRendering(current);
1763     m_view.start_job->setEnabled(false);
1764 }
1765
1766 void RenderWidget::slotCheckJob()
1767 {
1768     bool activate = false;
1769     QTreeWidgetItem *current = m_view.running_jobs->currentItem();
1770     if (current) {
1771         if (current->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB) {
1772             m_view.abort_job->setText(i18n("Abort Job"));
1773             m_view.start_job->setEnabled(false);
1774         } else {
1775             m_view.abort_job->setText(i18n("Remove Job"));
1776             m_view.start_job->setEnabled(current->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB);
1777         }
1778         activate = true;
1779     }
1780     m_view.abort_job->setEnabled(activate);
1781     for (int i = 0; i < m_view.running_jobs->topLevelItemCount(); i++) {
1782         current = m_view.running_jobs->topLevelItem(i);
1783         if (current == m_view.running_jobs->currentItem()) {
1784             current->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 3));
1785         } else current->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
1786     }
1787 }
1788
1789 void RenderWidget::slotCLeanUpJobs()
1790 {
1791     int ix = 0;
1792     QTreeWidgetItem *current = m_view.running_jobs->topLevelItem(ix);
1793     while (current) {
1794         if (current->data(1, Qt::UserRole + 2).toInt() == FINISHEDJOB)
1795             delete current;
1796         else ix++;
1797         current = m_view.running_jobs->topLevelItem(ix);
1798     }
1799     slotCheckJob();
1800 }
1801
1802 void RenderWidget::parseScriptFiles()
1803 {
1804     QStringList scriptsFilter;
1805     scriptsFilter << "*.sh";
1806     m_view.scripts_list->clear();
1807
1808     QTreeWidgetItem *item;
1809     // List the project scripts
1810     QStringList scriptFiles = QDir(m_projectFolder + "scripts").entryList(scriptsFilter, QDir::Files);
1811     for (int i = 0; i < scriptFiles.size(); ++i) {
1812         KUrl scriptpath(m_projectFolder + "scripts/" + scriptFiles.at(i));
1813         QString target;
1814         QString renderer;
1815         QString melt;
1816         QFile file(scriptpath.path());
1817         if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
1818             QTextStream stream(&file);
1819             while (!stream.atEnd()) {
1820                 QString line = stream.readLine();
1821                 if (line.startsWith("TARGET=")) {
1822                     target = line.section("TARGET=\"", 1);
1823                     target = target.section('"', 0, 0);
1824                 } else if (line.startsWith("RENDERER=\"")) {
1825                     renderer = line.section("RENDERER=", 1);
1826                     renderer = renderer.section('"', 0, 0);
1827                 } else if (line.startsWith("MELT=\"")) {
1828                     melt = line.section("MELT=", 1);
1829                     melt = melt.section('"', 0, 0);
1830                 }
1831             }
1832             file.close();
1833         }
1834         if (target.isEmpty()) continue;
1835         item = new QTreeWidgetItem(m_view.scripts_list, QStringList() << QString() << scriptpath.fileName());
1836         if (!renderer.isEmpty() && renderer.contains('/') && !QFile::exists(renderer)) {
1837             item->setIcon(0, KIcon("dialog-cancel"));
1838             item->setToolTip(1, i18n("Script contains wrong command: %1", renderer));
1839             item->setData(0, Qt::UserRole, '1');
1840         } else if (!melt.isEmpty() && melt.contains('/') && !QFile::exists(melt)) {
1841             item->setIcon(0, KIcon("dialog-cancel"));
1842             item->setToolTip(1, i18n("Script contains wrong command: %1", melt));
1843             item->setData(0, Qt::UserRole, '1');
1844         } else item->setIcon(0, KIcon("application-x-executable-script"));
1845         item->setSizeHint(0, QSize(m_view.scripts_list->columnWidth(0), fontMetrics().height() * 2));
1846         item->setData(1, Qt::UserRole, KUrl(target).path());
1847         item->setData(1, Qt::UserRole + 1, scriptpath.path());
1848     }
1849 //     bool activate = false;
1850     QTreeWidgetItem *script = m_view.scripts_list->topLevelItem(0);
1851     if (script) {
1852         m_view.scripts_list->setCurrentItem(script);
1853         script->setSelected(true);
1854 //         activate = true;
1855     }
1856 //    m_view.start_script->setEnabled(activate);
1857 //    m_view.delete_script->setEnabled(activate);
1858 }
1859
1860 void RenderWidget::slotCheckScript()
1861 {
1862     QTreeWidgetItem *current = m_view.scripts_list->currentItem();
1863     if (current == NULL) return;
1864     m_view.start_script->setEnabled(current->data(0, Qt::UserRole).toString().isEmpty());
1865     m_view.delete_script->setEnabled(true);
1866     for (int i = 0; i < m_view.scripts_list->topLevelItemCount(); i++) {
1867         current = m_view.scripts_list->topLevelItem(i);
1868         if (current == m_view.scripts_list->currentItem()) {
1869             current->setSizeHint(1, QSize(m_view.scripts_list->columnWidth(1), fontMetrics().height() * 3));
1870         } else current->setSizeHint(1, QSize(m_view.scripts_list->columnWidth(1), fontMetrics().height() * 2));
1871     }
1872 }
1873
1874 void RenderWidget::slotStartScript()
1875 {
1876     QTreeWidgetItem *item = m_view.scripts_list->currentItem();
1877     if (item) {
1878         QString destination = item->data(1, Qt::UserRole).toString();
1879         QString path = item->data(1, Qt::UserRole + 1).toString();
1880         // Insert new job in queue
1881         QTreeWidgetItem *renderItem;
1882         QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(destination, Qt::MatchExactly, 1);
1883         kDebug() << "------  START SCRIPT";
1884         if (!existing.isEmpty()) {
1885             renderItem = existing.at(0);
1886             if (renderItem->data(1, Qt::UserRole + 2).toInt() == RUNNINGJOB) {
1887                 KMessageBox::information(this, i18n("There is already a job writing file:<br /><b>%1</b><br />Abort the job if you want to overwrite it...", destination), i18n("Already running"));
1888                 return;
1889             }
1890         } else renderItem = new QTreeWidgetItem(m_view.running_jobs, QStringList() << QString() << destination << QString());
1891         kDebug() << "------  START SCRIPT 2";
1892         renderItem->setData(2, Qt::UserRole, 0);
1893         renderItem->setData(1, Qt::UserRole + 2, WAITINGJOB);
1894         renderItem->setIcon(0, KIcon("media-playback-pause"));
1895         renderItem->setData(1, Qt::UserRole, i18n("Waiting..."));
1896         renderItem->setSizeHint(1, QSize(m_view.running_jobs->columnWidth(1), fontMetrics().height() * 2));
1897         renderItem->setData(1, Qt::UserRole + 1, QTime::currentTime());
1898         renderItem->setData(1, Qt::UserRole + 3, path);
1899         renderItem->setData(1, Qt::UserRole + 4, '1');
1900         checkRenderStatus();
1901         m_view.tabWidget->setCurrentIndex(1);
1902     }
1903 }
1904
1905 void RenderWidget::slotDeleteScript()
1906 {
1907     QTreeWidgetItem *item = m_view.scripts_list->currentItem();
1908     if (item) {
1909         QString path = item->data(1, Qt::UserRole + 1).toString();
1910         KIO::NetAccess::del(path + ".mlt", this);
1911         KIO::NetAccess::del(path, this);
1912         parseScriptFiles();
1913     }
1914 }
1915
1916 void RenderWidget::slotGenerateScript()
1917 {
1918     slotPrepareExport(true);
1919 }
1920
1921 void RenderWidget::slotHideLog()
1922 {
1923     m_view.error_box->setVisible(false);
1924 }
1925
1926 void RenderWidget::setRenderProfile(QMap <QString, QString> props)
1927 {
1928     m_view.destination_list->blockSignals(true);
1929     m_view.format_list->blockSignals(true);
1930     m_view.scanning_list->setCurrentIndex(props.value("renderscanning").toInt());
1931     int exportAudio = props.value("renderexportaudio").toInt();
1932     switch (exportAudio) {
1933     case 1:
1934         m_view.export_audio->setCheckState(Qt::Unchecked);
1935         break;
1936     case 2:
1937         m_view.export_audio->setCheckState(Qt::Checked);
1938         break;
1939     default:
1940         m_view.export_audio->setCheckState(Qt::PartiallyChecked);
1941     }
1942     if (props.contains("renderrescale")) m_view.rescale->setChecked(props.value("renderrescale").toInt());
1943     if (props.contains("renderrescalewidth")) m_view.rescale_width->setValue(props.value("renderrescalewidth").toInt());
1944     if (props.contains("renderrescaleheight")) m_view.rescale_height->setValue(props.value("renderrescaleheight").toInt());
1945     if (props.contains("rendertcoverlay")) m_view.tc_overlay->setChecked(props.value("rendertcoverlay").toInt());
1946     if (props.contains("rendertctype")) m_view.tc_type->setCurrentIndex(props.value("rendertctype").toInt());
1947     if (props.contains("renderratio")) m_view.rescale_keep->setChecked(props.value("renderratio").toInt());
1948     if (props.contains("renderplay")) m_view.play_after->setChecked(props.value("renderplay").toInt());
1949     if (props.contains("rendertwopass")) m_view.checkTwoPass->setChecked(props.value("rendertwopass").toInt());
1950
1951     if (props.value("renderzone") == "1") m_view.render_zone->setChecked(true);
1952     else if (props.value("renderguide") == "1") {
1953         m_view.render_guide->setChecked(true);
1954         m_view.guide_start->setCurrentIndex(props.value("renderstartguide").toInt());
1955         m_view.guide_end->setCurrentIndex(props.value("renderendguide").toInt());
1956     } else m_view.render_full->setChecked(true);
1957     slotUpdateGuideBox();
1958
1959     QString url = props.value("renderurl");
1960     if (!url.isEmpty()) m_view.out_file->setUrl(KUrl(url));
1961
1962     // set destination
1963     for (int i = 0; i < m_view.destination_list->count(); i++) {
1964         if (m_view.destination_list->itemData(i, Qt::UserRole) == props.value("renderdestination")) {
1965             m_view.destination_list->setCurrentIndex(i);
1966             break;
1967         }
1968     }
1969     refreshCategory();
1970
1971     // set category
1972     QString group = props.value("rendercategory");
1973     if (!group.isEmpty()) {
1974         QList<QListWidgetItem *> childs = m_view.format_list->findItems(group, Qt::MatchExactly);
1975         if (!childs.isEmpty()) {
1976             m_view.format_list->setCurrentItem(childs.at(0));
1977             m_view.format_list->scrollToItem(childs.at(0));
1978         }
1979         refreshView();
1980     }
1981
1982     // set profile
1983     QList<QListWidgetItem *> childs = m_view.size_list->findItems(props.value("renderprofile"), Qt::MatchExactly);
1984     if (!childs.isEmpty()) {
1985         m_view.size_list->setCurrentItem(childs.at(0));
1986         m_view.size_list->scrollToItem(childs.at(0));
1987     }
1988     //refreshView();
1989     m_view.destination_list->blockSignals(false);
1990     m_view.format_list->blockSignals(false);
1991
1992 }
1993
1994 bool RenderWidget::startWaitingRenderJobs()
1995 {
1996     m_blockProcessing = true;
1997     QString autoscriptFile = getFreeScriptName("auto");
1998     QFile file(autoscriptFile);
1999     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
2000         kWarning() << "//////  ERROR writing to file: " << autoscriptFile;
2001         KMessageBox::error(0, i18n("Cannot write to file %1", autoscriptFile));
2002         return false;
2003     }
2004
2005     QTextStream outStream(&file);
2006     outStream << "#! /bin/sh" << "\n" << "\n";
2007     QTreeWidgetItem *item = m_view.running_jobs->topLevelItem(0);
2008     while (item) {
2009         if (item->data(1, Qt::UserRole + 2).toInt() == WAITINGJOB) {
2010             if (item->data(1, Qt::UserRole + 4).isNull()) {
2011                 // Add render process for item
2012                 const QString params = item->data(1, Qt::UserRole + 3).toStringList().join(" ");
2013                 outStream << m_renderer << " " << params << "\n";
2014             } else {
2015                 // Script item
2016                 outStream << item->data(1, Qt::UserRole + 3).toString() << "\n";
2017             }
2018         }
2019         item = m_view.running_jobs->itemBelow(item);
2020     }
2021     // erase itself when rendering is finished
2022     outStream << "rm " << autoscriptFile << "\n" << "\n";
2023     if (file.error() != QFile::NoError) {
2024         KMessageBox::error(0, i18n("Cannot write to file %1", autoscriptFile));
2025         file.close();
2026         m_blockProcessing = false;
2027         return false;
2028     }
2029     file.close();
2030     QFile::setPermissions(autoscriptFile, file.permissions() | QFile::ExeUser);
2031     QProcess::startDetached(autoscriptFile, QStringList());
2032     return true;
2033 }
2034
2035 QString RenderWidget::getFreeScriptName(const QString &prefix)
2036 {
2037     int ix = 0;
2038     QString scriptsFolder = m_projectFolder + "scripts/";
2039     KStandardDirs::makeDir(scriptsFolder);
2040     QString path;
2041     while (path.isEmpty() || QFile::exists(path)) {
2042         ix++;
2043         path = scriptsFolder + prefix + i18n("script") + QString::number(ix).rightJustified(3, '0', false) + ".sh";
2044     }
2045     return path;
2046 }
2047
2048 void RenderWidget::slotPlayRendering(QTreeWidgetItem *item, int)
2049 {
2050     if (KdenliveSettings::defaultplayerapp().isEmpty() || item->data(1, Qt::UserRole + 2).toInt() != FINISHEDJOB) return;
2051     KUrl::List urls;
2052     urls.append(KUrl(item->text(1)));
2053     KRun::run(KdenliveSettings::defaultplayerapp(), urls, this);
2054 }
2055
2056 void RenderWidget::missingClips(bool hasMissing)
2057 {
2058     if (hasMissing) {
2059         m_view.errorLabel->setText(i18n("Check missing clips"));
2060         m_view.errorBox->setHidden(false);
2061     } else m_view.errorBox->setHidden(true);
2062 }
2063
2064 void RenderWidget::errorMessage(const QString &message)
2065 {
2066     if (!message.isEmpty()) {
2067 #if KDE_IS_VERSION(4,7,0)
2068         m_infoMessage->setMessageType(KMessageWidget::Warning);
2069         m_infoMessage->setText(message);
2070         m_infoMessage->animatedShow();
2071 #else
2072         m_view.errorLabel->setText(message);
2073         m_view.errorBox->setHidden(false);
2074 #endif
2075     }
2076     else {
2077 #if KDE_IS_VERSION(4,7,0)
2078         m_infoMessage->animatedHide();
2079 #else
2080         m_view.errorBox->setHidden(true);
2081         m_view.errorLabel->setText(QString());
2082 #endif
2083
2084     }
2085 }
2086
2087
2088 void RenderWidget::slotUpdateEncodeThreads(int val)
2089 {
2090         KdenliveSettings::setEncodethreads(val);
2091 }
2092
2093 void RenderWidget::slotUpdateRescaleWidth(int val)
2094 {
2095     KdenliveSettings::setDefaultrescalewidth(val);
2096     if (!m_view.rescale_keep->isChecked()) return;
2097     m_view.rescale_height->blockSignals(true);
2098     m_view.rescale_height->setValue(val * m_profile.height / m_profile.width  + 0.5);
2099     KdenliveSettings::setDefaultrescaleheight(m_view.rescale_height->value());
2100     m_view.rescale_height->blockSignals(false);
2101 }
2102
2103 void RenderWidget::slotUpdateRescaleHeight(int val)
2104 {
2105     KdenliveSettings::setDefaultrescaleheight(val);
2106     if (!m_view.rescale_keep->isChecked()) return;
2107     m_view.rescale_width->blockSignals(true);
2108     m_view.rescale_width->setValue(val * m_profile.width / m_profile.height + 0.5);
2109     KdenliveSettings::setDefaultrescaleheight(m_view.rescale_width->value());
2110     m_view.rescale_width->blockSignals(false);
2111 }
2112
2113 void RenderWidget::slotSwitchAspectRatio()
2114 {
2115     KdenliveSettings::setRescalekeepratio(m_view.rescale_keep->isChecked());
2116     if (m_view.rescale_keep->isChecked()) slotUpdateRescaleWidth(m_view.rescale_width->value());
2117 }
2118
2119 void RenderWidget::slotUpdateAudioLabel(int ix)
2120 {
2121     if (ix == Qt::PartiallyChecked)
2122         m_view.export_audio->setText(i18n("Export audio (automatic)"));
2123     else
2124         m_view.export_audio->setText(i18n("Export audio"));
2125 }
2126
2127 bool RenderWidget::automaticAudioExport() const
2128 {
2129     return (m_view.export_audio->checkState() == Qt::PartiallyChecked);
2130 }
2131
2132 bool RenderWidget::selectedAudioExport() const
2133 {
2134     return (m_view.export_audio->checkState() != Qt::Unchecked);
2135 }
2136
2137 void RenderWidget::updateProxyConfig(bool enable)
2138 {
2139     m_view.proxy_render->setHidden(!enable);
2140 }
2141
2142 bool RenderWidget::proxyRendering()
2143 {
2144     return m_view.proxy_render->isChecked();
2145 }