documentvalidator.cpp 117 KB
Newer Older
Alberto Villa's avatar
Alberto Villa committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
/***************************************************************************
 *   Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org)        *
 *                                                                         *
 *   This program is free software; you can redistribute it and/or modify  *
 *   it under the terms of the GNU General Public License as published by  *
 *   the Free Software Foundation; either version 2 of the License, or     *
 *   (at your option) any later version.                                   *
 *                                                                         *
 *   This program is distributed in the hope that it will be useful,       *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU General Public License for more details.                          *
 *                                                                         *
 *   You should have received a copy of the GNU General Public License     *
 *   along with this program; if not, write to the                         *
 *   Free Software Foundation, Inc.,                                       *
 *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA          *
 ***************************************************************************/

Vincent Pinon's avatar
Vincent Pinon committed
20 21
#include "documentvalidator.h"

Alberto Villa's avatar
Alberto Villa committed
22
#include "definitions.h"
Vincent Pinon's avatar
Vincent Pinon committed
23
#include "effectslist/initeffects.h"
Till Theato's avatar
Till Theato committed
24
#include "mainwindow.h"
25
#include "core.h"
26
#include "mltcontroller/bincontroller.h"
Alberto Villa's avatar
Alberto Villa committed
27

Laurent Montel's avatar
Laurent Montel committed
28
#include "kdenlive_debug.h"
Alberto Villa's avatar
Alberto Villa committed
29
#include <KMessageBox>
30
#include <klocalizedstring.h>
Alberto Villa's avatar
Alberto Villa committed
31

32
#include <QFile>
Alberto Villa's avatar
Alberto Villa committed
33
#include <QColor>
34
#include <QString>
Till Theato's avatar
Till Theato committed
35 36
#include <QDir>
#include <QScriptEngine>
37

38 39
#include <mlt++/Mlt.h>

40
#include <locale>
41 42 43 44
#ifdef Q_OS_MAC
#include <xlocale.h>
#endif

45
#include <QStandardPaths>
46

47
DocumentValidator::DocumentValidator(const QDomDocument &doc, const QUrl &documentUrl):
Laurent Montel's avatar
Laurent Montel committed
48 49 50
    m_doc(doc),
    m_url(documentUrl),
    m_modified(false)
Alberto Villa's avatar
Alberto Villa committed
51 52 53 54
{}

bool DocumentValidator::validate(const double currentVersion)
{
55
    QDomElement mlt = m_doc.firstChildElement(QStringLiteral("mlt"));
56
    // At least the root element must be there
Laurent Montel's avatar
Laurent Montel committed
57
    if (mlt.isNull()) {
Alberto Villa's avatar
Alberto Villa committed
58
        return false;
Laurent Montel's avatar
Laurent Montel committed
59
    }
Alberto Villa's avatar
Alberto Villa committed
60

61 62 63
    QDomElement kdenliveDoc = mlt.firstChildElement(QStringLiteral("kdenlivedoc"));
    QString rootDir = mlt.attribute(QStringLiteral("root"));
    if (rootDir == QLatin1String("$CURRENTPATH")) {
64
        // The document was extracted from a Kdenlive archived project, fix root directory
65
        QString playlist = m_doc.toString();
66
        playlist.replace(QLatin1String("$CURRENTPATH"), m_url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile());
67
        m_doc.setContent(playlist);
68 69
        mlt = m_doc.firstChildElement(QStringLiteral("mlt"));
        kdenliveDoc = mlt.firstChildElement(QStringLiteral("kdenlivedoc"));
70 71
    } else if (rootDir.isEmpty()) {
        mlt.setAttribute(QStringLiteral("root"), m_url.adjusted(QUrl::RemoveFilename | QUrl::StripTrailingSlash).toLocalFile());
72
    }
73 74

    // Previous MLT / Kdenlive versions used C locale by default
75
    QLocale documentLocale = QLocale::c();
76

77
    if (mlt.hasAttribute(QStringLiteral("LC_NUMERIC"))) {
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
        // Check document numeric separator (added in Kdenlive 16.12.1
        QDomElement main_playlist = mlt.firstChildElement(QStringLiteral("playlist"));
        QDomNodeList props = main_playlist.elementsByTagName(QStringLiteral("property"));
        QChar numericalSeparator;
        for (int i = 0; i < props.count(); ++i) {
            QDomNode n = props.at(i);
            if (n.toElement().attribute(QStringLiteral("name")) == QLatin1String("kdenlive:docproperties.decimalPoint")) {
                QString sep = n.firstChild().nodeValue();
                if (!sep.isEmpty()) {
                    numericalSeparator = sep.at(0);
                }
                break;
            }
        }
        bool error = false;
        if (!numericalSeparator.isNull() && numericalSeparator != QLocale().decimalPoint()) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
94
            qCDebug(KDENLIVE_LOG)<<" * ** LOCALE CHANGE REQUIRED: "<<numericalSeparator <<"!="<< QLocale().decimalPoint()<<" / "<<QLocale::system().decimalPoint();
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
            // Change locale to match document
            QString requestedLocale = mlt.attribute(QStringLiteral("LC_NUMERIC"));
            documentLocale = QLocale(requestedLocale);
#ifdef Q_OS_WIN
            // Most locales don't work on windows, so use C whenever possible
            if (numericalSeparator == QLatin1Char('.')) {
#else
            if (numericalSeparator != documentLocale.decimalPoint() && numericalSeparator == QLatin1Char('.')) {
#endif
                requestedLocale = QStringLiteral("C");
                documentLocale = QLocale::c();
            }
#ifdef Q_OS_MAC
            setlocale(LC_NUMERIC_MASK, requestedLocale.toUtf8().constData());
#elifdef Q_OS_WIN
            std::locale::global(std::locale(requestedLocale.toUtf8().constData()));
#else
            setlocale(LC_NUMERIC, requestedLocale.toUtf8().constData());
#endif
            if (numericalSeparator != documentLocale.decimalPoint()) {
                // Parse installed locales to find one matching
                const QList<QLocale> list = QLocale::matchingLocales(QLocale::AnyLanguage, QLocale().script(), QLocale::AnyCountry);
                QLocale matching;
118
                for (const QLocale &loc : list) {
119 120
                    if (loc.decimalPoint() == numericalSeparator) {
                        matching = loc;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
121
                        qCDebug(KDENLIVE_LOG)<<"Warning, document locale: "<<mlt.attribute(QStringLiteral("LC_NUMERIC"))<<" is not available, using: "<<loc.name();
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
122
#ifndef Q_OS_MAC
123
                        setlocale(LC_NUMERIC, loc.name().toUtf8().constData());
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
124
#else
125
                        setlocale(LC_NUMERIC_MASK, loc.name().toUtf8().constData());
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
126
#endif
127 128 129 130 131 132 133 134
                        documentLocale = matching;
                        break;
                    }
                }
                error = numericalSeparator != documentLocale.decimalPoint();
            }
        } else if (numericalSeparator.isNull()) {
            // Change locale to match document
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
135
#ifndef Q_OS_MAC
136
            const QString newloc = QString::fromLatin1(setlocale(LC_NUMERIC, mlt.attribute(QStringLiteral("LC_NUMERIC")).toUtf8().constData()));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
137
#else
138
            const QString newloc = setlocale(LC_NUMERIC_MASK, mlt.attribute("LC_NUMERIC").toUtf8().constData());
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
139
#endif
140 141 142 143 144 145 146
            documentLocale = QLocale(mlt.attribute(QStringLiteral("LC_NUMERIC")));
            error = newloc.isEmpty();
        } else {
            // Document separator matching system separator
            documentLocale = QLocale();
        }
        if (error) {
147
            // Requested locale not available, ask for install
Laurent Montel's avatar
Laurent Montel committed
148
            KMessageBox::sorry(QApplication::activeWindow(), i18n("The document was created in \"%1\" locale, which is not installed on your system. Please install that language pack. Until then, Kdenlive might not be able to correctly open the document.", mlt.attribute(QStringLiteral("LC_NUMERIC"))));
149
        }
Laurent Montel's avatar
Laurent Montel committed
150

151 152
        // Make sure Qt locale and C++ locale have the same numeric separator, might not be the case
        // With some locales since C++ and Qt use a different database for locales
153 154
        // localeconv()->decimal_point does not give reliable results on Windows
#ifndef Q_OS_WIN
155
        char *separator = localeconv()->decimal_point;
156
        if (QString::fromUtf8(separator) != QString(documentLocale.decimalPoint())) {
Laurent Montel's avatar
Laurent Montel committed
157
        KMessageBox::sorry(QApplication::activeWindow(), i18n("There is a locale conflict on your system. The document uses locale %1 which uses a \"%2\" as numeric separator (in system libraries) but Qt expects \"%3\". You might not be able to correctly open the project.", mlt.attribute(QStringLiteral("LC_NUMERIC")), documentLocale.decimalPoint(), separator));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
158
            //qDebug()<<"------\n!!! system locale is not similar to Qt's locale... be prepared for bugs!!!\n------";
159
            // HACK: There is a locale conflict, so set locale to at least have correct decimal point
Laurent Montel's avatar
Laurent Montel committed
160 161 162 163 164
            if (strncmp(separator, ".", 1) == 0) {
                documentLocale = QLocale::c();
            } else if (strncmp(separator, ",", 1) == 0) {
                documentLocale = QLocale(QStringLiteral("fr_FR.UTF-8"));
            }
165
        }
166
#endif
167
    }
168
    documentLocale.setNumberOptions(QLocale::OmitGroupSeparator);
169 170
    if (documentLocale.decimalPoint() != QLocale().decimalPoint()) {
        // If loading an older MLT file without LC_NUMERIC, set locale to C which was previously the default
171
        if (!mlt.hasAttribute(QStringLiteral("LC_NUMERIC"))) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
172 173 174 175 176
#ifndef Q_OS_MAC
            setlocale(LC_NUMERIC, "C");
#else
            setlocale(LC_NUMERIC_MASK, "C");
#endif
177
	}
178
        QLocale::setDefault(documentLocale);
179 180 181
        if (documentLocale.decimalPoint() != QLocale().decimalPoint()) {
            KMessageBox::sorry(QApplication::activeWindow(), i18n("There is a locale conflict. The document uses a \"%1\" as numeric separator, but your computer is configured to use \"%2\". Change your computer settings or you might not be able to correctly open the project.", documentLocale.decimalPoint(), QLocale().decimalPoint()));
        }
182
        // locale conversion might need to be redone
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
183
#ifndef Q_OS_MAC
184
        initEffects::parseEffectFiles(pCore->getMltRepository(), QString::fromLatin1(setlocale(LC_NUMERIC, nullptr)));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
185
#else
186
        initEffects::parseEffectFiles(pCore->getMltRepository(), QString::fromLatin1(setlocale(LC_NUMERIC_MASK, nullptr)));
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
187
#endif
188
    }
