]> git.sesse.net Git - kdenlive/blob - src/renderwidget.cpp
indentation fixes
[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
23 #include <KStandardDirs>
24 #include <KDebug>
25 #include <KMessageBox>
26 #include <KComboBox>
27
28 #include "kdenlivesettings.h"
29 #include "renderwidget.h"
30 #include "ui_saveprofile_ui.h"
31
32 const int GroupRole = Qt::UserRole;
33 const int ExtensionRole = GroupRole + 1;
34 const int StandardRole = GroupRole + 2;
35 const int RenderRole = GroupRole + 3;
36 const int ParamsRole = GroupRole + 4;
37 const int EditableRole = GroupRole + 5;
38
39 RenderWidget::RenderWidget(QWidget * parent): QDialog(parent) {
40     m_view.setupUi(this);
41     m_view.buttonDelete->setIcon(KIcon("trash-empty"));
42     m_view.buttonDelete->setToolTip(i18n("Delete profile"));
43     m_view.buttonDelete->setEnabled(false);
44
45     m_view.buttonEdit->setIcon(KIcon("document-properties"));
46     m_view.buttonEdit->setToolTip(i18n("Edit profile"));
47     m_view.buttonEdit->setEnabled(false);
48
49     m_view.buttonSave->setIcon(KIcon("document-new"));
50     m_view.buttonSave->setToolTip(i18n("Create new profile"));
51
52     m_view.buttonInfo->setIcon(KIcon("help-about"));
53
54     if (KdenliveSettings::showrenderparams()) {
55         m_view.buttonInfo->setDown(true);
56     } else m_view.advanced_params->hide();
57
58     connect(m_view.buttonInfo, SIGNAL(clicked()), this, SLOT(showInfoPanel()));
59
60     connect(m_view.buttonSave, SIGNAL(clicked()), this, SLOT(slotSaveProfile()));
61     connect(m_view.buttonEdit, SIGNAL(clicked()), this, SLOT(slotEditProfile()));
62     connect(m_view.buttonDelete, SIGNAL(clicked()), this, SLOT(slotDeleteProfile()));
63     connect(m_view.buttonStart, SIGNAL(clicked()), this, SLOT(slotExport()));
64     connect(m_view.out_file, SIGNAL(textChanged(const QString &)), this, SLOT(slotUpdateButtons()));
65     connect(m_view.format_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshView()));
66     connect(m_view.size_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshParams()));
67
68     connect(m_view.render_guide, SIGNAL(clicked(bool)), this, SLOT(slotUpdateGuideBox()));
69     connect(m_view.render_zone, SIGNAL(clicked(bool)), this, SLOT(slotUpdateGuideBox()));
70     connect(m_view.render_full, SIGNAL(clicked(bool)), this, SLOT(slotUpdateGuideBox()));
71
72     connect(m_view.guide_end, SIGNAL(activated(int)), this, SLOT(slotCheckStartGuidePosition()));
73     connect(m_view.guide_start, SIGNAL(activated(int)), this, SLOT(slotCheckEndGuidePosition()));
74
75     connect(m_view.format_selection, SIGNAL(activated(int)), this, SLOT(refreshView()));
76
77     m_view.buttonStart->setEnabled(false);
78     m_view.guides_box->setVisible(false);
79     parseProfiles();
80     m_view.splitter->setStretchFactor(1, 5);
81     m_view.splitter->setStretchFactor(0, 2);
82
83     focusFirstVisibleItem();
84 }
85
86 void RenderWidget::showInfoPanel() {
87     if (m_view.advanced_params->isVisible()) {
88         m_view.advanced_params->setVisible(false);
89         m_view.buttonInfo->setDown(false);
90         KdenliveSettings::setShowrenderparams(false);
91     } else {
92         m_view.advanced_params->setVisible(true);
93         m_view.buttonInfo->setDown(true);
94         KdenliveSettings::setShowrenderparams(true);
95     }
96 }
97
98 void RenderWidget::slotUpdateGuideBox() {
99     m_view.guides_box->setVisible(m_view.render_guide->isChecked());
100 }
101
102 void RenderWidget::slotCheckStartGuidePosition() {
103     if (m_view.guide_start->currentIndex() > m_view.guide_end->currentIndex())
104         m_view.guide_start->setCurrentIndex(m_view.guide_end->currentIndex());
105 }
106
107 void RenderWidget::slotCheckEndGuidePosition() {
108     if (m_view.guide_end->currentIndex() < m_view.guide_start->currentIndex())
109         m_view.guide_end->setCurrentIndex(m_view.guide_start->currentIndex());
110 }
111
112 void RenderWidget::setGuides(QDomElement guidesxml, double duration) {
113     m_view.guide_start->clear();
114     m_view.guide_end->clear();
115     QDomNodeList nodes = guidesxml.elementsByTagName("guide");
116     if (nodes.count() > 0) {
117         m_view.guide_start->addItem(i18n("Render"), "0");
118         m_view.render_guide->setEnabled(true);
119     } else m_view.render_guide->setEnabled(false);
120     for (int i = 0; i < nodes.count(); i++) {
121         QDomElement e = nodes.item(i).toElement();
122         if (!e.isNull()) {
123             m_view.guide_start->addItem(e.attribute("comment"), e.attribute("time").toDouble());
124             m_view.guide_end->addItem(e.attribute("comment"), e.attribute("time").toDouble());
125         }
126     }
127     if (nodes.count() > 0)
128         m_view.guide_end->addItem(i18n("End"), QString::number(duration));
129 }
130
131 void RenderWidget::slotUpdateButtons() {
132     if (m_view.out_file->url().isEmpty()) m_view.buttonStart->setEnabled(false);
133     else m_view.buttonStart->setEnabled(true);
134 }
135
136 void RenderWidget::slotSaveProfile() {
137     Ui::SaveProfile_UI ui;
138     QDialog *d = new QDialog(this);
139     ui.setupUi(d);
140     QString customGroup = i18n("Custom");
141     QStringList groupNames;
142     for (int i = 0; i < m_view.format_list->count(); i++)
143         groupNames.append(m_view.format_list->item(i)->text());
144     if (!groupNames.contains(customGroup)) groupNames.prepend(customGroup);
145     ui.group_name->addItems(groupNames);
146     int pos = ui.group_name->findText(customGroup);
147     ui.group_name->setCurrentIndex(pos);
148
149     ui.parameters->setText(m_view.advanced_params->toPlainText());
150     ui.extension->setText(m_view.size_list->currentItem()->data(ExtensionRole).toString());
151     ui.profile_name->setFocus();
152     if (d->exec() == QDialog::Accepted && !ui.profile_name->text().simplified().isEmpty()) {
153         QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
154         QDomDocument doc;
155         QFile file(exportFile);
156         doc.setContent(&file, false);
157         file.close();
158
159         QDomElement documentElement;
160         bool groupExists = false;
161         QString groupName;
162         QString newProfileName = ui.profile_name->text().simplified();
163         QString newGroupName = ui.group_name->currentText();
164         QDomNodeList groups = doc.elementsByTagName("group");
165         int i = 0;
166         if (groups.count() == 0) {
167             QDomElement profiles = doc.createElement("profiles");
168             doc.appendChild(profiles);
169         } else while (!groups.item(i).isNull()) {
170                 documentElement = groups.item(i).toElement();
171                 groupName = documentElement.attribute("name");
172                 kDebug() << "// SAVE, PARSING FROUP: " << i << ", name: " << groupName << ", LOOK FR: " << newGroupName;
173                 if (groupName == newGroupName) {
174                     groupExists = true;
175                     break;
176                 }
177                 i++;
178             }
179         if (!groupExists) {
180             documentElement = doc.createElement("group");
181             documentElement.setAttribute("name", ui.group_name->currentText());
182             documentElement.setAttribute("renderer", "avformat");
183             doc.documentElement().appendChild(documentElement);
184         }
185         QDomElement profileElement = doc.createElement("profile");
186         profileElement.setAttribute("name", newProfileName);
187         profileElement.setAttribute("extension", ui.extension->text().simplified());
188         profileElement.setAttribute("args", ui.parameters->toPlainText().simplified());
189         documentElement.appendChild(profileElement);
190
191         //QCString save = doc.toString().utf8();
192
193         if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
194             KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
195             delete d;
196             return;
197         }
198         QTextStream out(&file);
199         out << doc.toString();
200         file.close();
201         parseProfiles(newGroupName, newProfileName);
202     }
203     delete d;
204 }
205
206 void RenderWidget::slotEditProfile() {
207     QListWidgetItem *item = m_view.size_list->currentItem();
208     if (!item) return;
209     QString currentGroup = m_view.format_list->currentItem()->text();
210
211     QString params = item->data(ParamsRole).toString();
212     QString extension = item->data(ExtensionRole).toString();
213     QString currentProfile = item->text();
214
215     Ui::SaveProfile_UI ui;
216     QDialog *d = new QDialog(this);
217     ui.setupUi(d);
218     QStringList groupNames;
219     for (int i = 0; i < m_view.format_list->count(); i++)
220         groupNames.append(m_view.format_list->item(i)->text());
221     if (!groupNames.contains(currentGroup)) groupNames.prepend(currentGroup);
222     ui.group_name->addItems(groupNames);
223     int pos = ui.group_name->findText(currentGroup);
224     ui.group_name->setCurrentIndex(pos);
225     ui.profile_name->setText(currentProfile);
226     ui.extension->setText(extension);
227     ui.parameters->setText(params);
228     ui.profile_name->setFocus();
229
230     if (d->exec() == QDialog::Accepted) {
231         slotDeleteProfile();
232         QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
233         QDomDocument doc;
234         QFile file(exportFile);
235         doc.setContent(&file, false);
236         file.close();
237
238         QDomElement documentElement;
239         bool groupExists = false;
240         QString groupName;
241         QString newProfileName = ui.profile_name->text();
242         QString newGroupName = ui.group_name->currentText();
243         QDomNodeList groups = doc.elementsByTagName("group");
244         int i = 0;
245         if (groups.count() == 0) {
246             QDomElement profiles = doc.createElement("profiles");
247             doc.appendChild(profiles);
248         } else while (!groups.item(i).isNull()) {
249                 documentElement = groups.item(i).toElement();
250                 groupName = documentElement.attribute("name");
251                 kDebug() << "// SAVE, PARSING FROUP: " << i << ", name: " << groupName << ", LOOK FR: " << newGroupName;
252                 if (groupName == newGroupName) {
253                     groupExists = true;
254                     break;
255                 }
256                 i++;
257             }
258         if (!groupExists) {
259             documentElement = doc.createElement("group");
260             documentElement.setAttribute("name", ui.group_name->currentText());
261             documentElement.setAttribute("renderer", "avformat");
262             doc.documentElement().appendChild(documentElement);
263         }
264         QDomElement profileElement = doc.createElement("profile");
265         profileElement.setAttribute("name", newProfileName);
266         profileElement.setAttribute("extension", ui.extension->text().simplified());
267         profileElement.setAttribute("args", ui.parameters->toPlainText().simplified());
268         documentElement.appendChild(profileElement);
269
270         //QCString save = doc.toString().utf8();
271
272         if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
273             KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
274             delete d;
275             return;
276         }
277         QTextStream out(&file);
278         out << doc.toString();
279         file.close();
280         parseProfiles(newGroupName, newProfileName);
281     }
282     delete d;
283 }
284
285 void RenderWidget::slotDeleteProfile() {
286     QString currentGroup = m_view.format_list->currentItem()->text();
287     QString currentProfile = m_view.size_list->currentItem()->text();
288
289     QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
290     QDomDocument doc;
291     QFile file(exportFile);
292     doc.setContent(&file, false);
293     file.close();
294
295     QDomElement documentElement;
296     bool groupExists = false;
297     QString groupName;
298     QDomNodeList groups = doc.elementsByTagName("group");
299     int i = 0;
300
301     while (!groups.item(i).isNull()) {
302         documentElement = groups.item(i).toElement();
303         groupName = documentElement.attribute("name");
304         if (groupName == currentGroup) {
305             QDomNodeList children = documentElement.childNodes();
306             for (int j = 0; j < children.count(); j++) {
307                 QDomElement pro = children.at(j).toElement();
308                 if (pro.attribute("name") == currentProfile) {
309                     groups.item(i).removeChild(children.at(j));
310                     if (groups.item(i).childNodes().isEmpty())
311                         doc.documentElement().removeChild(groups.item(i));
312                     break;
313                 }
314             }
315             break;
316         }
317         i++;
318     }
319
320     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
321         KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
322         return;
323     }
324     QTextStream out(&file);
325     out << doc.toString();
326     file.close();
327     parseProfiles(currentGroup);
328     focusFirstVisibleItem();
329 }
330
331 void RenderWidget::focusFirstVisibleItem() {
332     if (m_view.size_list->currentItem() && !m_view.size_list->currentItem()->isHidden()) return;
333     for (uint ix = 0; ix < m_view.size_list->count(); ix++) {
334         QListWidgetItem *item = m_view.size_list->item(ix);
335         if (item && !item->isHidden()) {
336             m_view.size_list->setCurrentRow(ix);
337             break;
338         }
339     }
340     if (!m_view.size_list->currentItem()) m_view.size_list->setCurrentRow(0);
341 }
342
343 void RenderWidget::slotExport() {
344     QListWidgetItem *item = m_view.size_list->currentItem();
345     if (!item) return;
346     QFile f(m_view.out_file->url().path());
347     if (f.exists()) {
348         if (KMessageBox::warningYesNo(this, i18n("File already exists. Do you want to overwrite it ?")) != KMessageBox::Yes)
349             return;
350     }
351     QStringList overlayargs;
352     if (m_view.tc_overlay->isChecked()) {
353         QString filterFile = KStandardDirs::locate("appdata", "metadata.properties");
354         overlayargs << "meta.attr.timecode=1" << "meta.attr.timecode.markup=#timecode";
355         overlayargs << "-attach" << "data_feed:attr_check" << "-attach";
356         overlayargs << "data_show:" + filterFile << "_fezzik=1" << "dynamic=1";
357     }
358     double startPos = -1;
359     double endPos = -1;
360     if (m_view.render_guide->isChecked()) {
361         startPos = m_view.guide_start->itemData(m_view.guide_start->currentIndex()).toDouble();
362         endPos = m_view.guide_end->itemData(m_view.guide_end->currentIndex()).toDouble();
363     }
364     emit doRender(m_view.out_file->url().path(), item->data(RenderRole).toString(), overlayargs, m_view.advanced_params->toPlainText().split(' '), m_view.render_zone->isChecked(), m_view.play_after->isChecked(), startPos, endPos);
365 }
366
367 void RenderWidget::setDocumentStandard(QString std) {
368     if (std == "PAL") m_view.format_selection->setCurrentIndex(0);
369     else m_view.format_selection->setCurrentIndex(1);
370
371     refreshView();
372 }
373
374 void RenderWidget::refreshView() {
375     QListWidgetItem *item = m_view.format_list->currentItem();
376     if (!item) {
377         m_view.format_list->setCurrentRow(0);
378         item = m_view.format_list->currentItem();
379     }
380     if (!item) return;
381     QString std;
382     QString group = item->text();
383     QListWidgetItem *sizeItem;
384     bool firstSelected = false;
385     for (int i = 0; i < m_view.size_list->count(); i++) {
386         sizeItem = m_view.size_list->item(i);
387         std = sizeItem->data(StandardRole).toString();
388         if (sizeItem->data(GroupRole) == group) {
389             if (!std.isEmpty()) {
390                 if (std.contains("PAL", Qt::CaseInsensitive)) sizeItem->setHidden(m_view.format_selection->currentIndex() != 0);
391                 else if (std.contains("NTSC", Qt::CaseInsensitive)) sizeItem->setHidden(m_view.format_selection->currentIndex() != 1);
392             } else {
393                 sizeItem->setHidden(false);
394                 if (!firstSelected) m_view.size_list->setCurrentItem(sizeItem);
395                 firstSelected = true;
396             }
397         } else sizeItem->setHidden(true);
398     }
399     focusFirstVisibleItem();
400
401 }
402
403 void RenderWidget::refreshParams() {
404     QListWidgetItem *item = m_view.size_list->currentItem();
405     if (!item) return;
406     QString params = item->data(ParamsRole).toString();
407     QString extension = item->data(ExtensionRole).toString();
408     m_view.advanced_params->setPlainText(params);
409     m_view.advanced_params->setToolTip(params);
410     KUrl url = m_view.out_file->url();
411     if (!url.isEmpty()) {
412         QString path = url.path();
413         int pos = path.lastIndexOf('.') + 1;
414         if (pos == 0) path.append('.') + extension;
415         else path = path.left(pos) + extension;
416         m_view.out_file->setUrl(KUrl(path));
417     } else {
418         m_view.out_file->setUrl(KUrl(QDir::homePath() + "/untitled." + extension));
419     }
420
421     if (item->data(EditableRole).toString().isEmpty()) {
422         m_view.buttonDelete->setEnabled(false);
423         m_view.buttonEdit->setEnabled(false);
424     } else {
425         m_view.buttonDelete->setEnabled(true);
426         m_view.buttonEdit->setEnabled(true);
427     }
428 }
429
430 void RenderWidget::parseProfiles(QString group, QString profile) {
431     m_view.size_list->clear();
432     m_view.format_list->clear();
433     QString exportFile = KStandardDirs::locate("appdata", "export/profiles.xml");
434     parseFile(exportFile, false);
435     exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
436     if (QFile::exists(exportFile)) parseFile(exportFile, true);
437     refreshView();
438     QList<QListWidgetItem *> child;
439     child = m_view.format_list->findItems(group, Qt::MatchExactly);
440     if (!child.isEmpty()) m_view.format_list->setCurrentItem(child.at(0));
441     child = m_view.size_list->findItems(profile, Qt::MatchExactly);
442     if (!child.isEmpty()) m_view.size_list->setCurrentItem(child.at(0));
443 }
444
445 void RenderWidget::parseFile(QString exportFile, bool editable) {
446     QDomDocument doc;
447     QFile file(exportFile);
448     doc.setContent(&file, false);
449     file.close();
450     QDomElement documentElement;
451     QDomElement profileElement;
452     QDomNodeList groups = doc.elementsByTagName("group");
453
454     if (groups.count() == 0) {
455         kDebug() << "// Export file: " << exportFile << " IS BROKEN";
456         return;
457     }
458
459     int i = 0;
460     QString groupName;
461     QString profileName;
462     QString extension;
463     QString prof_extension;
464     QString renderer;
465     QString params;
466     QString standard;
467     QListWidgetItem *item;
468     while (!groups.item(i).isNull()) {
469         documentElement = groups.item(i).toElement();
470         groupName = documentElement.attribute("name", QString::null);
471         extension = documentElement.attribute("extension", QString::null);
472         renderer = documentElement.attribute("renderer", QString::null);
473         if (m_view.format_list->findItems(groupName, Qt::MatchExactly).isEmpty())
474             new QListWidgetItem(groupName, m_view.format_list);
475
476         QDomNode n = groups.item(i).firstChild();
477         while (!n.isNull()) {
478             profileElement = n.toElement();
479             profileName = profileElement.attribute("name");
480             standard = profileElement.attribute("standard");
481             params = profileElement.attribute("args");
482             prof_extension = profileElement.attribute("extension");
483             if (!prof_extension.isEmpty()) extension = prof_extension;
484             item = new QListWidgetItem(profileName, m_view.size_list);
485             item->setData(GroupRole, groupName);
486             item->setData(ExtensionRole, extension);
487             item->setData(RenderRole, renderer);
488             item->setData(StandardRole, standard);
489             item->setData(ParamsRole, params);
490             if (editable) item->setData(EditableRole, "true");
491             n = n.nextSibling();
492         }
493
494         i++;
495     }
496 }
497
498
499
500 #include "renderwidget.moc"
501
502