]> git.sesse.net Git - kdenlive/blob - src/documentconvert.cpp
Update to the new MLT structure (based on patch by Dan Dennedy)
[kdenlive] / src / documentconvert.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
21 #include "documentconvert.h"
22 #include "definitions.h"
23
24 #include <KDebug>
25 #include <KMessageBox>
26 #include <KApplication>
27 #include <KLocale>
28
29 #include <QColor>
30
31 DocumentConvert::DocumentConvert(QDomDocument doc):
32         m_doc(doc),
33         m_modified(false)
34 {}
35
36
37 bool DocumentConvert::doConvert(double version, const double current_version)
38 {
39     kDebug() << "Opening a document with version " << version;
40
41     if (version == current_version) return true;
42
43     if (version > current_version) {
44         kDebug() << "Unable to open document with version " << version;
45         KMessageBox::sorry(kapp->activeWindow(), i18n("This project type is unsupported (version %1) and can't be loaded.\nPlease consider upgrading you Kdenlive version.", version), i18n("Unable to open project"));
46         return false;
47     }
48
49     // Opening a old Kdenlive document
50     if (version == 0.5 || version == 0.7) {
51         KMessageBox::sorry(kapp->activeWindow(), i18n("This project type is unsupported (version %1) and can't be loaded.", version), i18n("Unable to open project"));
52         kDebug() << "Unable to open document with version " << version;
53         // TODO: convert 0.7 (0.5?) files to the new document format.
54         return false;
55     }
56
57     m_modified = true;
58
59     if (version == 0.82) {
60         convertToMelt();
61         return true;
62     }
63
64     if (version == 0.81) {
65         // Add correct tracks info
66         QDomNode kdenlivedoc = m_doc.elementsByTagName("kdenlivedoc").at(0);
67         QDomElement infoXml = kdenlivedoc.toElement();
68         infoXml.setAttribute("version", current_version);
69         QString currentTrackOrder = infoXml.attribute("tracks");
70         QDomElement tracksinfo = m_doc.createElement("tracksinfo");
71         for (int i = 0; i < currentTrackOrder.size(); i++) {
72             QDomElement trackinfo = m_doc.createElement("trackinfo");
73             if (currentTrackOrder.data()[i] == 'a') {
74                 trackinfo.setAttribute("type", "audio");
75                 trackinfo.setAttribute("blind", true);
76             } else trackinfo.setAttribute("blind", false);
77             trackinfo.setAttribute("mute", false);
78             trackinfo.setAttribute("locked", false);
79             tracksinfo.appendChild(trackinfo);
80         }
81         infoXml.appendChild(tracksinfo);
82         convertToMelt();
83         return true;
84     }
85
86     if (version == 0.8) {
87         // Add the tracks information
88         QDomNodeList tracks = m_doc.elementsByTagName("track");
89         int max = tracks.count();
90
91         QDomNode kdenlivedoc = m_doc.elementsByTagName("kdenlivedoc").at(0);
92         QDomElement infoXml = kdenlivedoc.toElement();
93         infoXml.setAttribute("version", current_version);
94         QDomElement tracksinfo = m_doc.createElement("tracksinfo");
95
96         for (int i = 0; i < max; i++) {
97             QDomElement trackinfo = m_doc.createElement("trackinfo");
98             QDomElement t = tracks.at(i).toElement();
99             if (t.attribute("hide") == "video") {
100                 trackinfo.setAttribute("type", "audio");
101                 trackinfo.setAttribute("blind", true);
102             } else trackinfo.setAttribute("blind", false);
103             trackinfo.setAttribute("mute", false);
104             trackinfo.setAttribute("locked", false);
105             if (t.attribute("producer") != "black_track") tracksinfo.appendChild(trackinfo);
106         }
107         infoXml.appendChild(tracksinfo);
108         convertToMelt();
109         return true;
110     }
111
112     QDomNode westley = m_doc.elementsByTagName("westley").at(1);
113     QDomNode tractor = m_doc.elementsByTagName("tractor").at(0);
114     QDomNode kdenlivedoc = m_doc.elementsByTagName("kdenlivedoc").at(0);
115     QDomElement kdenlivedoc_old = kdenlivedoc.cloneNode(true).toElement(); // Needed for folders
116     QDomElement infoXml = kdenlivedoc.toElement();
117     infoXml.setAttribute("version", current_version);
118     QDomNode multitrack = m_doc.elementsByTagName("multitrack").at(0);
119     QDomNodeList playlists = m_doc.elementsByTagName("playlist");
120
121     QDomNode props = m_doc.elementsByTagName("properties").at(0).toElement();
122     QString profile = props.toElement().attribute("videoprofile");
123     int startPos = props.toElement().attribute("timeline_position").toInt();
124     infoXml.setAttribute("position", startPos);
125     if (profile == "dv_wide") profile = "dv_pal_wide";
126
127     // move playlists outside of tractor and add the tracks instead
128     int max = playlists.count();
129     if (westley.isNull())
130         westley = m_doc.elementsByTagName("westley").at(1);
131     if (westley.isNull()) {
132         westley = m_doc.createElement("mlt");
133         m_doc.documentElement().appendChild(westley);
134     }
135     if (tractor.isNull()) {
136         kDebug() << "// NO MLT PLAYLIST, building empty one";
137         QDomElement blank_tractor = m_doc.createElement("tractor");
138         westley.appendChild(blank_tractor);
139         QDomElement blank_playlist = m_doc.createElement("playlist");
140         blank_playlist.setAttribute("id", "black_track");
141         westley.insertBefore(blank_playlist, QDomNode());
142         QDomElement blank_track = m_doc.createElement("track");
143         blank_track.setAttribute("producer", "black_track");
144         blank_tractor.appendChild(blank_track);
145
146         QDomNodeList kdenlivetracks = m_doc.elementsByTagName("kdenlivetrack");
147         for (int i = 0; i < kdenlivetracks.count(); i++) {
148             blank_playlist = m_doc.createElement("playlist");
149             blank_playlist.setAttribute("id", "playlist" + QString::number(i));
150             westley.insertBefore(blank_playlist, QDomNode());
151             blank_track = m_doc.createElement("track");
152             blank_track.setAttribute("producer", "playlist" + QString::number(i));
153             blank_tractor.appendChild(blank_track);
154             if (kdenlivetracks.at(i).toElement().attribute("cliptype") == "Sound") {
155                 blank_playlist.setAttribute("hide", "video");
156                 blank_track.setAttribute("hide", "video");
157             }
158         }
159     } else for (int i = 0; i < max; i++) {
160             QDomNode n = playlists.at(i);
161             westley.insertBefore(n, QDomNode());
162             QDomElement pl = n.toElement();
163             QDomElement track = m_doc.createElement("track");
164             QString trackType = pl.attribute("hide");
165             if (!trackType.isEmpty())
166                 track.setAttribute("hide", trackType);
167             QString playlist_id =  pl.attribute("id");
168             if (playlist_id.isEmpty()) {
169                 playlist_id = "black_track";
170                 pl.setAttribute("id", playlist_id);
171             }
172             track.setAttribute("producer", playlist_id);
173             //tractor.appendChild(track);
174 #define KEEP_TRACK_ORDER 1
175 #ifdef KEEP_TRACK_ORDER
176             tractor.insertAfter(track, QDomNode());
177 #else
178             // Insert the new track in an order that hopefully matches the 3 video, then 2 audio tracks of Kdenlive 0.7.0
179             // insertion sort - O( tracks*tracks )
180             // Note, this breaks _all_ transitions - but you can move them up and down afterwards.
181             QDomElement tractor_elem = tractor.toElement();
182             if (! tractor_elem.isNull()) {
183                 QDomNodeList tracks = tractor_elem.elementsByTagName("track");
184                 int size = tracks.size();
185                 if (size == 0) {
186                     tractor.insertAfter(track, QDomNode());
187                 } else {
188                     bool inserted = false;
189                     for (int i = 0; i < size; ++i) {
190                         QDomElement track_elem = tracks.at(i).toElement();
191                         if (track_elem.isNull()) {
192                             tractor.insertAfter(track, QDomNode());
193                             inserted = true;
194                             break;
195                         } else {
196                             kDebug() << "playlist_id: " << playlist_id << " producer:" << track_elem.attribute("producer");
197                             if (playlist_id < track_elem.attribute("producer")) {
198                                 tractor.insertBefore(track, track_elem);
199                                 inserted = true;
200                                 break;
201                             }
202                         }
203                     }
204                     // Reach here, no insertion, insert last
205                     if (!inserted) {
206                         tractor.insertAfter(track, QDomNode());
207                     }
208                 }
209             } else {
210                 kWarning() << "tractor was not a QDomElement";
211                 tractor.insertAfter(track, QDomNode());
212             }
213 #endif
214         }
215     tractor.removeChild(multitrack);
216
217     // audio track mixing transitions should not be added to track view, so add required attribute
218     QDomNodeList transitions = m_doc.elementsByTagName("transition");
219     max = transitions.count();
220     for (int i = 0; i < max; i++) {
221         QDomElement tr = transitions.at(i).toElement();
222         if (tr.attribute("combine") == "1" && tr.attribute("mlt_service") == "mix") {
223             QDomElement property = m_doc.createElement("property");
224             property.setAttribute("name", "internal_added");
225             QDomText value = m_doc.createTextNode("237");
226             property.appendChild(value);
227             tr.appendChild(property);
228             property = m_doc.createElement("property");
229             property.setAttribute("name", "mlt_service");
230             value = m_doc.createTextNode("mix");
231             property.appendChild(value);
232             tr.appendChild(property);
233         } else {
234             // convert transition
235             QDomNamedNodeMap attrs = tr.attributes();
236             for (int j = 0; j < attrs.count(); j++) {
237                 QString attrName = attrs.item(j).nodeName();
238                 if (attrName != "in" && attrName != "out" && attrName != "id") {
239                     QDomElement property = m_doc.createElement("property");
240                     property.setAttribute("name", attrName);
241                     QDomText value = m_doc.createTextNode(attrs.item(j).nodeValue());
242                     property.appendChild(value);
243                     tr.appendChild(property);
244                 }
245             }
246         }
247     }
248
249     // move transitions after tracks
250     for (int i = 0; i < max; i++) {
251         tractor.insertAfter(transitions.at(0), QDomNode());
252     }
253
254     // Fix filters format
255     QDomNodeList entries = m_doc.elementsByTagName("entry");
256     max = entries.count();
257     for (int i = 0; i < max; i++) {
258         QString last_id;
259         int effectix = 0;
260         QDomNode m = entries.at(i).firstChild();
261         while (!m.isNull()) {
262             if (m.toElement().tagName() == "filter") {
263                 QDomElement filt = m.toElement();
264                 QDomNamedNodeMap attrs = filt.attributes();
265                 QString current_id = filt.attribute("kdenlive_id");
266                 if (current_id != last_id) {
267                     effectix++;
268                     last_id = current_id;
269                 }
270                 QDomElement e = m_doc.createElement("property");
271                 e.setAttribute("name", "kdenlive_ix");
272                 QDomText value = m_doc.createTextNode(QString::number(effectix));
273                 e.appendChild(value);
274                 filt.appendChild(e);
275                 for (int j = 0; j < attrs.count(); j++) {
276                     QDomAttr a = attrs.item(j).toAttr();
277                     if (!a.isNull()) {
278                         kDebug() << " FILTER; adding :" << a.name() << ":" << a.value();
279                         QDomElement e = m_doc.createElement("property");
280                         e.setAttribute("name", a.name());
281                         QDomText value = m_doc.createTextNode(a.value());
282                         e.appendChild(value);
283                         filt.appendChild(e);
284
285                     }
286                 }
287             }
288             m = m.nextSibling();
289         }
290     }
291
292     /*
293         QDomNodeList filters = m_doc.elementsByTagName("filter");
294         max = filters.count();
295         QString last_id;
296         int effectix = 0;
297         for (int i = 0; i < max; i++) {
298             QDomElement filt = filters.at(i).toElement();
299             QDomNamedNodeMap attrs = filt.attributes();
300      QString current_id = filt.attribute("kdenlive_id");
301      if (current_id != last_id) {
302          effectix++;
303          last_id = current_id;
304      }
305      QDomElement e = m_doc.createElement("property");
306             e.setAttribute("name", "kdenlive_ix");
307             QDomText value = m_doc.createTextNode(QString::number(1));
308             e.appendChild(value);
309             filt.appendChild(e);
310             for (int j = 0; j < attrs.count(); j++) {
311                 QDomAttr a = attrs.item(j).toAttr();
312                 if (!a.isNull()) {
313                     kDebug() << " FILTER; adding :" << a.name() << ":" << a.value();
314                     QDomElement e = m_doc.createElement("property");
315                     e.setAttribute("name", a.name());
316                     QDomText value = m_doc.createTextNode(a.value());
317                     e.appendChild(value);
318                     filt.appendChild(e);
319                 }
320             }
321         }*/
322
323     // fix slowmotion
324     QDomNodeList producers = westley.toElement().elementsByTagName("producer");
325     max = producers.count();
326     for (int i = 0; i < max; i++) {
327         QDomElement prod = producers.at(i).toElement();
328         if (prod.attribute("mlt_service") == "framebuffer") {
329             QString slowmotionprod = prod.attribute("resource");
330             slowmotionprod.replace(':', '?');
331             kDebug() << "// FOUND WRONG SLOWMO, new: " << slowmotionprod;
332             prod.setAttribute("resource", slowmotionprod);
333         }
334     }
335     // move producers to correct place, markers to a global list, fix clip descriptions
336     QDomElement markers = m_doc.createElement("markers");
337     // This will get the xml producers:
338     producers = m_doc.elementsByTagName("producer");
339     max = producers.count();
340     for (int i = 0; i < max; i++) {
341         QDomElement prod = producers.at(0).toElement();
342         // add resource also as a property (to allow path correction in setNewResource())
343         // TODO: will it work with slowmotion? needs testing
344         /*if (!prod.attribute("resource").isEmpty()) {
345             QDomElement prop_resource = m_doc.createElement("property");
346             prop_resource.setAttribute("name", "resource");
347             QDomText resource = m_doc.createTextNode(prod.attribute("resource"));
348             prop_resource.appendChild(resource);
349             prod.appendChild(prop_resource);
350         }*/
351         QDomNode m = prod.firstChild();
352         if (!m.isNull()) {
353             if (m.toElement().tagName() == "markers") {
354                 QDomNodeList prodchilds = m.childNodes();
355                 int maxchild = prodchilds.count();
356                 for (int k = 0; k < maxchild; k++) {
357                     QDomElement mark = prodchilds.at(0).toElement();
358                     mark.setAttribute("id", prod.attribute("id"));
359                     markers.insertAfter(mark, QDomNode());
360                 }
361                 prod.removeChild(m);
362             } else if (prod.attribute("type").toInt() == TEXT) {
363                 // convert title clip
364                 if (m.toElement().tagName() == "textclip") {
365                     QDomDocument tdoc;
366                     QDomElement titleclip = m.toElement();
367                     QDomElement title = tdoc.createElement("kdenlivetitle");
368                     tdoc.appendChild(title);
369                     QDomNodeList objects = titleclip.childNodes();
370                     int maxchild = objects.count();
371                     for (int k = 0; k < maxchild; k++) {
372                         QString objectxml;
373                         QDomElement ob = objects.at(k).toElement();
374                         if (ob.attribute("type") == "3") {
375                             // text object - all of this goes into "xmldata"...
376                             QDomElement item = tdoc.createElement("item");
377                             item.setAttribute("z-index", ob.attribute("z"));
378                             item.setAttribute("type", "QGraphicsTextItem");
379                             QDomElement position = tdoc.createElement("position");
380                             position.setAttribute("x", ob.attribute("x"));
381                             position.setAttribute("y", ob.attribute("y"));
382                             QDomElement content = tdoc.createElement("content");
383                             content.setAttribute("font", ob.attribute("font_family"));
384                             content.setAttribute("font-size", ob.attribute("font_size"));
385                             content.setAttribute("font-bold", ob.attribute("bold"));
386                             content.setAttribute("font-italic", ob.attribute("italic"));
387                             content.setAttribute("font-underline", ob.attribute("underline"));
388                             QString col = ob.attribute("color");
389                             QColor c(col);
390                             content.setAttribute("font-color", colorToString(c));
391                             // todo: These fields are missing from the newly generated xmldata:
392                             // transform, startviewport, endviewport, background
393
394                             QDomText conttxt = tdoc.createTextNode(ob.attribute("text"));
395                             content.appendChild(conttxt);
396                             item.appendChild(position);
397                             item.appendChild(content);
398                             title.appendChild(item);
399                         } else if (ob.attribute("type") == "5") {
400                             // rectangle object
401                             QDomElement item = tdoc.createElement("item");
402                             item.setAttribute("z-index", ob.attribute("z"));
403                             item.setAttribute("type", "QGraphicsRectItem");
404                             QDomElement position = tdoc.createElement("position");
405                             position.setAttribute("x", ob.attribute("x"));
406                             position.setAttribute("y", ob.attribute("y"));
407                             QDomElement content = tdoc.createElement("content");
408                             QString col = ob.attribute("color");
409                             QColor c(col);
410                             content.setAttribute("brushcolor", colorToString(c));
411                             QString rect = "0,0,";
412                             rect.append(ob.attribute("width"));
413                             rect.append(",");
414                             rect.append(ob.attribute("height"));
415                             content.setAttribute("rect", rect);
416                             item.appendChild(position);
417                             item.appendChild(content);
418                             title.appendChild(item);
419                         }
420                     }
421                     prod.setAttribute("xmldata", tdoc.toString());
422                     // mbd todo: This clearly does not work, as every title gets the same name - trying to leave it empty
423                     // QStringList titleInfo = TitleWidget::getFreeTitleInfo(projectFolder());
424                     // prod.setAttribute("titlename", titleInfo.at(0));
425                     // prod.setAttribute("resource", titleInfo.at(1));
426                     //kDebug()<<"TITLE DATA:\n"<<tdoc.toString();
427                     prod.removeChild(m);
428                 } // End conversion of title clips.
429
430             } else if (m.isText()) {
431                 QString comment = m.nodeValue();
432                 if (!comment.isEmpty()) {
433                     prod.setAttribute("description", comment);
434                 }
435                 prod.removeChild(m);
436             }
437         }
438         int duration = prod.attribute("duration").toInt();
439         if (duration > 0) prod.setAttribute("out", QString::number(duration));
440         // The clip goes back in, but text clips should not go back in, at least not modified
441         westley.insertBefore(prod, QDomNode());
442
443     }
444
445     QDomNode westley0 = m_doc.elementsByTagName("westley").at(0);
446     if (!markers.firstChild().isNull()) westley0.appendChild(markers);
447
448
449     // Convert as much of the kdenlivedoc as possible. Use the producer in westley
450     // First, remove the old stuff from westley, and add a new empty one
451     // Also, track the max id in order to use it for the adding of groups/folders
452     int max_kproducer_id = 0;
453     westley0.removeChild(kdenlivedoc);
454     QDomElement kdenlivedoc_new = m_doc.createElement("kdenlivedoc");
455     kdenlivedoc_new.setAttribute("profile", profile);
456
457     // Add tracks info
458     QDomNodeList tracks = m_doc.elementsByTagName("track");
459     max = tracks.count();
460     QDomElement tracksinfo = m_doc.createElement("tracksinfo");
461     for (int i = 0; i < max; i++) {
462         QDomElement trackinfo = m_doc.createElement("trackinfo");
463         QDomElement t = tracks.at(i).toElement();
464         if (t.attribute("hide") == "video") {
465             trackinfo.setAttribute("type", "audio");
466             trackinfo.setAttribute("blind", true);
467         } else trackinfo.setAttribute("blind", false);
468         trackinfo.setAttribute("mute", false);
469         trackinfo.setAttribute("locked", false);
470         if (t.attribute("producer") != "black_track") tracksinfo.appendChild(trackinfo);
471     }
472     kdenlivedoc_new.appendChild(tracksinfo);
473
474     // Add all the producers that has a resource in westley
475     QDomElement westley_element = westley0.toElement();
476     if (westley_element.isNull()) {
477         kWarning() << "westley0 element in document was not a QDomElement - unable to add producers to new kdenlivedoc";
478     } else {
479         QDomNodeList wproducers = westley_element.elementsByTagName("producer");
480         int kmax = wproducers.count();
481         for (int i = 0; i < kmax; i++) {
482             QDomElement wproducer = wproducers.at(i).toElement();
483             if (wproducer.isNull()) {
484                 kWarning() << "Found producer in westley0, that was not a QDomElement";
485                 continue;
486             }
487             if (wproducer.attribute("id") == "black") continue;
488             // We have to do slightly different things, depending on the type
489             kDebug() << "Converting producer element with type" << wproducer.attribute("type");
490             if (wproducer.attribute("type").toInt() == TEXT) {
491                 kDebug() << "Found TEXT element in producer" << endl;
492                 QDomElement kproducer = wproducer.cloneNode(true).toElement();
493                 kproducer.setTagName("kdenlive_producer");
494                 kdenlivedoc_new.appendChild(kproducer);
495                 // TODO: Perhaps needs some more changes here to "frequency", aspect ratio as a float, frame_size, channels, and later, ressource and title name
496             } else {
497                 QDomElement kproducer = m_doc.createElement("kdenlive_producer");
498                 kproducer.setAttribute("id", wproducer.attribute("id"));
499                 if (!wproducer.attribute("description").isEmpty())
500                     kproducer.setAttribute("description", wproducer.attribute("description"));
501                 kproducer.setAttribute("resource", wproducer.attribute("resource"));
502                 kproducer.setAttribute("type", wproducer.attribute("type"));
503                 // Testing fix for 358
504                 if (!wproducer.attribute("aspect_ratio").isEmpty()) {
505                     kproducer.setAttribute("aspect_ratio", wproducer.attribute("aspect_ratio"));
506                 }
507                 if (!wproducer.attribute("source_fps").isEmpty()) {
508                     kproducer.setAttribute("fps", wproducer.attribute("source_fps"));
509                 }
510                 if (!wproducer.attribute("length").isEmpty()) {
511                     kproducer.setAttribute("duration", wproducer.attribute("length"));
512                 }
513                 kdenlivedoc_new.appendChild(kproducer);
514             }
515             if (wproducer.attribute("id").toInt() > max_kproducer_id) {
516                 max_kproducer_id = wproducer.attribute("id").toInt();
517             }
518         }
519     }
520 #define LOOKUP_FOLDER 1
521 #ifdef LOOKUP_FOLDER
522     // Look through all the folder elements of the old doc, for each folder, for each producer,
523     // get the id, look it up in the new doc, set the groupname and groupid
524     // Note, this does not work at the moment - at least one folders shows up missing, and clips with no folder
525     // does not show up.
526     //    QDomElement kdenlivedoc_old = kdenlivedoc.toElement();
527     if (!kdenlivedoc_old.isNull()) {
528         QDomNodeList folders = kdenlivedoc_old.elementsByTagName("folder");
529         int fsize = folders.size();
530         int groupId = max_kproducer_id + 1; // Start at +1 of max id of the kdenlive_producers
531         for (int i = 0; i < fsize; ++i) {
532             QDomElement folder = folders.at(i).toElement();
533             if (!folder.isNull()) {
534                 QString groupName = folder.attribute("name");
535                 kDebug() << "groupName: " << groupName << " with groupId: " << groupId;
536                 QDomNodeList fproducers = folder.elementsByTagName("producer");
537                 int psize = fproducers.size();
538                 for (int j = 0; j < psize; ++j) {
539                     QDomElement fproducer = fproducers.at(j).toElement();
540                     if (!fproducer.isNull()) {
541                         QString id = fproducer.attribute("id");
542                         // This is not very effective, but compared to loading the clips, its a breeze
543                         QDomNodeList kdenlive_producers = kdenlivedoc_new.elementsByTagName("kdenlive_producer");
544                         int kpsize = kdenlive_producers.size();
545                         for (int k = 0; k < kpsize; ++k) {
546                             QDomElement kproducer = kdenlive_producers.at(k).toElement(); // Its an element for sure
547                             if (id == kproducer.attribute("id")) {
548                                 // We do not check that it already is part of a folder
549                                 kproducer.setAttribute("groupid", groupId);
550                                 kproducer.setAttribute("groupname", groupName);
551                                 break;
552                             }
553                         }
554                     }
555                 }
556                 ++groupId;
557             }
558         }
559     }
560 #endif
561     westley0.appendChild(kdenlivedoc_new);
562
563     QDomNodeList elements = westley.childNodes();
564     max = elements.count();
565     for (int i = 0; i < max; i++) {
566         QDomElement prod = elements.at(0).toElement();
567         westley0.insertAfter(prod, QDomNode());
568     }
569
570     westley0.removeChild(westley);
571
572     // experimental and probably slow
573     // adds <avfile /> information to <kdenlive_producer />
574     QDomNodeList kproducers = m_doc.elementsByTagName("kdenlive_producer");
575     QDomNodeList avfiles = kdenlivedoc_old.elementsByTagName("avfile");
576     kDebug() << "found" << avfiles.count() << "<avfile />s and" << kproducers.count() << "<kdenlive_producer />s";
577     for (int i = 0; i < avfiles.count(); ++i) {
578         QDomElement avfile = avfiles.at(i).toElement();
579         QDomElement kproducer;
580         if (avfile.isNull())
581             kWarning() << "found an <avfile /> that is not a QDomElement";
582         else {
583             QString id = avfile.attribute("id");
584             // this is horrible, must be rewritten, it's just for test
585             for (int j = 0; j < kproducers.count(); ++j) {
586                 //kDebug() << "checking <kdenlive_producer /> with id" << kproducers.at(j).toElement().attribute("id");
587                 if (kproducers.at(j).toElement().attribute("id") == id) {
588                     kproducer = kproducers.at(j).toElement();
589                     break;
590                 }
591             }
592             if (kproducer == QDomElement())
593                 kWarning() << "no match for <avfile /> with id =" << id;
594             else {
595                 //kDebug() << "ready to set additional <avfile />'s attributes (id =" << id << ")";
596                 kproducer.setAttribute("channels", avfile.attribute("channels"));
597                 kproducer.setAttribute("duration", avfile.attribute("duration"));
598                 kproducer.setAttribute("frame_size", avfile.attribute("width") + 'x' + avfile.attribute("height"));
599                 kproducer.setAttribute("frequency", avfile.attribute("frequency"));
600                 if (kproducer.attribute("description").isEmpty() && !avfile.attribute("description").isEmpty())
601                     kproducer.setAttribute("description", avfile.attribute("description"));
602             }
603         }
604     }
605
606     /*kDebug() << "/////////////////  CONVERTED DOC:";
607     kDebug() << m_doc.toString();
608     kDebug() << "/////////////////  END CONVERTED DOC:";
609
610     QFile file("converted.kdenlive");
611     if (file.open(QIODevice::WriteOnly)) {
612         QTextStream stream(&file);
613         stream << m_doc.toString().toUtf8();
614         file.close();
615     } else {
616         kDebug() << "Unable to dump file to converted.kdenlive";
617     }*/
618
619     //kDebug() << "/////////////////  END CONVERTED DOC:";
620     convertToMelt();
621     return true;
622 }
623
624 QString DocumentConvert::colorToString(const QColor& c)
625 {
626     QString ret = "%1,%2,%3,%4";
627     ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
628     return ret;
629 }
630
631 bool DocumentConvert::isModified() const
632 {
633     return m_modified;
634 }
635
636 void DocumentConvert::convertToMelt()
637 {
638     QDomNodeList list = m_doc.elementsByTagName("westley");
639     int max = list.count();
640     for (int i = 0; i < max; i++) {
641         QDomElement elem = list.at(i).toElement();
642         elem.setTagName("mlt");
643     }
644 }
645