189
    double version = -1;
190
    if (kdenliveDoc.isNull() || !kdenliveDoc.hasAttribute(QStringLiteral("version"))) {
191
        // Newer Kdenlive document version
192 193
        QDomElement main = mlt.firstChildElement(QStringLiteral("playlist"));
        version = EffectsList::property(main, QStringLiteral("kdenlive:docproperties.version")).toDouble();
Laurent Montel's avatar
Laurent Montel committed
194
    } else {
195
        bool ok;
196
        version = documentLocale.toDouble(kdenliveDoc.attribute(QStringLiteral("version")), &ok);
197 198
        if (!ok) {
            // Could not parse version number, there is probably a conflict in decimal separator
199 200
            QLocale tempLocale = QLocale(mlt.attribute(QStringLiteral("LC_NUMERIC")));
            version = tempLocale.toDouble(kdenliveDoc.attribute(QStringLiteral("version")), &ok);
Laurent Montel's avatar
Laurent Montel committed
201 202 203
            if (!ok) {
                version = kdenliveDoc.attribute(QStringLiteral("version")).toDouble(&ok);
            }
204 205
            if (!ok) {
                // Last try: replace comma with a dot
206
                QString versionString = kdenliveDoc.attribute(QStringLiteral("version"));
Laurent Montel's avatar
Laurent Montel committed
207
                if (versionString.contains(QLatin1Char(','))) {
Laurent Montel's avatar
Laurent Montel committed
208
                    versionString.replace(QLatin1Char(','), QLatin1Char('.'));
Laurent Montel's avatar
Laurent Montel committed
209
                }
210
                version = versionString.toDouble(&ok);
Laurent Montel's avatar
Laurent Montel committed
211 212 213
                if (!ok) {
                    qCDebug(KDENLIVE_LOG) << "// CANNOT PARSE VERSION NUMBER, ERROR!";
                }
214 215
            }
        }
216
    }
Alberto Villa's avatar
Alberto Villa committed
217
    // Upgrade the document to the latest version
Laurent Montel's avatar
Laurent Montel committed
218
    if (!upgrade(version, currentVersion)) {
Alberto Villa's avatar
Alberto Villa committed
219
        return false;
Laurent Montel's avatar
Laurent Montel committed
220
    }
Alberto Villa's avatar
Alberto Villa committed
221

222 223
    checkOrphanedProducers();

224
    return true;
