]> git.sesse.net Git - kdenlive/blob - src/kdenlivedoc.cpp
small bugfixes
[kdenlive] / src / kdenlivedoc.cpp
1 /***************************************************************************
2  *   Copyright (C) 2007 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 #include <KDebug>
21 #include <KStandardDirs>
22 #include <KMessageBox>
23 #include <KLocale>
24 #include <KFileDialog>
25 #include <KIO/NetAccess>
26 #include <KApplication>
27
28 #include "kdenlivedoc.h"
29 #include "docclipbase.h"
30 #include "profilesdialog.h"
31 #include "kdenlivesettings.h"
32 #include "renderer.h"
33 #include "clipmanager.h"
34 #include "addfoldercommand.h"
35 #include "editfoldercommand.h"
36 #include "titlewidget.h"
37 #include "mainwindow.h"
38
39 KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, MltVideoProfile profile, QUndoGroup *undoGroup, MainWindow *parent): QObject(parent), m_render(NULL), m_url(url), m_projectFolder(projectFolder), m_profile(profile), m_fps((double)profile.frame_rate_num / profile.frame_rate_den), m_width(profile.width), m_height(profile.height), m_commandStack(new KUndoStack(undoGroup)), m_modified(false), m_documentLoadingProgress(0), m_documentLoadingStep(0.0), m_startPos(0) {
40     m_clipManager = new ClipManager(this);
41     if (!url.isEmpty()) {
42         QString tmpFile;
43         if (KIO::NetAccess::download(url.path(), tmpFile, parent)) {
44             QFile file(tmpFile);
45             m_document.setContent(&file, false);
46             file.close();
47             QDomNode infoXmlNode = m_document.elementsByTagName("kdenlivedoc").at(0);
48             QDomNode westley = m_document.elementsByTagName("westley").at(0);
49             if (!infoXmlNode.isNull()) {
50                 QDomElement infoXml = infoXmlNode.toElement();
51                 QString profilePath = infoXml.attribute("profile");
52                 m_startPos = infoXml.attribute("position").toInt();
53                 if (!profilePath.isEmpty()) setProfilePath(profilePath);
54                 double version = infoXml.attribute("version").toDouble();
55                 if (version < 0.7) convertDocument(version);
56                 else {
57                     //delete all mlt producers and instead, use Kdenlive saved producers
58                     QDomNodeList prods = m_document.elementsByTagName("producer");
59                     int maxprod = prods.count();
60                     int pos = 0;
61                     for (int i = 0; i < maxprod; i++) {
62                         QDomNode m = prods.at(pos);
63                         if (m.toElement().attribute("id") == "black")
64                             pos = 1;
65                         else westley.removeChild(m);
66                     }
67                     prods = m_document.elementsByTagName("kdenlive_producer");
68                     maxprod = prods.count();
69                     for (int i = 0; i < maxprod; i++) {
70                         prods.at(0).toElement().setTagName("producer");
71                         westley.insertBefore(prods.at(0), QDomNode());
72                     }
73                 }
74                 QDomElement e;
75                 QDomNodeList producers = m_document.elementsByTagName("producer");
76                 const int max = producers.count();
77                 if (max > 0) {
78                     m_documentLoadingStep = 100.0 / (max + m_document.elementsByTagName("entry").count());
79                     parent->slotGotProgressInfo(i18n("Loading project clips"), (int) m_documentLoadingProgress);
80                 }
81
82                 for (int i = 0; i < max; i++) {
83                     e = producers.item(i).cloneNode().toElement();
84                     if (m_documentLoadingStep > 0) {
85                         m_documentLoadingProgress += m_documentLoadingStep;
86                         parent->slotGotProgressInfo(QString(), (int) m_documentLoadingProgress);
87                         qApp->processEvents();
88                     }
89                     if (!e.isNull() && e.attribute("id") != "black") {
90                         addClip(e, e.attribute("id").toInt());
91                     }
92                 }
93
94                 QDomNode markers = m_document.elementsByTagName("markers").at(0);
95                 if (!markers.isNull()) {
96                     QDomNodeList markerslist = markers.childNodes();
97                     int maxchild = markerslist.count();
98                     for (int k = 0; k < maxchild; k++) {
99                         e = markerslist.at(k).toElement();
100                         if (e.tagName() == "marker") {
101                             int id = e.attribute("id").toInt();
102                             m_clipManager->getClipById(id)->addSnapMarker(GenTime(e.attribute("time").toDouble()), e.attribute("comment"));
103                         }
104                     }
105                     m_document.removeChild(markers);
106                 }
107                 m_document.removeChild(infoXmlNode);
108
109                 kDebug() << "Reading file: " << url.path() << ", found clips: " << producers.count();
110             } else kWarning() << "  NO KDENLIVE INFO FOUND IN FILE: " << url.path();
111             KIO::NetAccess::removeTempFile(tmpFile);
112         } else {
113             KMessageBox::error(parent, KIO::NetAccess::lastErrorString());
114         }
115     } else {
116         // Creating new document
117         QDomElement westley = m_document.createElement("westley");
118         m_document.appendChild(westley);
119
120         QDomElement tractor = m_document.createElement("tractor");
121         tractor.setAttribute("id", "maintractor");
122         QDomElement multitrack = m_document.createElement("multitrack");
123         QDomElement playlist = m_document.createElement("playlist");
124         playlist.setAttribute("id", "black_track");
125         westley.appendChild(playlist);
126
127
128         // create playlists
129         int audiotracks = 2;
130         int videotracks = 3;
131         int total = audiotracks + videotracks + 1;
132
133         for (int i = 1; i < total; i++) {
134             QDomElement playlist = m_document.createElement("playlist");
135             playlist.setAttribute("id", "playlist" + QString::number(i));
136             westley.appendChild(playlist);
137         }
138
139         QDomElement track0 = m_document.createElement("track");
140         track0.setAttribute("producer", "black_track");
141         tractor.appendChild(track0);
142
143         // create audio tracks
144         for (int i = 1; i < audiotracks + 1; i++) {
145             QDomElement track = m_document.createElement("track");
146             track.setAttribute("producer", "playlist" + QString::number(i));
147             track.setAttribute("hide", "video");
148             tractor.appendChild(track);
149         }
150
151         // create video tracks
152         for (int i = audiotracks + 1; i < total; i++) {
153             QDomElement track = m_document.createElement("track");
154             track.setAttribute("producer", "playlist" + QString::number(i));
155             tractor.appendChild(track);
156         }
157
158         for (uint i = 2; i < total ; i++) {
159             QDomElement transition = m_document.createElement("transition");
160             transition.setAttribute("in", "0");
161             //TODO: Make audio mix last for all project duration
162             transition.setAttribute("out", "15000");
163
164             QDomElement property = m_document.createElement("property");
165             property.setAttribute("name", "a_track");
166             QDomText value = m_document.createTextNode(QString::number(1));
167             property.appendChild(value);
168             transition.appendChild(property);
169
170             property = m_document.createElement("property");
171             property.setAttribute("name", "b_track");
172             value = m_document.createTextNode(QString::number(i));
173             property.appendChild(value);
174             transition.appendChild(property);
175
176             property = m_document.createElement("property");
177             property.setAttribute("name", "mlt_service");
178             value = m_document.createTextNode("mix");
179             property.appendChild(value);
180             transition.appendChild(property);
181
182             property = m_document.createElement("property");
183             property.setAttribute("name", "combine");
184             value = m_document.createTextNode("1");
185             property.appendChild(value);
186             transition.appendChild(property);
187
188             property = m_document.createElement("property");
189             property.setAttribute("name", "internal_added");
190             value = m_document.createTextNode("237");
191             property.appendChild(value);
192             transition.appendChild(property);
193             tractor.appendChild(transition);
194         }
195         westley.appendChild(tractor);
196     }
197     m_scenelist = m_document.toString();
198     // kDebug() << "scenelist" << m_scenelist;
199     if (m_fps == 30000.0 / 1001.0) m_timecode.setFormat(30, true);
200     else m_timecode.setFormat((int) m_fps);
201 }
202
203 KdenliveDoc::~KdenliveDoc() {
204     delete m_commandStack;
205     delete m_clipManager;
206 }
207
208 void KdenliveDoc::convertDocument(double version) {
209     // Opening a old Kdenlive document
210     QDomNode westley = m_document.elementsByTagName("westley").at(1);
211     QDomNode tractor = m_document.elementsByTagName("tractor").at(0);
212     QDomNode kdenlivedoc = m_document.elementsByTagName("kdenlivedoc").at(0);
213     QDomNode multitrack = m_document.elementsByTagName("multitrack").at(0);
214     QDomNodeList playlists = m_document.elementsByTagName("playlist");
215
216     QDomNode props = m_document.elementsByTagName("properties").at(0).toElement();
217     QString profile = props.toElement().attribute("videoprofile");
218     if (profile == "dv_wide") profile = "dv_pal_wide";
219     if (!profile.isEmpty()) {
220         setProfilePath(profile);
221     } else setProfilePath("dv_pal");
222
223     // move playlists outside of tractor and add the tracks instead
224     int max = playlists.count();
225     for (int i = 0; i < max; i++) {
226         QDomNode n = playlists.at(i);
227         westley.insertBefore(n, QDomNode());
228         QDomElement pl = n.toElement();
229         QDomElement track = m_document.createElement("track");
230         QString trackType = pl.attribute("hide");
231         if (!trackType.isEmpty()) track.setAttribute("hide", trackType);
232         QString playlist_id =  pl.attribute("id");
233         if (playlist_id.isEmpty()) {
234             playlist_id = "black_track";
235             pl.setAttribute("id", playlist_id);
236         }
237         track.setAttribute("producer", playlist_id);
238         tractor.appendChild(track);
239     }
240     tractor.removeChild(multitrack);
241
242     // audio track mixing transitions should not be added to track view, so add required attribute
243     QDomNodeList transitions = m_document.elementsByTagName("transition");
244     max = transitions.count();
245     for (int i = 0; i < max; i++) {
246         QDomElement tr = transitions.at(i).toElement();
247         if (tr.attribute("combine") == "1" && tr.attribute("mlt_service") == "mix") {
248             QDomElement property = m_document.createElement("property");
249             property.setAttribute("name", "internal_added");
250             QDomText value = m_document.createTextNode("237");
251             property.appendChild(value);
252             tr.appendChild(property);
253         } else {
254             // convert transition
255             QDomNamedNodeMap attrs = tr.attributes();
256             for (unsigned int j = 0; j < attrs.count(); j++) {
257                 QString attrName = attrs.item(j).nodeName();
258                 if (attrName != "in" && attrName != "out" && attrName != "id") {
259                     QDomElement property = m_document.createElement("property");
260                     property.setAttribute("name", attrName);
261                     QDomText value = m_document.createTextNode(attrs.item(j).nodeValue());
262                     property.appendChild(value);
263                     tr.appendChild(property);
264                 }
265             }
266         }
267     }
268
269     // move transitions after tracks
270     for (int i = 0; i < max; i++) {
271         tractor.insertAfter(transitions.at(0), QDomNode());
272     }
273
274     QDomElement markers = m_document.createElement("markers");
275
276     // change producer names
277     QDomNodeList producers = m_document.elementsByTagName("producer");
278     max = producers.count();
279     for (int i = 0; i < max; i++) {
280         QDomElement prod = producers.at(0).toElement();
281         QDomNode m = prod.firstChild();
282         if (!m.isNull() && m.toElement().tagName() == "markers") {
283             QDomNodeList prodchilds = m.childNodes();
284             int maxchild = prodchilds.count();
285             for (int k = 0; k < maxchild; k++) {
286                 QDomElement mark = prodchilds.at(0).toElement();
287                 mark.setAttribute("id", prod.attribute("id"));
288                 markers.insertAfter(mark, QDomNode());
289             }
290             prod.removeChild(m);
291         }
292         int duration = prod.attribute("duration").toInt();
293         if (duration > 0) prod.setAttribute("out", QString::number(duration));
294         westley.insertBefore(prod, QDomNode());
295     }
296
297     QDomNode westley0 = m_document.elementsByTagName("westley").at(0);
298     if (!markers.firstChild().isNull()) westley0.appendChild(markers);
299     westley0.removeChild(kdenlivedoc);
300
301     QDomNodeList elements = westley.childNodes();
302     max = elements.count();
303     for (int i = 0; i < max; i++) {
304         QDomElement prod = elements.at(0).toElement();
305         westley0.insertAfter(prod, QDomNode());
306     }
307
308     westley0.removeChild(westley);
309
310     //kDebug() << "/////////////////  CONVERTED DOC:";
311     //kDebug() << m_document.toString();
312     //kDebug() << "/////////////////  END CONVERTED DOC:";
313 }
314
315 QDomElement KdenliveDoc::documentInfoXml() {
316     QDomDocument doc;
317     QDomElement e;
318     QDomElement addedXml = doc.createElement("kdenlivedoc");
319     QDomElement markers = doc.createElement("markers");
320     addedXml.setAttribute("version", "0.7");
321     addedXml.setAttribute("profile", profilePath());
322     addedXml.setAttribute("position", m_render->seekPosition().frames(m_fps));
323     QList <DocClipBase*> list = m_clipManager->documentClipList();
324     for (int i = 0; i < list.count(); i++) {
325         e = list.at(i)->toXML();
326         e.setTagName("kdenlive_producer");
327         addedXml.appendChild(doc.importNode(e, true));
328         QList < CommentedTime > marks = list.at(i)->commentedSnapMarkers();
329         for (int j = 0; j < marks.count(); j++) {
330             QDomElement marker = doc.createElement("marker");
331             marker.setAttribute("time", marks.at(j).time().ms() / 1000);
332             marker.setAttribute("comment", marks.at(j).comment());
333             marker.setAttribute("id", e.attribute("id"));
334             markers.appendChild(marker);
335         }
336     }
337     addedXml.appendChild(markers);
338     //kDebug() << m_document.toString();
339     return addedXml;
340 }
341
342
343 ClipManager *KdenliveDoc::clipManager() {
344     return m_clipManager;
345 }
346
347 KUrl KdenliveDoc::projectFolder() const {
348     if (m_projectFolder.isEmpty()) return KUrl(KStandardDirs::locateLocal("appdata", "/projects/"));
349     return m_projectFolder;
350 }
351
352 QString KdenliveDoc::getDocumentStandard() {
353     //WARNING: this way to tell the video standard is a bit hackish...
354     if (m_profile.description.contains("pal", Qt::CaseInsensitive) || m_profile.description.contains("25", Qt::CaseInsensitive) || m_profile.description.contains("50", Qt::CaseInsensitive)) return "PAL";
355     return "NTSC";
356 }
357
358 QString KdenliveDoc::profilePath() const {
359     return m_profile.path;
360 }
361
362 void KdenliveDoc::setProfilePath(QString path) {
363     KdenliveSettings::setCurrent_profile(path);
364     m_profile = ProfilesDialog::getVideoProfile(path);
365     m_fps = (double) m_profile.frame_rate_num / m_profile.frame_rate_den;
366     m_width = m_profile.width;
367     m_height = m_profile.height;
368     if (m_fps == 30000.0 / 1001.0) m_timecode.setFormat(30, true);
369     else m_timecode.setFormat((int) m_fps);
370 }
371
372 void KdenliveDoc::setThumbsProgress(const QString &message, int progress) {
373     emit progressInfo(message, progress);
374 }
375
376 void KdenliveDoc::loadingProgressed() {
377     m_documentLoadingProgress += m_documentLoadingStep;
378     emit progressInfo(QString(), (int) m_documentLoadingProgress);
379 }
380
381 KUndoStack *KdenliveDoc::commandStack() {
382     return m_commandStack;
383 }
384
385 void KdenliveDoc::setRenderer(Render *render) {
386     m_render = render;
387     emit progressInfo(i18n("Loading playlist..."), 0);
388     qApp->processEvents();
389     if (m_render) m_render->setSceneList(m_scenelist, m_startPos);
390     emit progressInfo(QString(), -1);
391 }
392
393 Render *KdenliveDoc::renderer() {
394     return m_render;
395 }
396
397 void KdenliveDoc::updateClip(int id) {
398     emit updateClipDisplay(id);
399 }
400
401 int KdenliveDoc::getFramePos(QString duration) {
402     return m_timecode.getFrameCount(duration, m_fps);
403 }
404
405 QString KdenliveDoc::producerName(int id) {
406     QString result = "unnamed";
407     QDomNodeList prods = producersList();
408     int ct = prods.count();
409     for (int i = 0; i <  ct ; i++) {
410         QDomElement e = prods.item(i).toElement();
411         if (e.attribute("id") != "black" && e.attribute("id").toInt() == id) {
412             result = e.attribute("name");
413             if (result.isEmpty()) result = KUrl(e.attribute("resource")).fileName();
414             break;
415         }
416     }
417     return result;
418 }
419
420 void KdenliveDoc::setProducerDuration(int id, int duration) {
421     QDomNodeList prods = producersList();
422     int ct = prods.count();
423     for (int i = 0; i <  ct ; i++) {
424         QDomElement e = prods.item(i).toElement();
425         if (e.attribute("id") != "black" && e.attribute("id").toInt() == id) {
426             e.setAttribute("duration", QString::number(duration));
427             break;
428         }
429     }
430 }
431
432 int KdenliveDoc::getProducerDuration(int id) {
433     int result = 0;
434     QDomNodeList prods = producersList();
435     int ct = prods.count();
436     for (int i = 0; i <  ct ; i++) {
437         QDomElement e = prods.item(i).toElement();
438         if (e.attribute("id") != "black" && e.attribute("id").toInt() == id) {
439             result = e.attribute("duration").toInt();
440             break;
441         }
442     }
443     return result;
444 }
445
446
447 QDomDocument KdenliveDoc::generateSceneList() {
448     QDomDocument doc;
449     QDomElement westley = doc.createElement("westley");
450     doc.appendChild(westley);
451     QDomElement prod = doc.createElement("producer");
452 }
453
454 QDomDocument KdenliveDoc::toXml() const {
455     return m_document;
456 }
457
458 Timecode KdenliveDoc::timecode() const {
459     return m_timecode;
460 }
461
462 QDomNodeList KdenliveDoc::producersList() {
463     return m_document.elementsByTagName("producer");
464 }
465
466 void KdenliveDoc::backupMltPlaylist() {
467     if (m_render) m_scenelist = m_render->sceneList();
468 }
469
470 double KdenliveDoc::fps() const {
471     return m_fps;
472 }
473
474 int KdenliveDoc::width() const {
475     return m_width;
476 }
477
478 int KdenliveDoc::height() const {
479     return m_height;
480 }
481
482 KUrl KdenliveDoc::url() const {
483     return m_url;
484 }
485
486 void KdenliveDoc::setUrl(KUrl url) {
487     m_url = url;
488 }
489
490 void KdenliveDoc::setModified(bool mod) {
491     if (mod == m_modified) return;
492     m_modified = mod;
493     emit docModified(m_modified);
494 }
495
496 bool KdenliveDoc::isModified() const {
497     return m_modified;
498 }
499
500 QString KdenliveDoc::description() const {
501     if (m_url.isEmpty())
502         return i18n("Untitled") + " / " + m_profile.description;
503     else
504         return m_url.fileName() + " / " + m_profile.description;
505 }
506
507 void KdenliveDoc::addClip(const QDomElement &elem, const int clipId) {
508     DocClipBase *clip = new DocClipBase(m_clipManager, elem, clipId);
509     kDebug() << "/////////  DOCUM, CREATING NEW CLIP, ID:" << clipId << ", PAR ID:" << elem.attribute("groupid");
510     m_clipManager->addClip(clip);
511     emit addProjectClip(clip);
512 }
513
514 void KdenliveDoc::addFolder(const QString foldername, int clipId, bool edit) {
515     emit addProjectFolder(foldername, clipId, false, edit);
516 }
517
518 void KdenliveDoc::deleteFolder(const QString foldername, int clipId) {
519     emit addProjectFolder(foldername, clipId, true);
520 }
521
522 void KdenliveDoc::deleteProjectClip(QList <int> ids) {
523     for (int i = 0; i < ids.size(); ++i) {
524         emit deletTimelineClip(ids.at(i));
525         m_clipManager->slotDeleteClip(ids.at(i));
526     }
527     setModified(true);
528 }
529
530 void KdenliveDoc::deleteProjectFolder(QMap <QString, int> map) {
531     QMapIterator<QString, int> i(map);
532     while (i.hasNext()) {
533         i.next();
534         slotDeleteFolder(i.key(), i.value());
535     }
536     setModified(true);
537 }
538
539 void KdenliveDoc::deleteClip(const uint clipId) {
540     emit signalDeleteProjectClip(clipId);
541     m_clipManager->deleteClip(clipId);
542 }
543
544 void KdenliveDoc::slotAddClipFile(const KUrl url, const QString group, const int groupId) {
545     kDebug() << "/////////  DOCUM, ADD CLP: " << url;
546     m_clipManager->slotAddClipFile(url, group, groupId);
547     setModified(true);
548 }
549
550 void KdenliveDoc::slotAddTextClipFile(const QString path, const QString group, const int groupId) {
551     kDebug() << "/////////  DOCUM, ADD TXT CLP: " << path;
552     m_clipManager->slotAddTextClipFile(path, group, groupId);
553     setModified(true);
554 }
555
556 void KdenliveDoc::slotAddFolder(const QString folderName) {
557     AddFolderCommand *command = new AddFolderCommand(this, folderName, m_clipManager->getFreeClipId(), true);
558     commandStack()->push(command);
559     setModified(true);
560 }
561
562 void KdenliveDoc::slotDeleteFolder(const QString folderName, const int id) {
563     AddFolderCommand *command = new AddFolderCommand(this, folderName, id, false);
564     commandStack()->push(command);
565     setModified(true);
566 }
567
568 void KdenliveDoc::slotEditFolder(const QString newfolderName, const QString oldfolderName, int clipId) {
569     EditFolderCommand *command = new EditFolderCommand(this, newfolderName, oldfolderName, clipId, false);
570     commandStack()->push(command);
571     setModified(true);
572 }
573
574 int KdenliveDoc::getFreeClipId() {
575     return m_clipManager->getFreeClipId();
576 }
577
578 DocClipBase *KdenliveDoc::getBaseClip(int clipId) {
579     return m_clipManager->getClipById(clipId);
580 }
581
582 void KdenliveDoc::slotAddColorClipFile(const QString name, const QString color, QString duration, const QString group, const int groupId) {
583     m_clipManager->slotAddColorClipFile(name, color, duration, group, groupId);
584     setModified(true);
585 }
586
587 void KdenliveDoc::slotAddSlideshowClipFile(const QString name, const QString path, int count, const QString duration, bool loop, const QString group, const int groupId) {
588     m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop, group, groupId);
589     setModified(true);
590 }
591
592 void KdenliveDoc::slotCreateTextClip(QString group, int groupId) {
593     QString titlesFolder = projectFolder().path() + "/titles/";
594     KStandardDirs::makeDir(titlesFolder);
595     TitleWidget *dia_ui = new TitleWidget(KUrl(), titlesFolder, m_render, kapp->activeWindow());
596     if (dia_ui->exec() == QDialog::Accepted) {
597         QString titleName = "title";
598         int counter = 0;
599         QString path = titlesFolder + titleName + QString::number(counter).rightJustified(3, '0', false);
600         while (QFile::exists(path + ".kdenlivetitle")) {
601             counter++;
602             path = titlesFolder + titleName + QString::number(counter).rightJustified(3, '0', false);
603         }
604         QPixmap pix = dia_ui->renderedPixmap();
605         pix.save(path + ".png");
606         dia_ui->saveTitle(path + ".kdenlivetitle");
607         slotAddTextClipFile(path, QString(), -1);
608     }
609     delete dia_ui;
610 }
611
612 void KdenliveDoc::editTextClip(QString path, int id) {
613     TitleWidget *dia_ui = new TitleWidget(KUrl(path + ".kdenlivetitle"), path, m_render, kapp->activeWindow());
614     if (dia_ui->exec() == QDialog::Accepted) {
615         QPixmap pix = dia_ui->renderedPixmap();
616         pix.save(path + ".png");
617         dia_ui->saveTitle(path + ".kdenlivetitle");
618         //slotAddClipFile(KUrl("/tmp/kdenlivetitle.png"), QString(), -1);
619         emit refreshClipThumbnail(id);
620     }
621     delete dia_ui;
622 }
623
624
625 #include "kdenlivedoc.moc"
626