]> git.sesse.net Git - kdenlive/blob - src/renderwidget.cpp
Jobs can now be aborted from the "running job" view
[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 <QDomDocument>
22 #include <QItemDelegate>
23 #include <QTreeWidgetItem>
24 #include <QHeaderView>
25
26 #include <KStandardDirs>
27 #include <KDebug>
28 #include <KMessageBox>
29 #include <KComboBox>
30
31 #include "kdenlivesettings.h"
32 #include "renderwidget.h"
33 #include "ui_saveprofile_ui.h"
34
35 const int GroupRole = Qt::UserRole;
36 const int ExtensionRole = GroupRole + 1;
37 const int StandardRole = GroupRole + 2;
38 const int RenderRole = GroupRole + 3;
39 const int ParamsRole = GroupRole + 4;
40 const int EditableRole = GroupRole + 5;
41
42 RenderWidget::RenderWidget(QWidget * parent): QDialog(parent) {
43     m_view.setupUi(this);
44     m_view.buttonDelete->setIcon(KIcon("trash-empty"));
45     m_view.buttonDelete->setToolTip(i18n("Delete profile"));
46     m_view.buttonDelete->setEnabled(false);
47
48     m_view.buttonEdit->setIcon(KIcon("document-properties"));
49     m_view.buttonEdit->setToolTip(i18n("Edit profile"));
50     m_view.buttonEdit->setEnabled(false);
51
52     m_view.buttonSave->setIcon(KIcon("document-new"));
53     m_view.buttonSave->setToolTip(i18n("Create new profile"));
54
55     m_view.buttonInfo->setIcon(KIcon("help-about"));
56
57     if (KdenliveSettings::showrenderparams()) {
58         m_view.buttonInfo->setDown(true);
59     } else m_view.advanced_params->hide();
60
61     m_view.experimentalrender->setChecked(KdenliveSettings::experimentalrender());
62
63     m_view.experimentalrender->setToolTip(i18n("Changing the size of video when rendering\nis not fully supported, you may have problems\nwith some effects or title clips, so the export\nprofiles that resize your video are marked as\nexperimental"));
64
65     connect(m_view.buttonInfo, SIGNAL(clicked()), this, SLOT(showInfoPanel()));
66
67     connect(m_view.buttonSave, SIGNAL(clicked()), this, SLOT(slotSaveProfile()));
68     connect(m_view.buttonEdit, SIGNAL(clicked()), this, SLOT(slotEditProfile()));
69     connect(m_view.buttonDelete, SIGNAL(clicked()), this, SLOT(slotDeleteProfile()));
70     connect(m_view.buttonStart, SIGNAL(clicked()), this, SLOT(slotExport()));
71     connect(m_view.abort_job, SIGNAL(clicked()), this, SLOT(slotAbortCurrentJob()));
72     connect(m_view.buttonClose, SIGNAL(clicked()), this, SLOT(hide()));
73     connect(m_view.buttonClose2, SIGNAL(clicked()), this, SLOT(hide()));
74     connect(m_view.out_file, SIGNAL(textChanged(const QString &)), this, SLOT(slotUpdateButtons()));
75     connect(m_view.format_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshView()));
76     connect(m_view.size_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshParams()));
77
78     connect(m_view.render_guide, SIGNAL(clicked(bool)), this, SLOT(slotUpdateGuideBox()));
79     connect(m_view.render_zone, SIGNAL(clicked(bool)), this, SLOT(slotUpdateGuideBox()));
80     connect(m_view.render_full, SIGNAL(clicked(bool)), this, SLOT(slotUpdateGuideBox()));
81
82     connect(m_view.guide_end, SIGNAL(activated(int)), this, SLOT(slotCheckStartGuidePosition()));
83     connect(m_view.guide_start, SIGNAL(activated(int)), this, SLOT(slotCheckEndGuidePosition()));
84
85     connect(m_view.format_selection, SIGNAL(activated(int)), this, SLOT(refreshView()));
86     connect(m_view.experimentalrender, SIGNAL(stateChanged(int)), this, SLOT(slotUpdateExperimentalRendering()));
87
88     m_view.buttonStart->setEnabled(false);
89     m_view.guides_box->setVisible(false);
90     parseProfiles();
91     m_view.splitter->setStretchFactor(1, 5);
92     m_view.splitter->setStretchFactor(0, 2);
93
94     m_view.out_file->setMode(KFile::File);
95
96     m_view.running_jobs->setItemDelegate(new RenderViewDelegate(this));
97     QHeaderView *header = m_view.running_jobs->header();
98     QFontMetrics fm = fontMetrics();
99     //header->resizeSection(0, fm.width("typical-name-for-a-torrent.torrent"));
100     header->setResizeMode(0, QHeaderView::Interactive);
101     header->resizeSection(0, fm.width("typical-name-for-a-file.torrent"));
102     header->setResizeMode(1, QHeaderView::Fixed);
103     header->resizeSection(0, width() * 2 / 3);
104     header->setResizeMode(1, QHeaderView::Interactive);
105     //header->setResizeMode(1, QHeaderView::Fixed);
106
107     focusFirstVisibleItem();
108 }
109
110 void RenderWidget::slotUpdateExperimentalRendering() {
111     KdenliveSettings::setExperimentalrender(m_view.experimentalrender->isChecked());
112     refreshView();
113 }
114
115
116 void RenderWidget::showInfoPanel() {
117     if (m_view.advanced_params->isVisible()) {
118         m_view.advanced_params->setVisible(false);
119         m_view.buttonInfo->setDown(false);
120         KdenliveSettings::setShowrenderparams(false);
121     } else {
122         m_view.advanced_params->setVisible(true);
123         m_view.buttonInfo->setDown(true);
124         KdenliveSettings::setShowrenderparams(true);
125     }
126 }
127
128 void RenderWidget::slotUpdateGuideBox() {
129     m_view.guides_box->setVisible(m_view.render_guide->isChecked());
130 }
131
132 void RenderWidget::slotCheckStartGuidePosition() {
133     if (m_view.guide_start->currentIndex() > m_view.guide_end->currentIndex())
134         m_view.guide_start->setCurrentIndex(m_view.guide_end->currentIndex());
135 }
136
137 void RenderWidget::slotCheckEndGuidePosition() {
138     if (m_view.guide_end->currentIndex() < m_view.guide_start->currentIndex())
139         m_view.guide_end->setCurrentIndex(m_view.guide_start->currentIndex());
140 }
141
142 void RenderWidget::setGuides(QDomElement guidesxml, double duration) {
143     m_view.guide_start->clear();
144     m_view.guide_end->clear();
145     QDomNodeList nodes = guidesxml.elementsByTagName("guide");
146     if (nodes.count() > 0) {
147         m_view.guide_start->addItem(i18n("Render"), "0");
148         m_view.render_guide->setEnabled(true);
149     } else m_view.render_guide->setEnabled(false);
150     for (int i = 0; i < nodes.count(); i++) {
151         QDomElement e = nodes.item(i).toElement();
152         if (!e.isNull()) {
153             m_view.guide_start->addItem(e.attribute("comment"), e.attribute("time").toDouble());
154             m_view.guide_end->addItem(e.attribute("comment"), e.attribute("time").toDouble());
155         }
156     }
157     if (nodes.count() > 0)
158         m_view.guide_end->addItem(i18n("End"), QString::number(duration));
159 }
160
161 void RenderWidget::slotUpdateButtons() {
162     if (m_view.out_file->url().isEmpty()) m_view.buttonStart->setEnabled(false);
163     else m_view.buttonStart->setEnabled(true);
164 }
165
166 void RenderWidget::slotSaveProfile() {
167     Ui::SaveProfile_UI ui;
168     QDialog *d = new QDialog(this);
169     ui.setupUi(d);
170     QString customGroup = i18n("Custom");
171     QStringList groupNames;
172     for (int i = 0; i < m_view.format_list->count(); i++)
173         groupNames.append(m_view.format_list->item(i)->text());
174     if (!groupNames.contains(customGroup)) groupNames.prepend(customGroup);
175     ui.group_name->addItems(groupNames);
176     int pos = ui.group_name->findText(customGroup);
177     ui.group_name->setCurrentIndex(pos);
178
179     ui.parameters->setText(m_view.advanced_params->toPlainText());
180     ui.extension->setText(m_view.size_list->currentItem()->data(ExtensionRole).toString());
181     ui.profile_name->setFocus();
182     if (d->exec() == QDialog::Accepted && !ui.profile_name->text().simplified().isEmpty()) {
183         QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
184         QDomDocument doc;
185         QFile file(exportFile);
186         doc.setContent(&file, false);
187         file.close();
188
189         QDomElement documentElement;
190         bool groupExists = false;
191         QString groupName;
192         QString newProfileName = ui.profile_name->text().simplified();
193         QString newGroupName = ui.group_name->currentText();
194         QDomNodeList groups = doc.elementsByTagName("group");
195         int i = 0;
196         if (groups.count() == 0) {
197             QDomElement profiles = doc.createElement("profiles");
198             doc.appendChild(profiles);
199         } else while (!groups.item(i).isNull()) {
200                 documentElement = groups.item(i).toElement();
201                 groupName = documentElement.attribute("name");
202                 kDebug() << "// SAVE, PARSING FROUP: " << i << ", name: " << groupName << ", LOOK FR: " << newGroupName;
203                 if (groupName == newGroupName) {
204                     groupExists = true;
205                     break;
206                 }
207                 i++;
208             }
209         if (!groupExists) {
210             documentElement = doc.createElement("group");
211             documentElement.setAttribute("name", ui.group_name->currentText());
212             documentElement.setAttribute("renderer", "avformat");
213             doc.documentElement().appendChild(documentElement);
214         }
215         QDomElement profileElement = doc.createElement("profile");
216         profileElement.setAttribute("name", newProfileName);
217         profileElement.setAttribute("extension", ui.extension->text().simplified());
218         profileElement.setAttribute("args", ui.parameters->toPlainText().simplified());
219         documentElement.appendChild(profileElement);
220
221         //QCString save = doc.toString().utf8();
222
223         if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
224             KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
225             delete d;
226             return;
227         }
228         QTextStream out(&file);
229         out << doc.toString();
230         file.close();
231         parseProfiles(newGroupName, newProfileName);
232     }
233     delete d;
234 }
235
236 void RenderWidget::slotEditProfile() {
237     QListWidgetItem *item = m_view.size_list->currentItem();
238     if (!item) return;
239     QString currentGroup = m_view.format_list->currentItem()->text();
240
241     QString params = item->data(ParamsRole).toString();
242     QString extension = item->data(ExtensionRole).toString();
243     QString currentProfile = item->text();
244
245     Ui::SaveProfile_UI ui;
246     QDialog *d = new QDialog(this);
247     ui.setupUi(d);
248     QStringList groupNames;
249     for (int i = 0; i < m_view.format_list->count(); i++)
250         groupNames.append(m_view.format_list->item(i)->text());
251     if (!groupNames.contains(currentGroup)) groupNames.prepend(currentGroup);
252     ui.group_name->addItems(groupNames);
253     int pos = ui.group_name->findText(currentGroup);
254     ui.group_name->setCurrentIndex(pos);
255     ui.profile_name->setText(currentProfile);
256     ui.extension->setText(extension);
257     ui.parameters->setText(params);
258     ui.profile_name->setFocus();
259
260     if (d->exec() == QDialog::Accepted) {
261         slotDeleteProfile();
262         QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
263         QDomDocument doc;
264         QFile file(exportFile);
265         doc.setContent(&file, false);
266         file.close();
267
268         QDomElement documentElement;
269         bool groupExists = false;
270         QString groupName;
271         QString newProfileName = ui.profile_name->text();
272         QString newGroupName = ui.group_name->currentText();
273         QDomNodeList groups = doc.elementsByTagName("group");
274         int i = 0;
275         if (groups.count() == 0) {
276             QDomElement profiles = doc.createElement("profiles");
277             doc.appendChild(profiles);
278         } else while (!groups.item(i).isNull()) {
279                 documentElement = groups.item(i).toElement();
280                 groupName = documentElement.attribute("name");
281                 kDebug() << "// SAVE, PARSING FROUP: " << i << ", name: " << groupName << ", LOOK FR: " << newGroupName;
282                 if (groupName == newGroupName) {
283                     groupExists = true;
284                     break;
285                 }
286                 i++;
287             }
288         if (!groupExists) {
289             documentElement = doc.createElement("group");
290             documentElement.setAttribute("name", ui.group_name->currentText());
291             documentElement.setAttribute("renderer", "avformat");
292             doc.documentElement().appendChild(documentElement);
293         }
294         QDomElement profileElement = doc.createElement("profile");
295         profileElement.setAttribute("name", newProfileName);
296         profileElement.setAttribute("extension", ui.extension->text().simplified());
297         profileElement.setAttribute("args", ui.parameters->toPlainText().simplified());
298         documentElement.appendChild(profileElement);
299
300         //QCString save = doc.toString().utf8();
301
302         if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
303             KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
304             delete d;
305             return;
306         }
307         QTextStream out(&file);
308         out << doc.toString();
309         file.close();
310         parseProfiles(newGroupName, newProfileName);
311     }
312     delete d;
313 }
314
315 void RenderWidget::slotDeleteProfile() {
316     QString currentGroup = m_view.format_list->currentItem()->text();
317     QString currentProfile = m_view.size_list->currentItem()->text();
318
319     QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
320     QDomDocument doc;
321     QFile file(exportFile);
322     doc.setContent(&file, false);
323     file.close();
324
325     QDomElement documentElement;
326     bool groupExists = false;
327     QString groupName;
328     QDomNodeList groups = doc.elementsByTagName("group");
329     int i = 0;
330
331     while (!groups.item(i).isNull()) {
332         documentElement = groups.item(i).toElement();
333         groupName = documentElement.attribute("name");
334         if (groupName == currentGroup) {
335             QDomNodeList children = documentElement.childNodes();
336             for (int j = 0; j < children.count(); j++) {
337                 QDomElement pro = children.at(j).toElement();
338                 if (pro.attribute("name") == currentProfile) {
339                     groups.item(i).removeChild(children.at(j));
340                     if (groups.item(i).childNodes().isEmpty())
341                         doc.documentElement().removeChild(groups.item(i));
342                     break;
343                 }
344             }
345             break;
346         }
347         i++;
348     }
349
350     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
351         KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
352         return;
353     }
354     QTextStream out(&file);
355     out << doc.toString();
356     file.close();
357     parseProfiles(currentGroup);
358     focusFirstVisibleItem();
359 }
360
361 void RenderWidget::updateButtons() {
362     if (!m_view.size_list->currentItem() || m_view.size_list->currentItem()->isHidden()) {
363         m_view.buttonSave->setEnabled(false);
364         m_view.buttonDelete->setEnabled(false);
365         m_view.buttonEdit->setEnabled(false);
366     } else {
367         m_view.buttonSave->setEnabled(true);
368         if (m_view.size_list->currentItem()->data(EditableRole).toString().isEmpty()) {
369             m_view.buttonDelete->setEnabled(false);
370             m_view.buttonEdit->setEnabled(false);
371         } else {
372             m_view.buttonDelete->setEnabled(true);
373             m_view.buttonEdit->setEnabled(true);
374         }
375     }
376 }
377
378
379 void RenderWidget::focusFirstVisibleItem() {
380     if (m_view.size_list->currentItem() && !m_view.size_list->currentItem()->isHidden()) {
381         updateButtons();
382         return;
383     }
384     for (uint ix = 0; ix < m_view.size_list->count(); ix++) {
385         QListWidgetItem *item = m_view.size_list->item(ix);
386         if (item && !item->isHidden()) {
387             m_view.size_list->setCurrentRow(ix);
388             break;
389         }
390     }
391     if (!m_view.size_list->currentItem()) m_view.size_list->setCurrentRow(0);
392     updateButtons();
393 }
394
395 void RenderWidget::slotExport() {
396     QListWidgetItem *item = m_view.size_list->currentItem();
397     if (!item) return;
398     QFile f(m_view.out_file->url().path());
399     if (f.exists()) {
400         if (KMessageBox::warningYesNo(this, i18n("File already exists. Do you want to overwrite it ?")) != KMessageBox::Yes)
401             return;
402     }
403     QStringList overlayargs;
404     if (m_view.tc_overlay->isChecked()) {
405         QString filterFile = KStandardDirs::locate("appdata", "metadata.properties");
406         overlayargs << "meta.attr.timecode=1" << "meta.attr.timecode.markup=#timecode";
407         overlayargs << "-attach" << "data_feed:attr_check" << "-attach";
408         overlayargs << "data_show:" + filterFile << "_fezzik=1" << "dynamic=1";
409     }
410     double startPos = -1;
411     double endPos = -1;
412     if (m_view.render_guide->isChecked()) {
413         startPos = m_view.guide_start->itemData(m_view.guide_start->currentIndex()).toDouble();
414         endPos = m_view.guide_end->itemData(m_view.guide_end->currentIndex()).toDouble();
415     }
416     QString renderArgs = m_view.advanced_params->toPlainText();
417     renderArgs.replace("%width", QString::number(m_profile.width));
418     renderArgs.replace("%height", QString::number(m_profile.height));
419     renderArgs.replace("%dar", "@" + QString::number(m_profile.display_aspect_num) + "/" + QString::number(m_profile.display_aspect_den));
420     if (m_view.force_progressive->checkState() == Qt::Checked) renderArgs.append(" progressive=1");
421     else if (m_view.force_progressive->checkState() == Qt::Unchecked) renderArgs.append(" progressive=0");
422
423     // Check if the rendering profile is different from project profile,
424     // in which case we need to use the producer_comsumer from MLT
425     bool resizeProfile = false;
426
427     QString std = item->data(ParamsRole).toString();
428     if (resizeProfile == false && std.contains(" s=")) {
429         QString subsize = std.section(" s=", 1, 1);
430         subsize = subsize.section(' ', 0, 0).toLower();
431         if (subsize != "%widthx%height") {
432             const QString currentSize = QString::number(m_profile.width) + 'x' + QString::number(m_profile.height);
433             if (subsize != currentSize) resizeProfile = true;
434         }
435     }
436
437     emit doRender(m_view.out_file->url().path(), item->data(RenderRole).toString(), overlayargs, renderArgs.simplified().split(' '), m_view.render_zone->isChecked(), m_view.play_after->isChecked(), startPos, endPos, resizeProfile);
438     m_view.tabWidget->setCurrentIndex(1);
439 }
440
441 void RenderWidget::setProfile(MltVideoProfile profile) {
442     m_profile = profile;
443     //WARNING: this way to tell the video standard is a bit hackish...
444     if (m_profile.description.contains("pal", Qt::CaseInsensitive) || m_profile.description.contains("25", Qt::CaseInsensitive) || m_profile.description.contains("50", Qt::CaseInsensitive)) m_view.format_selection->setCurrentIndex(0);
445     else m_view.format_selection->setCurrentIndex(1);
446     m_view.force_progressive->setCheckState(Qt::PartiallyChecked);
447     refreshView();
448 }
449
450 void RenderWidget::refreshView() {
451     m_view.size_list->blockSignals(true);
452     QListWidgetItem *item = m_view.format_list->currentItem();
453     if (!item) {
454         m_view.format_list->setCurrentRow(0);
455         item = m_view.format_list->currentItem();
456     }
457     if (!item) return;
458     QString std;
459     QString group = item->text();
460     QListWidgetItem *sizeItem;
461     bool firstSelected = false;
462     const QStringList formatsList = KdenliveSettings::supportedformats();
463     const QStringList vcodecsList = KdenliveSettings::videocodecs();
464     const QStringList acodecsList = KdenliveSettings::audiocodecs();
465     for (int i = 0; i < m_view.size_list->count(); i++) {
466         sizeItem = m_view.size_list->item(i);
467         if (sizeItem->data(GroupRole) == group) {
468             std = sizeItem->data(StandardRole).toString();
469             if (!std.isEmpty()) {
470                 if (std.contains("PAL", Qt::CaseInsensitive)) sizeItem->setHidden(m_view.format_selection->currentIndex() != 0);
471                 else if (std.contains("NTSC", Qt::CaseInsensitive)) sizeItem->setHidden(m_view.format_selection->currentIndex() != 1);
472             } else {
473                 sizeItem->setHidden(false);
474                 if (!firstSelected) m_view.size_list->setCurrentItem(sizeItem);
475                 firstSelected = true;
476             }
477             if (!KdenliveSettings::experimentalrender() && !sizeItem->isHidden()) {
478                 // hide experimental codecs (which do resize the video)
479                 std = sizeItem->data(ParamsRole).toString();
480                 if (std.contains(" s=")) {
481                     QString subsize = std.section(" s=", 1, 1);
482                     subsize = subsize.section(' ', 0, 0).toLower();
483                     if (subsize != "%widthx%height") {
484                         const QString currentSize = QString::number(m_profile.width) + 'x' + QString::number(m_profile.height);
485                         if (subsize != currentSize) sizeItem->setHidden(true);
486                     }
487                 }
488             }
489             if (!sizeItem->isHidden()) {
490                 // Make sure the selected profile uses an installed avformat codec / format
491                 std = sizeItem->data(ParamsRole).toString();
492
493                 if (!formatsList.isEmpty()) {
494                     QString format;
495                     if (std.startsWith("f=")) format = std.section("f=", 1, 1);
496                     else if (std.contains(" f=")) format = std.section(" f=", 1, 1);
497                     if (!format.isEmpty()) {
498                         format = format.section(' ', 0, 0).toLower();
499                         if (!formatsList.contains(format)) {
500                             kDebug() << "*****  UNSUPPORTED F: " << format;
501                             sizeItem->setHidden(true);
502                         }
503                     }
504                 }
505                 if (!acodecsList.isEmpty() && !sizeItem->isHidden()) {
506                     QString format;
507                     if (std.startsWith("acodec=")) format = std.section("acodec=", 1, 1);
508                     else if (std.contains(" acodec=")) format = std.section(" acodec=", 1, 1);
509                     if (!format.isEmpty()) {
510                         format = format.section(' ', 0, 0).toLower();
511                         if (!acodecsList.contains(format)) {
512                             kDebug() << "*****  UNSUPPORTED ACODEC: " << format;
513                             sizeItem->setHidden(true);
514                         }
515                     }
516                 }
517                 if (!vcodecsList.isEmpty() && !sizeItem->isHidden()) {
518                     QString format;
519                     if (std.startsWith("vcodec=")) format = std.section("vcodec=", 1, 1);
520                     else if (std.contains(" vcodec=")) format = std.section(" vcodec=", 1, 1);
521                     if (!format.isEmpty()) {
522                         format = format.section(' ', 0, 0).toLower();
523                         if (!vcodecsList.contains(format)) {
524                             kDebug() << "*****  UNSUPPORTED VCODEC: " << format;
525                             sizeItem->setHidden(true);
526                         }
527                     }
528                 }
529             }
530         } else sizeItem->setHidden(true);
531     }
532     focusFirstVisibleItem();
533     m_view.size_list->blockSignals(false);
534     refreshParams();
535 }
536
537 void RenderWidget::refreshParams() {
538     QListWidgetItem *item = m_view.size_list->currentItem();
539     if (!item || item->isHidden()) {
540         m_view.advanced_params->clear();
541         m_view.buttonStart->setEnabled(false);
542         return;
543     }
544     QString params = item->data(ParamsRole).toString();
545     QString extension = item->data(ExtensionRole).toString();
546     m_view.advanced_params->setPlainText(params);
547     m_view.advanced_params->setToolTip(params);
548     KUrl url = m_view.out_file->url();
549     if (!url.isEmpty()) {
550         QString path = url.path();
551         int pos = path.lastIndexOf('.') + 1;
552         if (pos == 0) path.append('.') + extension;
553         else path = path.left(pos) + extension;
554         m_view.out_file->setUrl(KUrl(path));
555     } else {
556         m_view.out_file->setUrl(KUrl(QDir::homePath() + "/untitled." + extension));
557     }
558     m_view.out_file->setFilter("*." + extension);
559
560     if (item->data(EditableRole).toString().isEmpty()) {
561         m_view.buttonDelete->setEnabled(false);
562         m_view.buttonEdit->setEnabled(false);
563     } else {
564         m_view.buttonDelete->setEnabled(true);
565         m_view.buttonEdit->setEnabled(true);
566     }
567     m_view.buttonStart->setEnabled(true);
568 }
569
570 void RenderWidget::parseProfiles(QString group, QString profile) {
571     m_view.size_list->clear();
572     m_view.format_list->clear();
573     QString exportFile = KStandardDirs::locate("appdata", "export/profiles.xml");
574     parseFile(exportFile, false);
575     exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
576     if (QFile::exists(exportFile)) parseFile(exportFile, true);
577     refreshView();
578     QList<QListWidgetItem *> child;
579     child = m_view.format_list->findItems(group, Qt::MatchExactly);
580     if (!child.isEmpty()) m_view.format_list->setCurrentItem(child.at(0));
581     child = m_view.size_list->findItems(profile, Qt::MatchExactly);
582     if (!child.isEmpty()) m_view.size_list->setCurrentItem(child.at(0));
583 }
584
585 void RenderWidget::parseFile(QString exportFile, bool editable) {
586     QDomDocument doc;
587     QFile file(exportFile);
588     doc.setContent(&file, false);
589     file.close();
590     QDomElement documentElement;
591     QDomElement profileElement;
592     QDomNodeList groups = doc.elementsByTagName("group");
593
594     if (groups.count() == 0) {
595         kDebug() << "// Export file: " << exportFile << " IS BROKEN";
596         return;
597     }
598
599     int i = 0;
600     QString groupName;
601     QString profileName;
602     QString extension;
603     QString prof_extension;
604     QString renderer;
605     QString params;
606     QString standard;
607     QListWidgetItem *item;
608     while (!groups.item(i).isNull()) {
609         documentElement = groups.item(i).toElement();
610         groupName = documentElement.attribute("name", QString::null);
611         extension = documentElement.attribute("extension", QString::null);
612         renderer = documentElement.attribute("renderer", QString::null);
613         if (m_view.format_list->findItems(groupName, Qt::MatchExactly).isEmpty())
614             new QListWidgetItem(groupName, m_view.format_list);
615
616         QDomNode n = groups.item(i).firstChild();
617         while (!n.isNull()) {
618             profileElement = n.toElement();
619             profileName = profileElement.attribute("name");
620             standard = profileElement.attribute("standard");
621             params = profileElement.attribute("args");
622             prof_extension = profileElement.attribute("extension");
623             if (!prof_extension.isEmpty()) extension = prof_extension;
624             item = new QListWidgetItem(profileName, m_view.size_list);
625             item->setData(GroupRole, groupName);
626             item->setData(ExtensionRole, extension);
627             item->setData(RenderRole, renderer);
628             item->setData(StandardRole, standard);
629             item->setData(ParamsRole, params);
630             if (editable) item->setData(EditableRole, "true");
631             n = n.nextSibling();
632         }
633
634         i++;
635     }
636 }
637
638 void RenderWidget::setRenderJob(const QString &dest, int progress) {
639     QList<QTreeWidgetItem *> existing = m_view.running_jobs->findItems(dest, Qt::MatchExactly);
640     if (!existing.isEmpty()) {
641         if (progress == -1) {
642             // Job finished successfully
643             existing.at(0)->setIcon(0, KIcon("dialog-ok"));
644             existing.at(0)->setData(1, Qt::UserRole, 100);
645         } else if (progress == -2) {
646             // Rendering crashed
647             existing.at(0)->setIcon(0, KIcon("dialog-close"));
648             existing.at(0)->setData(1, Qt::UserRole, 0);
649         } else if (progress == -3) {
650             // User aborted job
651             existing.at(0)->setIcon(0, KIcon("dialog-close"));
652             existing.at(0)->setData(1, Qt::UserRole, 100);
653         } else existing.at(0)->setData(1, Qt::UserRole, progress);
654         return;
655     }
656     QTreeWidgetItem *item = new QTreeWidgetItem(m_view.running_jobs, QStringList() << dest << QString());
657     if (progress == -1) {
658         // Job finished successfully
659         item->setIcon(0, KIcon("dialog-ok"));
660         item->setData(1, Qt::UserRole, 100);
661     } else if (progress == -2) {
662         // Rendering crashed
663         item->setIcon(0, KIcon("dialog-close"));
664         item->setData(1, Qt::UserRole, 0);
665     } else if (progress == -3) {
666         // User aborted job
667         item->setIcon(0, KIcon("dialog-close"));
668         item->setData(1, Qt::UserRole, 100);
669     } else item->setData(1, Qt::UserRole, progress);
670
671 }
672
673 void RenderWidget::slotAbortCurrentJob() {
674     QTreeWidgetItem *current = m_view.running_jobs->currentItem();
675     if (current) emit abortProcess(current->text(0));
676 }
677
678 #include "renderwidget.moc"