225
    /*
226 227
    // Check the syntax (this will be replaced by XSD validation with Qt 4.6)
    // and correct some errors
228
    {
Alberto Villa's avatar
Alberto Villa committed
229
        // Return (or create) the tractor
230 231
        QDomElement tractor = mlt.firstChildElement("tractor");
        if (tractor.isNull()) {
Alberto Villa's avatar
Alberto Villa committed
232
            m_modified = true;
233 234 235 236 237 238
            tractor = m_doc.createElement("tractor");
            tractor.setAttribute("global_feed", "1");
            tractor.setAttribute("in", "0");
            tractor.setAttribute("out", "-1");
            tractor.setAttribute("id", "maintractor");
            mlt.appendChild(tractor);
Alberto Villa's avatar
Alberto Villa committed
239 240
        }

241 242 243
        // Make sure at least one track exists, and they're equal in number to
        // to the maximum between MLT and Kdenlive playlists and tracks
        //
244 245 246
        // In older Kdenlive project files, one playlist is not a real track (the black track), we have: track count = playlist count- 1
        // In newer Qt5 Kdenlive, the Bin playlist should not appear as a track. So we should have: track count = playlist count- 2
        int trackOffset = 1;
Alberto Villa's avatar
Alberto Villa committed
247
        QDomNodeList playlists = m_doc.elementsByTagName("playlist");
Laurent Montel's avatar
Laurent Montel committed
248 249 250 251 252 253
    // Remove "main bin" playlist that simply holds the bin's clips and is not a real playlist
    for (int i = 0; i < playlists.count(); ++i) {
        QString playlistId = playlists.at(i).toElement().attribute("id");
        if (playlistId == BinController::binPlaylistId()) {
        // remove pseudo-playlist
        //playlists.at(i).parentNode().removeChild(playlists.at(i));
254
                trackOffset = 2;
Laurent Montel's avatar
Laurent Montel committed
255 256 257 258
        break;
        }
    }

259
        int tracksMax = playlists.count() - trackOffset; // Remove the black track and bin track
260
        QDomNodeList tracks = tractor.elementsByTagName("track");
Alberto Villa's avatar
Alberto Villa committed
261
        tracksMax = qMax(tracks.count() - 1, tracksMax);
262
        QDomNodeList tracksinfo = kdenliveDoc.elementsByTagName("trackinfo");
Alberto Villa's avatar
Alberto Villa committed
263
        tracksMax = qMax(tracksinfo.count(), tracksMax);
Yuri Chornoivan's avatar
Yuri Chornoivan committed
264
        tracksMax = qMax(1, tracksMax); // Force existence of one track
265 266
        if (playlists.count() - trackOffset < tracksMax ||
                tracks.count() < tracksMax ||
Alberto Villa's avatar
Alberto Villa committed
267
                tracksinfo.count() < tracksMax) {
Laurent Montel's avatar
Laurent Montel committed
268
            qCDebug(KDENLIVE_LOG) << "//// WARNING, PROJECT IS CORRUPTED, MISSING TRACK";
Alberto Villa's avatar
Alberto Villa committed
269 270
            m_modified = true;
            int difference;
271 272 273 274 275
            // use the MLT tracks as reference
            if (tracks.count() - 1 < tracksMax) {
                // Looks like one MLT track is missing, remove the extra Kdenlive track if there is one.
                if (tracksinfo.count() != tracks.count() - 1) {
                    // The Kdenlive tracks are not ok, clear and rebuild them
Jean-Baptiste Mardelle's avatar
Cleanup  
Jean-Baptiste Mardelle committed
276
                    QDomNode tinfo = kdenliveDoc.firstChildElement("tracksinfo");
277 278 279 280 281 282
                    QDomNode tnode = tinfo.firstChild();
                    while (!tnode.isNull()) {
                        tinfo.removeChild(tnode);
                        tnode = tinfo.firstChild();
                    }

283
                    for (int i = 1; i < tracks.count(); ++i) {
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
                        QString hide = tracks.at(i).toElement().attribute("hide");
                        QDomElement newTrack = m_doc.createElement("trackinfo");
                        if (hide == "video") {
                            // audio track;
                            newTrack.setAttribute("type", "audio");
                            newTrack.setAttribute("blind", 1);
                            newTrack.setAttribute("mute", 0);
                            newTrack.setAttribute("lock", 0);
                        } else {
                            newTrack.setAttribute("blind", 0);
                            newTrack.setAttribute("mute", 0);
                            newTrack.setAttribute("lock", 0);
                        }
                        tinfo.appendChild(newTrack);
                    }
                }
            }

Alberto Villa's avatar
Alberto Villa committed
302 303 304 305
            if (playlists.count() - 1 < tracksMax) {
                difference = tracksMax - (playlists.count() - 1);
                for (int i = 0; i < difference; ++i) {
                    QDomElement playlist = m_doc.createElement("playlist");
306
                    mlt.appendChild(playlist);
Alberto Villa's avatar
Alberto Villa committed
307 308 309 310 311 312
                }
            }
            if (tracks.count() - 1 < tracksMax) {
                difference = tracksMax - (tracks.count() - 1);
                for (int i = 0; i < difference; ++i) {
                    QDomElement track = m_doc.createElement("track");
313
                    tractor.appendChild(track);
Alberto Villa's avatar
Alberto Villa committed
314 315 316
                }
            }
            if (tracksinfo.count() < tracksMax) {
317
                QDomElement tracksinfoElm = kdenliveDoc.firstChildElement("tracksinfo");
Alberto Villa's avatar
Alberto Villa committed
318 319
                if (tracksinfoElm.isNull()) {
                    tracksinfoElm = m_doc.createElement("tracksinfo");
320
                    kdenliveDoc.appendChild(tracksinfoElm);
Alberto Villa's avatar
Alberto Villa committed
321 322 323 324 325 326 327 328 329
                }
                difference = tracksMax - tracksinfo.count();
                for (int i = 0; i < difference; ++i) {
                    QDomElement trackinfo = m_doc.createElement("trackinfo");
                    trackinfo.setAttribute("mute", "0");
                    trackinfo.setAttribute("locked", "0");
                    tracksinfoElm.appendChild(trackinfo);
                }
            }
330
        }
Alberto Villa's avatar
Alberto Villa committed
331 332 333 334
        // TODO: check the tracks references
        // TODO: check internal mix transitions
    }

Till Theato's avatar
Till Theato committed
335 336
    updateEffects();

Alberto Villa's avatar
Alberto Villa committed
337
    return true;
338
    */
Alberto Villa's avatar
Alberto Villa committed
339 340 341 342
}

