]> git.sesse.net Git - kdenlive/blob - src/renderwidget.cpp
Small fixes for composite transition and more fixes for title clips.
[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), m_standard("PAL") {
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     connect(m_view.buttonSave, SIGNAL(clicked()), this, SLOT(slotSaveProfile()));
53     connect(m_view.buttonEdit, SIGNAL(clicked()), this, SLOT(slotEditProfile()));
54     connect(m_view.buttonDelete, SIGNAL(clicked()), this, SLOT(slotDeleteProfile()));
55     connect(m_view.buttonStart, SIGNAL(clicked()), this, SLOT(slotExport()));
56     connect(m_view.out_file, SIGNAL(textChanged(const QString &)), this, SLOT(slotUpdateButtons()));
57     connect(m_view.format_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshView()));
58     connect(m_view.size_list, SIGNAL(currentRowChanged(int)), this, SLOT(refreshParams()));
59
60     m_view.buttonStart->setEnabled(false);
61     parseProfiles();
62 }
63
64 void RenderWidget::slotUpdateButtons() {
65     if (m_view.out_file->url().isEmpty()) m_view.buttonStart->setEnabled(false);
66     else m_view.buttonStart->setEnabled(true);
67 }
68
69 void RenderWidget::slotSaveProfile() {
70     Ui::SaveProfile_UI ui;
71     QDialog *d = new QDialog(this);
72     ui.setupUi(d);
73     QString customGroup = i18n("Custom");
74     QStringList groupNames;
75     for (int i = 0; i < m_view.format_list->count(); i++)
76         groupNames.append(m_view.format_list->item(i)->text());
77     if (!groupNames.contains(customGroup)) groupNames.prepend(customGroup);
78     ui.group_name->addItems(groupNames);
79     int pos = ui.group_name->findText(customGroup);
80     ui.group_name->setCurrentIndex(pos);
81
82     ui.parameters->setText(m_view.advanced_params->text());
83     ui.extension->setText(m_view.size_list->currentItem()->data(ExtensionRole).toString());
84     ui.profile_name->setFocus();
85     if (d->exec() == QDialog::Accepted) {
86         QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
87         QDomDocument doc;
88         QFile file(exportFile);
89         doc.setContent(&file, false);
90         file.close();
91
92         QDomElement documentElement;
93         bool groupExists = false;
94         QString groupName;
95         QString newProfileName = ui.profile_name->text();
96         QString newGroupName = ui.group_name->currentText();
97         QDomNodeList groups = doc.elementsByTagName("group");
98         int i = 0;
99         if (groups.count() == 0) {
100             QDomElement profiles = doc.createElement("profiles");
101             doc.appendChild(profiles);
102         } else while (!groups.item(i).isNull()) {
103                 documentElement = groups.item(i).toElement();
104                 groupName = documentElement.attribute("name");
105                 kDebug() << "// SAVE, PARSING FROUP: " << i << ", name: " << groupName << ", LOOK FR: " << newGroupName;
106                 if (groupName == newGroupName) {
107                     groupExists = true;
108                     break;
109                 }
110                 i++;
111             }
112         if (!groupExists) {
113             documentElement = doc.createElement("group");
114             documentElement.setAttribute("name", ui.group_name->currentText());
115             documentElement.setAttribute("renderer", "avformat");
116             doc.documentElement().appendChild(documentElement);
117         }
118         QDomElement profileElement = doc.createElement("profile");
119         profileElement.setAttribute("name", newProfileName);
120         profileElement.setAttribute("extension", ui.extension->text().simplified());
121         profileElement.setAttribute("args", ui.parameters->text().simplified());
122         documentElement.appendChild(profileElement);
123
124         //QCString save = doc.toString().utf8();
125
126         if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
127             KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
128             delete d;
129             return;
130         }
131         QTextStream out(&file);
132         out << doc.toString();
133         file.close();
134         parseProfiles(newGroupName, newProfileName);
135     }
136     delete d;
137 }
138
139 void RenderWidget::slotEditProfile() {
140     QListWidgetItem *item = m_view.size_list->currentItem();
141     if (!item) return;
142     QString currentGroup = m_view.format_list->currentItem()->text();
143
144     QString params = item->data(ParamsRole).toString();
145     QString extension = item->data(ExtensionRole).toString();
146     QString currentProfile = item->text();
147
148     Ui::SaveProfile_UI ui;
149     QDialog *d = new QDialog(this);
150     ui.setupUi(d);
151     QStringList groupNames;
152     for (int i = 0; i < m_view.format_list->count(); i++)
153         groupNames.append(m_view.format_list->item(i)->text());
154     if (!groupNames.contains(currentGroup)) groupNames.prepend(currentGroup);
155     ui.group_name->addItems(groupNames);
156     int pos = ui.group_name->findText(currentGroup);
157     ui.group_name->setCurrentIndex(pos);
158     ui.profile_name->setText(currentProfile);
159     ui.extension->setText(extension);
160     ui.parameters->setText(params);
161     ui.profile_name->setFocus();
162
163     if (d->exec() == QDialog::Accepted) {
164         slotDeleteProfile();
165         QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
166         QDomDocument doc;
167         QFile file(exportFile);
168         doc.setContent(&file, false);
169         file.close();
170
171         QDomElement documentElement;
172         bool groupExists = false;
173         QString groupName;
174         QString newProfileName = ui.profile_name->text();
175         QString newGroupName = ui.group_name->currentText();
176         QDomNodeList groups = doc.elementsByTagName("group");
177         int i = 0;
178         if (groups.count() == 0) {
179             QDomElement profiles = doc.createElement("profiles");
180             doc.appendChild(profiles);
181         } else while (!groups.item(i).isNull()) {
182                 documentElement = groups.item(i).toElement();
183                 groupName = documentElement.attribute("name");
184                 kDebug() << "// SAVE, PARSING FROUP: " << i << ", name: " << groupName << ", LOOK FR: " << newGroupName;
185                 if (groupName == newGroupName) {
186                     groupExists = true;
187                     break;
188                 }
189                 i++;
190             }
191         if (!groupExists) {
192             documentElement = doc.createElement("group");
193             documentElement.setAttribute("name", ui.group_name->currentText());
194             documentElement.setAttribute("renderer", "avformat");
195             doc.documentElement().appendChild(documentElement);
196         }
197         QDomElement profileElement = doc.createElement("profile");
198         profileElement.setAttribute("name", newProfileName);
199         profileElement.setAttribute("extension", ui.extension->text().simplified());
200         profileElement.setAttribute("args", ui.parameters->text().simplified());
201         documentElement.appendChild(profileElement);
202
203         //QCString save = doc.toString().utf8();
204
205         if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
206             KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
207             delete d;
208             return;
209         }
210         QTextStream out(&file);
211         out << doc.toString();
212         file.close();
213         parseProfiles(newGroupName, newProfileName);
214     }
215     delete d;
216 }
217
218 void RenderWidget::slotDeleteProfile() {
219     QString currentGroup = m_view.format_list->currentItem()->text();
220     QString currentProfile = m_view.size_list->currentItem()->text();
221
222     QString exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
223     QDomDocument doc;
224     QFile file(exportFile);
225     doc.setContent(&file, false);
226     file.close();
227
228     QDomElement documentElement;
229     bool groupExists = false;
230     QString groupName;
231     QDomNodeList groups = doc.elementsByTagName("group");
232     int i = 0;
233
234     while (!groups.item(i).isNull()) {
235         documentElement = groups.item(i).toElement();
236         groupName = documentElement.attribute("name");
237         if (groupName == currentGroup) {
238             QDomNodeList children = documentElement.childNodes();
239             for (int j = 0; j < children.count(); j++) {
240                 QDomElement pro = children.at(j).toElement();
241                 if (pro.attribute("name") == currentProfile) {
242                     groups.item(i).removeChild(children.at(j));
243                     if (groups.item(i).childNodes().isEmpty())
244                         doc.documentElement().removeChild(groups.item(i));
245                     break;
246                 }
247             }
248             break;
249         }
250         i++;
251     }
252
253     if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
254         KMessageBox::sorry(this, i18n("Unable to write to file %1", exportFile));
255         return;
256     }
257     QTextStream out(&file);
258     out << doc.toString();
259     file.close();
260     parseProfiles(currentGroup);
261 }
262
263 void RenderWidget::slotExport() {
264     QListWidgetItem *item = m_view.size_list->currentItem();
265     if (!item) return;
266     QFile f(m_view.out_file->url().path());
267     if (f.exists()) {
268         if (KMessageBox::warningYesNo(this, i18n("File already exists. Do you want to overwrite it ?")) != KMessageBox::Yes)
269             return;
270     }
271     QStringList overlayargs;
272     if (m_view.tc_overlay->isChecked()) {
273         QString filterFile = KStandardDirs::locate("appdata", "metadata.properties");
274         overlayargs << "meta.attr.timecode=1" << "meta.attr.timecode.markup=#timecode";
275         overlayargs << "-attach" << "data_feed:attr_check" << "-attach";
276         overlayargs << "data_show:" + filterFile << "_fezzik=1" << "dynamic=1";
277     }
278     emit doRender(m_view.out_file->url().path(), item->data(RenderRole).toString(), overlayargs, m_view.advanced_params->text().split(' '), m_view.zone_only->isChecked(), m_view.play_after->isChecked());
279 }
280
281 void RenderWidget::setDocumentStandard(QString std) {
282     m_standard = std;
283     refreshView();
284 }
285
286 void RenderWidget::refreshView() {
287     QListWidgetItem *item = m_view.format_list->currentItem();
288     if (!item) {
289         m_view.format_list->setCurrentRow(0);
290         item = m_view.format_list->currentItem();
291     }
292     if (!item) return;
293     QString std;
294     QString group = item->text();
295     QListWidgetItem *sizeItem;
296     bool firstSelected = false;
297     for (int i = 0; i < m_view.size_list->count(); i++) {
298         sizeItem = m_view.size_list->item(i);
299         std = sizeItem->data(StandardRole).toString();
300         if (!std.isEmpty() && !std.contains(m_standard, Qt::CaseInsensitive)) sizeItem->setHidden(true);
301         else if (sizeItem->data(GroupRole) == group) {
302             sizeItem->setHidden(false);
303             if (!firstSelected) m_view.size_list->setCurrentItem(sizeItem);
304             firstSelected = true;
305         } else sizeItem->setHidden(true);
306     }
307
308 }
309
310 void RenderWidget::refreshParams() {
311     QListWidgetItem *item = m_view.size_list->currentItem();
312     if (!item) return;
313     QString params = item->data(ParamsRole).toString();
314     QString extension = item->data(ExtensionRole).toString();
315     m_view.advanced_params->setText(params);
316     m_view.advanced_params->setToolTip(params);
317     KUrl url = m_view.out_file->url();
318     if (!url.isEmpty()) {
319         QString path = url.path();
320         int pos = path.lastIndexOf('.') + 1;
321         if (pos == 0) path.append('.') + extension;
322         else path = path.left(pos) + extension;
323         m_view.out_file->setUrl(KUrl(path));
324     } else {
325         m_view.out_file->setUrl(KUrl(QDir::homePath() + "/untitled." + extension));
326     }
327
328     if (item->data(EditableRole).toString().isEmpty()) {
329         m_view.buttonDelete->setEnabled(false);
330         m_view.buttonEdit->setEnabled(false);
331     } else {
332         m_view.buttonDelete->setEnabled(true);
333         m_view.buttonEdit->setEnabled(true);
334     }
335 }
336
337 void RenderWidget::parseProfiles(QString group, QString profile) {
338     m_view.size_list->clear();
339     m_view.format_list->clear();
340     QString exportFile = KStandardDirs::locate("appdata", "export/profiles.xml");
341     parseFile(exportFile, false);
342     exportFile = KStandardDirs::locateLocal("appdata", "export/customprofiles.xml");
343     parseFile(exportFile, true);
344     refreshView();
345     QList<QListWidgetItem *> child;
346     child = m_view.format_list->findItems(group, Qt::MatchExactly);
347     if (!child.isEmpty()) m_view.format_list->setCurrentItem(child.at(0));
348     child = m_view.size_list->findItems(profile, Qt::MatchExactly);
349     if (!child.isEmpty()) m_view.size_list->setCurrentItem(child.at(0));
350 }
351
352 void RenderWidget::parseFile(QString exportFile, bool editable) {
353     QDomDocument doc;
354     QFile file(exportFile);
355     doc.setContent(&file, false);
356     file.close();
357     QDomElement documentElement;
358     QDomElement profileElement;
359     QDomNodeList groups = doc.elementsByTagName("group");
360
361     if (groups.count() == 0) {
362         kDebug() << "// Export file: " << exportFile << " IS BROKEN";
363         return;
364     }
365
366     int i = 0;
367     QString groupName;
368     QString profileName;
369     QString extension;
370     QString prof_extension;
371     QString renderer;
372     QString params;
373     QString standard;
374     QListWidgetItem *item;
375     while (!groups.item(i).isNull()) {
376         documentElement = groups.item(i).toElement();
377         groupName = documentElement.attribute("name", QString::null);
378         extension = documentElement.attribute("extension", QString::null);
379         renderer = documentElement.attribute("renderer", QString::null);
380         if (m_view.format_list->findItems(groupName, Qt::MatchExactly).isEmpty())
381             new QListWidgetItem(groupName, m_view.format_list);
382
383         QDomNode n = groups.item(i).firstChild();
384         while (!n.isNull()) {
385             profileElement = n.toElement();
386             profileName = profileElement.attribute("name");
387             standard = profileElement.attribute("standard");
388             params = profileElement.attribute("args");
389             prof_extension = profileElement.attribute("extension");
390             if (!prof_extension.isEmpty()) extension = prof_extension;
391             item = new QListWidgetItem(profileName, m_view.size_list);
392             item->setData(GroupRole, groupName);
393             item->setData(ExtensionRole, extension);
394             item->setData(RenderRole, renderer);
395             item->setData(StandardRole, standard);
396             item->setData(ParamsRole, params);
397             if (editable) item->setData(EditableRole, "true");
398             n = n.nextSibling();
399         }
400
401         i++;
402     }
403 }
404
405
406
407 #include "renderwidget.moc"
408
409