bool DocumentValidator::upgrade(double version, const double currentVersion)
{
Laurent Montel's avatar
Laurent Montel committed
343
    qCDebug(KDENLIVE_LOG) << "Opening a document with version " << version << " / " << currentVersion;
Alberto Villa's avatar
Alberto Villa committed
344 345

    // No conversion needed
346
    if (version == currentVersion) {
347
        return true;
348
    }
Alberto Villa's avatar
Alberto Villa committed
349 350 351

    // The document is too new
    if (version > currentVersion) {
Laurent Montel's avatar
Laurent Montel committed
352
        //qCDebug(KDENLIVE_LOG) << "Unable to open document with version " << version;
353
        KMessageBox::sorry(QApplication::activeWindow(), i18n("This project type is unsupported (version %1) and can't be loaded.\nPlease consider upgrading your Kdenlive version.", version), i18n("Unable to open project"));
Alberto Villa's avatar
Alberto Villa committed
354 355 356 357 358
        return false;
    }

    // Unsupported document versions
    if (version == 0.5 || version == 0.7) {
Laurent Montel's avatar
Laurent Montel committed
359
        //qCDebug(KDENLIVE_LOG) << "Unable to open document with version " << version;
360
        KMessageBox::sorry(QApplication::activeWindow(), i18n("This project type is unsupported (version %1) and can't be loaded.", version), i18n("Unable to open project"));
Alberto Villa's avatar
Alberto Villa committed
361 362
        return false;
    }
363

364
    // <kdenlivedoc />
365 366
    QDomNode infoXmlNode;
    QDomElement infoXml;
367
    QDomNodeList docs = m_doc.elementsByTagName(QStringLiteral("kdenlivedoc"));
368
    if (!docs.isEmpty()) {
369
        infoXmlNode = m_doc.elementsByTagName(QStringLiteral("kdenlivedoc")).at(0);
370
        infoXml = infoXmlNode.toElement();
371
        infoXml.setAttribute(QStringLiteral("upgraded"), QStringLiteral("1"));
372
    }
373
    m_doc.documentElement().setAttribute(QStringLiteral("upgraded"), QStringLiteral("1"));
374

Alberto Villa's avatar
Alberto Villa committed
375 376
    if (version <= 0.6) {
        QDomElement infoXml_old = infoXmlNode.cloneNode(true).toElement(); // Needed for folders
377 378 379 380
        QDomNode westley = m_doc.elementsByTagName(QStringLiteral("westley")).at(1);
        QDomNode tractor = m_doc.elementsByTagName(QStringLiteral("tractor")).at(0);
        QDomNode multitrack = m_doc.elementsByTagName(QStringLiteral("multitrack")).at(0);
        QDomNodeList playlists = m_doc.elementsByTagName(QStringLiteral("playlist"));
Alberto Villa's avatar
Alberto Villa committed
381

382 383 384
        QDomNode props = m_doc.elementsByTagName(QStringLiteral("properties")).at(0).toElement();
        QString profile = props.toElement().attribute(QStringLiteral("videoprofile"));
        int startPos = props.toElement().attribute(QStringLiteral("timeline_position")).toInt();
Laurent Montel's avatar
Laurent Montel committed
385
        if (profile == QLatin1String("dv_wide")) {
386
            profile = QStringLiteral("dv_pal_wide");
Laurent Montel's avatar
Laurent Montel committed
387
        }
Alberto Villa's avatar
Alberto Villa committed
388 389 390 391

        // move playlists outside of tractor and add the tracks instead
        int max = playlists.count();
        if (westley.isNull()) {
392
            westley = m_doc.createElement(QStringLiteral("westley"));
Alberto Villa's avatar
Alberto Villa committed
393 394 395
            m_doc.documentElement().appendChild(westley);
        }
        if (tractor.isNull()) {
Laurent Montel's avatar
Laurent Montel committed
396
            //qCDebug(KDENLIVE_LOG) << "// NO MLT PLAYLIST, building empty one";
397
            QDomElement blank_tractor = m_doc.createElement(QStringLiteral("tractor"));
Alberto Villa's avatar
Alberto Villa committed
398
            westley.appendChild(blank_tractor);
399 400
            QDomElement blank_playlist = m_doc.createElement(QStringLiteral("playlist"));
            blank_playlist.setAttribute(QStringLiteral("id"), QStringLiteral("black_track"));
Alberto Villa's avatar
Alberto Villa committed
401
            westley.insertBefore(blank_playlist, QDomNode());
402 403
            QDomElement blank_track = m_doc.createElement(QStringLiteral("track"));
            blank_track.setAttribute(QStringLiteral("producer"), QStringLiteral("black_track"));
Alberto Villa's avatar
Alberto Villa committed
404 405
            blank_tractor.appendChild(blank_track);

406
            QDomNodeList kdenlivetracks = m_doc.elementsByTagName(QStringLiteral("kdenlivetrack"));
407
            for (int i = 0; i < kdenlivetracks.count(); ++i) {
408
                blank_playlist = m_doc.createElement(QStringLiteral("playlist"));
Laurent Montel's avatar
Laurent Montel committed
409
                blank_playlist.setAttribute(QStringLiteral("id"), QStringLiteral("playlist") + QString::number(i));
Alberto Villa's avatar
Alberto Villa committed
410
                westley.insertBefore(blank_playlist, QDomNode());
411
                blank_track = m_doc.createElement(QStringLiteral("track"));
Laurent Montel's avatar
Laurent Montel committed
412
                blank_track.setAttribute(QStringLiteral("producer"), QStringLiteral("playlist") + QString::number(i));
Alberto Villa's avatar
Alberto Villa committed
413
                blank_tractor.appendChild(blank_track);
414 415 416
                if (kdenlivetracks.at(i).toElement().attribute(QStringLiteral("cliptype")) == QLatin1String("Sound")) {
                    blank_playlist.setAttribute(QStringLiteral("hide"), QStringLiteral("video"));
                    blank_track.setAttribute(QStringLiteral("hide"), QStringLiteral("video"));
Alberto Villa's avatar
Alberto Villa committed
417 418
                }
            }
419
        } else for (int i = 0; i < max; ++i) {
Alberto Villa's avatar
Alberto Villa committed
420 421 422
                QDomNode n = playlists.at(i);
                westley.insertBefore(n, QDomNode());
                QDomElement pl = n.toElement();
423 424
                QDomElement track = m_doc.createElement(QStringLiteral("track"));
                QString trackType = pl.attribute(QStringLiteral("hide"));
Laurent Montel's avatar
Laurent Montel committed
425
                if (!trackType.isEmpty()) {
426
                    track.setAttribute(QStringLiteral("hide"), trackType);
Laurent Montel's avatar
Laurent Montel committed
427
                }
428
                QString playlist_id =  pl.attribute(QStringLiteral("id"));
Alberto Villa's avatar
Alberto Villa committed
429
                if (playlist_id.isEmpty()) {
430 431
                    playlist_id = QStringLiteral("black_track");
                    pl.setAttribute(QStringLiteral("id"), playlist_id);
Alberto Villa's avatar
Alberto Villa committed
432
                }
433
                track.setAttribute(QStringLiteral("producer"), playlist_id);
Alberto Villa's avatar
Alberto Villa committed
434
                //tractor.appendChild(track);
Alberto Villa's avatar
Alberto Villa committed
435 436
#define KEEP_TRACK_ORDER 1
#ifdef KEEP_TRACK_ORDER
Alberto Villa's avatar
Alberto Villa committed
437
                tractor.insertAfter(track, QDomNode());
Alberto Villa's avatar
Alberto Villa committed
438
#else
Alberto Villa's avatar
Alberto Villa committed
439 440 441 442 443 444 445 446 447 448 449 450 451 452 453
                // Insert the new track in an order that hopefully matches the 3 video, then 2 audio tracks of Kdenlive 0.7.0
                // insertion sort - O( tracks*tracks )
                // Note, this breaks _all_ transitions - but you can move them up and down afterwards.
                QDomElement tractor_elem = tractor.toElement();
                if (! tractor_elem.isNull()) {
                    QDomNodeList tracks = tractor_elem.elementsByTagName("track");
                    int size = tracks.size();
                    if (size == 0) {
                        tractor.insertAfter(track, QDomNode());
                    } else {
                        bool inserted = false;
                        for (int i = 0; i < size; ++i) {
                            QDomElement track_elem = tracks.at(i).toElement();
                            if (track_elem.isNull()) {
                                tractor.insertAfter(track, QDomNode());
Alberto Villa's avatar
Alberto Villa committed
454 455
                                inserted = true;
                                break;
Alberto Villa's avatar
Alberto Villa committed
456
                            } else {
Laurent Montel's avatar
Laurent Montel committed
457
                                //qCDebug(KDENLIVE_LOG) << "playlist_id: " << playlist_id << " producer:" << track_elem.attribute("producer");
Alberto Villa's avatar
Alberto Villa committed
458 459 460 461 462
                                if (playlist_id < track_elem.attribute("producer")) {
                                    tractor.insertBefore(track, track_elem);
                                    inserted = true;
                                    break;
                                }
Alberto Villa's avatar
Alberto Villa committed
463 464
                            }
                        }
Alberto Villa's avatar
Alberto Villa committed
465 466 467 468
                        // Reach here, no insertion, insert last
                        if (!inserted) {
                            tractor.insertAfter(track, QDomNode());
                        }
Alberto Villa's avatar
Alberto Villa committed
469
                    }
Alberto Villa's avatar
Alberto Villa committed
470
                } else {
Laurent Montel's avatar
Laurent Montel committed
471
                    qCWarning(KDENLIVE_LOG) << "tractor was not a QDomElement";
Alberto Villa's avatar
Alberto Villa committed
472
                    tractor.insertAfter(track, QDomNode());
Alberto Villa's avatar
Alberto Villa committed
473 474
                }
#endif
Alberto Villa's avatar
Alberto Villa committed
475
            }
Alberto Villa's avatar
Alberto Villa committed
476 477 478
        tractor.removeChild(multitrack);

        // audio track mixing transitions should not be added to track view, so add required attribute
479
        QDomNodeList transitions = m_doc.elementsByTagName(QStringLiteral("transition"));
Alberto Villa's avatar
Alberto Villa committed
480
        max = transitions.count();
481
        for (int i = 0; i < max; ++i) {
Alberto Villa's avatar
Alberto Villa committed
482
            QDomElement tr = transitions.at(i).toElement();
483 484 485 486
            if (tr.attribute(QStringLiteral("combine")) == QLatin1String("1") && tr.attribute(QStringLiteral("mlt_service")) == QLatin1String("mix")) {
                QDomElement property = m_doc.createElement(QStringLiteral("property"));
                property.setAttribute(QStringLiteral("name"), QStringLiteral("internal_added"));
                QDomText value = m_doc.createTextNode(QStringLiteral("237"));
Alberto Villa's avatar
Alberto Villa committed
487 488
                property.appendChild(value);
                tr.appendChild(property);
489 490 491
                property = m_doc.createElement(QStringLiteral("property"));
                property.setAttribute(QStringLiteral("name"), QStringLiteral("mlt_service"));
                value = m_doc.createTextNode(QStringLiteral("mix"));
Alberto Villa's avatar
Alberto Villa committed
492 493 494 495 496
                property.appendChild(value);
                tr.appendChild(property);
            } else {
                // convert transition
                QDomNamedNodeMap attrs = tr.attributes();
497
                for (int j = 0; j < attrs.count(); ++j) {
Alberto Villa's avatar
Alberto Villa committed
498
                    QString attrName = attrs.item(j).nodeName();
499 500 501
                    if (attrName != QLatin1String("in") && attrName != QLatin1String("out") && attrName != QLatin1String("id")) {
                        QDomElement property = m_doc.createElement(QStringLiteral("property"));
                        property.setAttribute(QStringLiteral("name"), attrName);
Alberto Villa's avatar
Alberto Villa committed
502 503 504 505 506 507 508 509 510
                        QDomText value = m_doc.createTextNode(attrs.item(j).nodeValue());
                        property.appendChild(value);
                        tr.appendChild(property);
                    }
                }
            }
        }

        // move transitions after tracks
511
        for (int i = 0; i < max; ++i) {
Alberto Villa's avatar
Alberto Villa committed
512 513 514 515
            tractor.insertAfter(transitions.at(0), QDomNode());
        }

        // Fix filters format
516
        QDomNodeList entries = m_doc.elementsByTagName(QStringLiteral("entry"));
Alberto Villa's avatar
Alberto Villa committed
517
        max = entries.count();
518
        for (int i = 0; i < max; ++i) {
Alberto Villa's avatar
Alberto Villa committed
519 520 521 522
            QString last_id;
            int effectix = 0;
            QDomNode m = entries.at(i).firstChild();
            while (!m.isNull()) {
523
                if (m.toElement().tagName() == QLatin1String("filter")) {
Alberto Villa's avatar
Alberto Villa committed
524 525
                    QDomElement filt = m.toElement();
                    QDomNamedNodeMap attrs = filt.attributes();
526
                    QString current_id = filt.attribute(QStringLiteral("kdenlive_id"));
Alberto Villa's avatar
Alberto Villa committed
527 528 529 530
                    if (current_id != last_id) {
                        effectix++;
                        last_id = current_id;
                    }
531 532
                    QDomElement e = m_doc.createElement(QStringLiteral("property"));
                    e.setAttribute(QStringLiteral("name"), QStringLiteral("kdenlive_ix"));
Alberto Villa's avatar
Alberto Villa committed
533 534 535
                    QDomText value = m_doc.createTextNode(QString::number(effectix));
                    e.appendChild(value);
                    filt.appendChild(e);
536
                    for (int j = 0; j < attrs.count(); ++j) {
Alberto Villa's avatar
Alberto Villa committed
537 538
                        QDomAttr a = attrs.item(j).toAttr();
                        if (!a.isNull()) {
Laurent Montel's avatar
Laurent Montel committed
539
                            //qCDebug(KDENLIVE_LOG) << " FILTER; adding :" << a.name() << ':' << a.value();
540 541 542 543 544
                            auto property = m_doc.createElement(QStringLiteral("property"));
                            property.setAttribute(QStringLiteral("name"), a.name());
                            auto property_value = m_doc.createTextNode(a.value());
                            property.appendChild(property_value);
                            filt.appendChild(property);
Alberto Villa's avatar
Alberto Villa committed
545 546 547 548 549 550 551 552 553 554 555 556 557

                        }
                    }
                }
                m = m.nextSibling();
            }
        }

        /*
            QDomNodeList filters = m_doc.elementsByTagName("filter");
            max = filters.count();
            QString last_id;
            int effectix = 0;
558
            for (int i = 0; i < max; ++i) {
Alberto Villa's avatar
Alberto Villa committed
559 560 561 562 563 564 565 566 567 568 569 570
                QDomElement filt = filters.at(i).toElement();
                QDomNamedNodeMap attrs = filt.attributes();
        QString current_id = filt.attribute("kdenlive_id");
        if (current_id != last_id) {
            effectix++;
            last_id = current_id;
        }
        QDomElement e = m_doc.createElement("property");
                e.setAttribute("name", "kdenlive_ix");
                QDomText value = m_doc.createTextNode(QString::number(1));
                e.appendChild(value);
                filt.appendChild(e);
571
                for (int j = 0; j < attrs.count(); ++j) {
Alberto Villa's avatar
Alberto Villa committed
572 573
                    QDomAttr a = attrs.item(j).toAttr();
                    if (!a.isNull()) {
Laurent Montel's avatar
Laurent Montel committed
574
                        //qCDebug(KDENLIVE_LOG) << " FILTER; adding :" << a.name() << ':' << a.value();
Alberto Villa's avatar
Alberto Villa committed
575 576 577 578 579 580 581 582 583 584
                        QDomElement e = m_doc.createElement("property");
                        e.setAttribute("name", a.name());
                        QDomText value = m_doc.createTextNode(a.value());
                        e.appendChild(value);
                        filt.appendChild(e);
                    }
                }
            }*/

        // fix slowmotion
585
        QDomNodeList producers = westley.toElement().elementsByTagName(QStringLiteral("producer"));
Alberto Villa's avatar
Alberto Villa committed
586
        max = producers.count();
587
        for (int i = 0; i < max; ++i) {
Alberto Villa's avatar
Alberto Villa committed
588
            QDomElement prod = producers.at(i).toElement();
589 590
            if (prod.attribute(QStringLiteral("mlt_service")) == QLatin1String("framebuffer")) {
                QString slowmotionprod = prod.attribute(QStringLiteral("resource"));
Laurent Montel's avatar
Laurent Montel committed
591
                slowmotionprod.replace(QLatin1Char(':'), QLatin1Char('?'));
Laurent Montel's avatar
Laurent Montel committed
592
                //qCDebug(KDENLIVE_LOG) << "// FOUND WRONG SLOWMO, new: " << slowmotionprod;
593
                prod.setAttribute(QStringLiteral("resource"), slowmotionprod);
Alberto Villa's avatar
Alberto Villa committed
594 595 596
            }
        }
        // move producers to correct place, markers to a global list, fix clip descriptions
597
        QDomElement markers = m_doc.createElement(QStringLiteral("markers"));
Alberto Villa's avatar
Alberto Villa committed
598
        // This will get the xml producers:
599
        producers = m_doc.elementsByTagName(QStringLiteral("producer"));
Alberto Villa's avatar
Alberto Villa committed
600
        max = producers.count();
601
        for (int i = 0; i < max; ++i) {
Alberto Villa's avatar
Alberto Villa committed
602 603 604 605 606 607 608 609 610 611 612 613
            QDomElement prod = producers.at(0).toElement();
            // add resource also as a property (to allow path correction in setNewResource())
            // TODO: will it work with slowmotion? needs testing
            /*if (!prod.attribute("resource").isEmpty()) {
                QDomElement prop_resource = m_doc.createElement("property");
                prop_resource.setAttribute("name", "resource");
                QDomText resource = m_doc.createTextNode(prod.attribute("resource"));
                prop_resource.appendChild(resource);
                prod.appendChild(prop_resource);
            }*/
            QDomNode m = prod.firstChild();
            if (!m.isNull()) {
614
                if (m.toElement().tagName() == QLatin1String("markers")) {
Alberto Villa's avatar
Alberto Villa committed
615 616
                    QDomNodeList prodchilds = m.childNodes();
                    int maxchild = prodchilds.count();
617
                    for (int k = 0; k < maxchild; ++k) {
Alberto Villa's avatar
Alberto Villa committed
618
                        QDomElement mark = prodchilds.at(0).toElement();
619
                        mark.setAttribute(QStringLiteral("id"), prod.attribute(QStringLiteral("id")));
Alberto Villa's avatar
Alberto Villa committed
620 621 622
                        markers.insertAfter(mark, QDomNode());
                    }
                    prod.removeChild(m);
623
                } else if (prod.attribute(QStringLiteral("type")).toInt() == Text) {
Alberto Villa's avatar
Alberto Villa committed
624
                    // convert title clip
625
                    if (m.toElement().tagName() == QLatin1String("textclip")) {
Alberto Villa's avatar
Alberto Villa committed
626 627
                        QDomDocument tdoc;
                        QDomElement titleclip = m.toElement();
628
                        QDomElement title = tdoc.createElement(QStringLiteral("kdenlivetitle"));
Alberto Villa's avatar
Alberto Villa committed
629 630 631
                        tdoc.appendChild(title);
                        QDomNodeList objects = titleclip.childNodes();
                        int maxchild = objects.count();
632
                        for (int k = 0; k < maxchild; ++k) {
Alberto Villa's avatar
Alberto Villa committed
633
                            QDomElement ob = objects.at(k).toElement();
634
                            if (ob.attribute(QStringLiteral("type")) == QLatin1String("3")) {
Alberto Villa's avatar
Alberto Villa committed
635
                                // text object - all of this goes into "xmldata"...
636 637 638 639 640 641 642 643 644 645 646 647 648
                                QDomElement item = tdoc.createElement(QStringLiteral("item"));
                                item.setAttribute(QStringLiteral("z-index"), ob.attribute(QStringLiteral("z")));
                                item.setAttribute(QStringLiteral("type"), QStringLiteral("QGraphicsTextItem"));
                                QDomElement position = tdoc.createElement(QStringLiteral("position"));
                                position.setAttribute(QStringLiteral("x"), ob.attribute(QStringLiteral("x")));
                                position.setAttribute(QStringLiteral("y"), ob.attribute(QStringLiteral("y")));
                                QDomElement content = tdoc.createElement(QStringLiteral("content"));
                                content.setAttribute(QStringLiteral("font"), ob.attribute(QStringLiteral("font_family")));
                                content.setAttribute(QStringLiteral("font-size"), ob.attribute(QStringLiteral("font_size")));
                                content.setAttribute(QStringLiteral("font-bold"), ob.attribute(QStringLiteral("bold")));
                                content.setAttribute(QStringLiteral("font-italic"), ob.attribute(QStringLiteral("italic")));
                                content.setAttribute(QStringLiteral("font-underline"), ob.attribute(QStringLiteral("underline")));
                                QString col = ob.attribute(QStringLiteral("color"));
Alberto Villa's avatar
Alberto Villa committed
649
                                QColor c(col);
650
                                content.setAttribute(QStringLiteral("font-color"), colorToString(c));
Alberto Villa's avatar
Alberto Villa committed
651 652 653
                                // todo: These fields are missing from the newly generated xmldata:
                                // transform, startviewport, endviewport, background

654
                                QDomText conttxt = tdoc.createTextNode(ob.attribute(QStringLiteral("text")));
Alberto Villa's avatar
Alberto Villa committed
655 656 657 658
                                content.appendChild(conttxt);
                                item.appendChild(position);
                                item.appendChild(content);
                                title.appendChild(item);
659
                            } else if (ob.attribute(QStringLiteral("type")) == QLatin1String("5")) {
Alberto Villa's avatar
Alberto Villa committed
660
                                // rectangle object
661 662 663 664 665 666 667 668
                                QDomElement item = tdoc.createElement(QStringLiteral("item"));
                                item.setAttribute(QStringLiteral("z-index"), ob.attribute(QStringLiteral("z")));
                                item.setAttribute(QStringLiteral("type"), QStringLiteral("QGraphicsRectItem"));
                                QDomElement position = tdoc.createElement(QStringLiteral("position"));
                                position.setAttribute(QStringLiteral("x"), ob.attribute(QStringLiteral("x")));
                                position.setAttribute(QStringLiteral("y"), ob.attribute(QStringLiteral("y")));
                                QDomElement content = tdoc.createElement(QStringLiteral("content"));
                                QString col = ob.attribute(QStringLiteral("color"));
Alberto Villa's avatar
Alberto Villa committed
669
                                QColor c(col);
670 671 672
                                content.setAttribute(QStringLiteral("brushcolor"), colorToString(c));
                                QString rect = QStringLiteral("0,0,");
                                rect.append(ob.attribute(QStringLiteral("width")));
Laurent Montel's avatar
Laurent Montel committed
673
                                rect.append(QLatin1String(","));
674 675
                                rect.append(ob.attribute(QStringLiteral("height")));
                                content.setAttribute(QStringLiteral("rect"), rect);
Alberto Villa's avatar
Alberto Villa committed
676 677 678 679 680
                                item.appendChild(position);
                                item.appendChild(content);
                                title.appendChild(item);
                            }
                        }
681
                        prod.setAttribute(QStringLiteral("xmldata"), tdoc.toString());
Alberto Villa's avatar
Alberto Villa committed
682 683 684 685
                        // mbd todo: This clearly does not work, as every title gets the same name - trying to leave it empty
                        // QStringList titleInfo = TitleWidget::getFreeTitleInfo(projectFolder());
                        // prod.setAttribute("titlename", titleInfo.at(0));
                        // prod.setAttribute("resource", titleInfo.at(1));
Laurent Montel's avatar
Laurent Montel committed
686
                        ////qCDebug(KDENLIVE_LOG)<<"TITLE DATA:\n"<<tdoc.toString();
Alberto Villa's avatar
Alberto Villa committed
687 688 689 690 691 692
                        prod.removeChild(m);
                    } // End conversion of title clips.

                } else if (m.isText()) {
                    QString comment = m.nodeValue();
                    if (!comment.isEmpty()) {
693
                        prod.setAttribute(QStringLiteral("description"), comment);
Alberto Villa's avatar
Alberto Villa committed
694 695 696 697
                    }
                    prod.removeChild(m);
                }
            }
698
            int duration = prod.attribute(QStringLiteral("duration")).toInt();
Laurent Montel's avatar
Laurent Montel committed
699 700 701
            if (duration > 0) {
                prod.setAttribute(QStringLiteral("out"), QString::number(duration));
            }
Alberto Villa's avatar
Alberto Villa committed
702 703 704 705
            // The clip goes back in, but text clips should not go back in, at least not modified
            westley.insertBefore(prod, QDomNode());
        }

706
        QDomNode westley0 = m_doc.elementsByTagName(QStringLiteral("westley")).at(0);
Laurent Montel's avatar
Laurent Montel committed
707 708 709
        if (!markers.firstChild().isNull()) {
            westley0.appendChild(markers);
        }
Alberto Villa's avatar
Alberto Villa committed
710 711 712 713 714 715 716 717 718

        /*
         * Convert as much of the kdenlivedoc as possible. Use the producer in
         * westley. First, remove the old stuff from westley, and add a new
         * empty one. Also, track the max id in order to use it for the adding
         * of groups/folders
         */
        int max_kproducer_id = 0;
        westley0.removeChild(infoXmlNode);
719 720 721
        QDomElement infoXml_new = m_doc.createElement(QStringLiteral("kdenlivedoc"));
        infoXml_new.setAttribute(QStringLiteral("profile"), profile);
        infoXml.setAttribute(QStringLiteral("position"), startPos);
Alberto Villa's avatar
Alberto Villa committed
722 723 724 725

        // Add all the producers that has a resource in westley
        QDomElement westley_element = westley0.toElement();
        if (westley_element.isNull()) {
Laurent Montel's avatar
Laurent Montel committed
726
            qCWarning(KDENLIVE_LOG) << "westley0 element in document was not a QDomElement - unable to add producers to new kdenlivedoc";
Alberto Villa's avatar
Alberto Villa committed
727
        } else {
728
            QDomNodeList wproducers = westley_element.elementsByTagName(QStringLiteral("producer"));
Alberto Villa's avatar
Alberto Villa committed
729
            int kmax = wproducers.count();
730
            for (int i = 0; i < kmax; ++i) {
Alberto Villa's avatar
Alberto Villa committed
731 732
                QDomElement wproducer = wproducers.at(i).toElement();
                if (wproducer.isNull()) {
Laurent Montel's avatar
Laurent Montel committed
733
                    qCWarning(KDENLIVE_LOG) << "Found producer in westley0, that was not a QDomElement";
Alberto Villa's avatar
Alberto Villa committed
734 735
                    continue;
                }
Laurent Montel's avatar
Laurent Montel committed
736 737 738
                if (wproducer.attribute(QStringLiteral("id")) == QLatin1String("black")) {
                    continue;
                }
Alberto Villa's avatar
Alberto Villa committed
739
                // We have to do slightly different things, depending on the type
Laurent Montel's avatar
Laurent Montel committed
740
                //qCDebug(KDENLIVE_LOG) << "Converting producer element with type" << wproducer.attribute("type");
741
                if (wproducer.attribute(QStringLiteral("type")).toInt() == Text) {
Laurent Montel's avatar
Laurent Montel committed
742
                    //qCDebug(KDENLIVE_LOG) << "Found TEXT element in producer" << endl;
Alberto Villa's avatar
Alberto Villa committed
743
                    QDomElement kproducer = wproducer.cloneNode(true).toElement();
744
                    kproducer.setTagName(QStringLiteral("kdenlive_producer"));
Alberto Villa's avatar
Alberto Villa committed
745 746 747 748 749 750 751
                    infoXml_new.appendChild(kproducer);
                    /*
                     * TODO: Perhaps needs some more changes here to
                     * "frequency", aspect ratio as a float, frame_size,
                     * channels, and later, resource and title name
                     */
                } else {
752 753
                    QDomElement kproducer = m_doc.createElement(QStringLiteral("kdenlive_producer"));
                    kproducer.setAttribute(QStringLiteral("id"), wproducer.attribute(QStringLiteral("id")));
Laurent Montel's avatar
Laurent Montel committed
754
                    if (!wproducer.attribute(QStringLiteral("description")).isEmpty()) {
755
                        kproducer.setAttribute(QStringLiteral("description"), wproducer.attribute(QStringLiteral("description")));
Laurent Montel's avatar
Laurent Montel committed
756
                    }
757 758
                    kproducer.setAttribute(QStringLiteral("resource"), wproducer.attribute(QStringLiteral("resource")));
                    kproducer.setAttribute(QStringLiteral("type"), wproducer.attribute(QStringLiteral("type")));
Alberto Villa's avatar
Alberto Villa committed
759
                    // Testing fix for 358
760 761
                    if (!wproducer.attribute(QStringLiteral("aspect_ratio")).isEmpty()) {
                        kproducer.setAttribute(QStringLiteral("aspect_ratio"), wproducer.attribute(QStringLiteral("aspect_ratio")));
Alberto Villa's avatar
Alberto Villa committed
762
                    }
763 764
                    if (!wproducer.attribute(QStringLiteral("source_fps")).isEmpty()) {
                        kproducer.setAttribute(QStringLiteral("fps"), wproducer.attribute(QStringLiteral("source_fps")));
Alberto Villa's avatar
Alberto Villa committed
765
                    }
766 767
                    if (!wproducer.attribute(QStringLiteral("length")).isEmpty()) {
                        kproducer.setAttribute(QStringLiteral("duration"), wproducer.attribute(QStringLiteral("length")));
Alberto Villa's avatar
Alberto Villa committed
768 769 770
                    }
                    infoXml_new.appendChild(kproducer);
                }
771 772
                if (wproducer.attribute(QStringLiteral("id")).toInt() > max_kproducer_id) {
                    max_kproducer_id = wproducer.attribute(QStringLiteral("id")).toInt();
Alberto Villa's avatar
Alberto Villa committed
773 774 775 776 777 778 779 780 781 782 783 784 785 786
                }
            }
        }
#define LOOKUP_FOLDER 1
#ifdef LOOKUP_FOLDER
        /*
         * Look through all the folder elements of the old doc, for each folder,
         * for each producer, get the id, look it up in the new doc, set the
         * groupname and groupid. Note, this does not work at the moment - at
         * least one folder shows up missing, and clips with no folder does not
         * show up.
         */
        //QDomElement infoXml_old = infoXmlNode.toElement();
        if (!infoXml_old.isNull()) {
787
            QDomNodeList folders = infoXml_old.elementsByTagName(QStringLiteral("folder"));
Alberto Villa's avatar
Alberto Villa committed
788 789 790 791 792
            int fsize = folders.size();
            int groupId = max_kproducer_id + 1; // Start at +1 of max id of the kdenlive_producers
            for (int i = 0; i < fsize; ++i) {
                QDomElement folder = folders.at(i).toElement();
                if (!folder.isNull()) {
793
                    QString groupName = folder.attribute(QStringLiteral("name"));
Laurent Montel's avatar
Laurent Montel committed
794
                    //qCDebug(KDENLIVE_LOG) << "groupName: " << groupName << " with groupId: " << groupId;
795
                    QDomNodeList fproducers = folder.elementsByTagName(QStringLiteral("producer"));
Alberto Villa's avatar
Alberto Villa committed
796 797 798 799
                    int psize = fproducers.size();
                    for (int j = 0; j < psize; ++j) {
                        QDomElement fproducer = fproducers.at(j).toElement();
                        if (!fproducer.isNull()) {
800
                            QString id = fproducer.attribute(QStringLiteral("id"));
Alberto Villa's avatar
Alberto Villa committed
801
                            // This is not very effective, but compared to loading the clips, its a breeze
802
                            QDomNodeList kdenlive_producers = infoXml_new.elementsByTagName(QStringLiteral("kdenlive_producer"));
Alberto Villa's avatar
Alberto Villa committed
803 804 805
                            int kpsize = kdenlive_producers.size();
                            for (int k = 0; k < kpsize; ++k) {
                                QDomElement kproducer = kdenlive_producers.at(k).toElement(); // Its an element for sure
806
                                if (id == kproducer.attribute(QStringLiteral("id"))) {
Alberto Villa's avatar
Alberto Villa committed
807
                                    // We do not check that it already is part of a folder
808 809
                                    kproducer.setAttribute(QStringLiteral("groupid"), groupId);
                                    kproducer.setAttribute(QStringLiteral("groupname"), groupName);
Alberto Villa's avatar
Alberto Villa committed
810 811 812 813 814 815 816 817 818 819