]> git.sesse.net Git - kdenlive/commitdiff
kdenlivedoc.cpp:
authorAlberto Villa <avilla@FreeBSD.org>
Wed, 10 Jun 2009 20:55:26 +0000 (20:55 +0000)
committerAlberto Villa <avilla@FreeBSD.org>
Wed, 10 Jun 2009 20:55:26 +0000 (20:55 +0000)
- revert document loading logic, so that errors are handled first
- validate the document instead of simply upgrading it
- share the code for the creation of a new project
- set the correct document version in saved files

documentvalidator.(h|cpp):
- replace documentconvert.(h|cpp)
- the upgrade function now works with incremental changes
- start a validation function to check that the document can really be handled by kdenlive

svn path=/trunk/kdenlive/; revision=3513

src/CMakeLists.txt
src/documentconvert.cpp [deleted file]
src/documentvalidator.cpp [new file with mode: 0644]
src/documentvalidator.h [moved from src/documentconvert.h with 85% similarity]
src/kdenlivedoc.cpp

index 59fdde5da272135fe965dab8c6b22a53d39f2a16..f2fa89f86e3f99ffb26667af0b19d12acb432d4e 100644 (file)
@@ -10,9 +10,9 @@ include_directories (
     ${QT_INCLUDES}
     ${LIBMLT_INCLUDE_DIR}
     ${LIBMLTPLUS_INCLUDE_DIR}
-    ${QDBUS_INCLUDE_DIRS} 
-    ${CMAKE_SOURCE_DIR} 
-    ${CMAKE_BINARY_DIR} 
+    ${QDBUS_INCLUDE_DIRS}
+    ${CMAKE_SOURCE_DIR}
+    ${CMAKE_BINARY_DIR}
 
     ${CMAKE_SOURCE_DIR}/src/widgets
     ${NEPOMUK_INCLUDES}
@@ -75,8 +75,8 @@ kde4_add_ui_files(kdenlive_UI
   widgets/cliptranscode_ui.ui
   widgets/geometryposition_ui.ui
 )
-set(kdenlive_SRCS 
+
+set(kdenlive_SRCS
   addclipcommand.cpp
   main.cpp
   mainwindow.cpp
@@ -161,7 +161,7 @@ set(kdenlive_SRCS
   changecliptypecommand.cpp
   documentchecker.cpp
   dvdwizardchapters.cpp
-  documentconvert.cpp
+  documentvalidator.cpp
   cliptranscode.cpp
 )
 
@@ -178,7 +178,7 @@ QT4_ADD_DBUS_ADAPTOR(kdenlive_SRCS org.kdenlive.MainWindow.xml mainwindow.h Main
 kde4_add_executable(kdenlive ${kdenlive_SRCS} ${kdenlive_UI})
 
 
-target_link_libraries(kdenlive 
+target_link_libraries(kdenlive
   ${KDE4_KDEUI_LIBS}
   ${KDE4_KIO_LIBS}
   ${KDE4_KNEWSTUFF2_LIBS}
diff --git a/src/documentconvert.cpp b/src/documentconvert.cpp
deleted file mode 100644 (file)
index 67cca68..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-/***************************************************************************
- *   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          *
- ***************************************************************************/
-
-
-#include "documentconvert.h"
-#include "definitions.h"
-
-#include <KDebug>
-#include <KMessageBox>
-#include <KApplication>
-#include <KLocale>
-
-#include <QColor>
-
-DocumentConvert::DocumentConvert(QDomDocument doc):
-        m_doc(doc),
-        m_modified(false)
-{}
-
-
-bool DocumentConvert::doConvert(double version, const double current_version)
-{
-    kDebug() << "Opening a document with version " << version;
-
-    if (version == current_version) return true;
-
-    if (version > current_version) {
-        kDebug() << "Unable to open document with version " << version;
-        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"));
-        return false;
-    }
-
-    // Opening a old Kdenlive document
-    if (version == 0.5 || version == 0.7) {
-        KMessageBox::sorry(kapp->activeWindow(), i18n("This project type is unsupported (version %1) and can't be loaded.", version), i18n("Unable to open project"));
-        kDebug() << "Unable to open document with version " << version;
-        // TODO: convert 0.7 (0.5?) files to the new document format.
-        return false;
-    }
-
-    m_modified = true;
-
-    if (version == 0.82) {
-        convertToMelt();
-        return true;
-    }
-
-    if (version == 0.81) {
-        // Add correct tracks info
-        QDomNode kdenlivedoc = m_doc.elementsByTagName("kdenlivedoc").at(0);
-        QDomElement infoXml = kdenlivedoc.toElement();
-        infoXml.setAttribute("version", current_version);
-        QString currentTrackOrder = infoXml.attribute("tracks");
-        QDomElement tracksinfo = m_doc.createElement("tracksinfo");
-        for (int i = 0; i < currentTrackOrder.size(); i++) {
-            QDomElement trackinfo = m_doc.createElement("trackinfo");
-            if (currentTrackOrder.data()[i] == 'a') {
-                trackinfo.setAttribute("type", "audio");
-                trackinfo.setAttribute("blind", true);
-            } else trackinfo.setAttribute("blind", false);
-            trackinfo.setAttribute("mute", false);
-            trackinfo.setAttribute("locked", false);
-            tracksinfo.appendChild(trackinfo);
-        }
-        infoXml.appendChild(tracksinfo);
-        convertToMelt();
-        return true;
-    }
-
-    if (version == 0.8) {
-        // Add the tracks information
-        QDomNodeList tracks = m_doc.elementsByTagName("track");
-        int max = tracks.count();
-
-        QDomNode kdenlivedoc = m_doc.elementsByTagName("kdenlivedoc").at(0);
-        QDomElement infoXml = kdenlivedoc.toElement();
-        infoXml.setAttribute("version", current_version);
-        QDomElement tracksinfo = m_doc.createElement("tracksinfo");
-
-        for (int i = 0; i < max; i++) {
-            QDomElement trackinfo = m_doc.createElement("trackinfo");
-            QDomElement t = tracks.at(i).toElement();
-            if (t.attribute("hide") == "video") {
-                trackinfo.setAttribute("type", "audio");
-                trackinfo.setAttribute("blind", true);
-            } else trackinfo.setAttribute("blind", false);
-            trackinfo.setAttribute("mute", false);
-            trackinfo.setAttribute("locked", false);
-            if (t.attribute("producer") != "black_track") tracksinfo.appendChild(trackinfo);
-        }
-        infoXml.appendChild(tracksinfo);
-        convertToMelt();
-        return true;
-    }
-
-    QDomNode westley = m_doc.elementsByTagName("westley").at(1);
-    QDomNode tractor = m_doc.elementsByTagName("tractor").at(0);
-    QDomNode kdenlivedoc = m_doc.elementsByTagName("kdenlivedoc").at(0);
-    QDomElement kdenlivedoc_old = kdenlivedoc.cloneNode(true).toElement(); // Needed for folders
-    QDomElement infoXml = kdenlivedoc.toElement();
-    infoXml.setAttribute("version", current_version);
-    QDomNode multitrack = m_doc.elementsByTagName("multitrack").at(0);
-    QDomNodeList playlists = m_doc.elementsByTagName("playlist");
-
-    QDomNode props = m_doc.elementsByTagName("properties").at(0).toElement();
-    QString profile = props.toElement().attribute("videoprofile");
-    int startPos = props.toElement().attribute("timeline_position").toInt();
-    infoXml.setAttribute("position", startPos);
-    if (profile == "dv_wide") profile = "dv_pal_wide";
-
-    // move playlists outside of tractor and add the tracks instead
-    int max = playlists.count();
-    if (westley.isNull())
-        westley = m_doc.elementsByTagName("westley").at(1);
-    if (westley.isNull()) {
-        westley = m_doc.createElement("mlt");
-        m_doc.documentElement().appendChild(westley);
-    }
-    if (tractor.isNull()) {
-        kDebug() << "// NO MLT PLAYLIST, building empty one";
-        QDomElement blank_tractor = m_doc.createElement("tractor");
-        westley.appendChild(blank_tractor);
-        QDomElement blank_playlist = m_doc.createElement("playlist");
-        blank_playlist.setAttribute("id", "black_track");
-        westley.insertBefore(blank_playlist, QDomNode());
-        QDomElement blank_track = m_doc.createElement("track");
-        blank_track.setAttribute("producer", "black_track");
-        blank_tractor.appendChild(blank_track);
-
-        QDomNodeList kdenlivetracks = m_doc.elementsByTagName("kdenlivetrack");
-        for (int i = 0; i < kdenlivetracks.count(); i++) {
-            blank_playlist = m_doc.createElement("playlist");
-            blank_playlist.setAttribute("id", "playlist" + QString::number(i));
-            westley.insertBefore(blank_playlist, QDomNode());
-            blank_track = m_doc.createElement("track");
-            blank_track.setAttribute("producer", "playlist" + QString::number(i));
-            blank_tractor.appendChild(blank_track);
-            if (kdenlivetracks.at(i).toElement().attribute("cliptype") == "Sound") {
-                blank_playlist.setAttribute("hide", "video");
-                blank_track.setAttribute("hide", "video");
-            }
-        }
-    } else for (int i = 0; i < max; i++) {
-            QDomNode n = playlists.at(i);
-            westley.insertBefore(n, QDomNode());
-            QDomElement pl = n.toElement();
-            QDomElement track = m_doc.createElement("track");
-            QString trackType = pl.attribute("hide");
-            if (!trackType.isEmpty())
-                track.setAttribute("hide", trackType);
-            QString playlist_id =  pl.attribute("id");
-            if (playlist_id.isEmpty()) {
-                playlist_id = "black_track";
-                pl.setAttribute("id", playlist_id);
-            }
-            track.setAttribute("producer", playlist_id);
-            //tractor.appendChild(track);
-#define KEEP_TRACK_ORDER 1
-#ifdef KEEP_TRACK_ORDER
-            tractor.insertAfter(track, QDomNode());
-#else
-            // 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());
-                            inserted = true;
-                            break;
-                        } else {
-                            kDebug() << "playlist_id: " << playlist_id << " producer:" << track_elem.attribute("producer");
-                            if (playlist_id < track_elem.attribute("producer")) {
-                                tractor.insertBefore(track, track_elem);
-                                inserted = true;
-                                break;
-                            }
-                        }
-                    }
-                    // Reach here, no insertion, insert last
-                    if (!inserted) {
-                        tractor.insertAfter(track, QDomNode());
-                    }
-                }
-            } else {
-                kWarning() << "tractor was not a QDomElement";
-                tractor.insertAfter(track, QDomNode());
-            }
-#endif
-        }
-    tractor.removeChild(multitrack);
-
-    // audio track mixing transitions should not be added to track view, so add required attribute
-    QDomNodeList transitions = m_doc.elementsByTagName("transition");
-    max = transitions.count();
-    for (int i = 0; i < max; i++) {
-        QDomElement tr = transitions.at(i).toElement();
-        if (tr.attribute("combine") == "1" && tr.attribute("mlt_service") == "mix") {
-            QDomElement property = m_doc.createElement("property");
-            property.setAttribute("name", "internal_added");
-            QDomText value = m_doc.createTextNode("237");
-            property.appendChild(value);
-            tr.appendChild(property);
-            property = m_doc.createElement("property");
-            property.setAttribute("name", "mlt_service");
-            value = m_doc.createTextNode("mix");
-            property.appendChild(value);
-            tr.appendChild(property);
-        } else {
-            // convert transition
-            QDomNamedNodeMap attrs = tr.attributes();
-            for (int j = 0; j < attrs.count(); j++) {
-                QString attrName = attrs.item(j).nodeName();
-                if (attrName != "in" && attrName != "out" && attrName != "id") {
-                    QDomElement property = m_doc.createElement("property");
-                    property.setAttribute("name", attrName);
-                    QDomText value = m_doc.createTextNode(attrs.item(j).nodeValue());
-                    property.appendChild(value);
-                    tr.appendChild(property);
-                }
-            }
-        }
-    }
-
-    // move transitions after tracks
-    for (int i = 0; i < max; i++) {
-        tractor.insertAfter(transitions.at(0), QDomNode());
-    }
-
-    // Fix filters format
-    QDomNodeList entries = m_doc.elementsByTagName("entry");
-    max = entries.count();
-    for (int i = 0; i < max; i++) {
-        QString last_id;
-        int effectix = 0;
-        QDomNode m = entries.at(i).firstChild();
-        while (!m.isNull()) {
-            if (m.toElement().tagName() == "filter") {
-                QDomElement filt = m.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(effectix));
-                e.appendChild(value);
-                filt.appendChild(e);
-                for (int j = 0; j < attrs.count(); j++) {
-                    QDomAttr a = attrs.item(j).toAttr();
-                    if (!a.isNull()) {
-                        kDebug() << " FILTER; adding :" << a.name() << ":" << a.value();
-                        QDomElement e = m_doc.createElement("property");
-                        e.setAttribute("name", a.name());
-                        QDomText value = m_doc.createTextNode(a.value());
-                        e.appendChild(value);
-                        filt.appendChild(e);
-
-                    }
-                }
-            }
-            m = m.nextSibling();
-        }
-    }
-
-    /*
-        QDomNodeList filters = m_doc.elementsByTagName("filter");
-        max = filters.count();
-        QString last_id;
-        int effectix = 0;
-        for (int i = 0; i < max; i++) {
-            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);
-            for (int j = 0; j < attrs.count(); j++) {
-                QDomAttr a = attrs.item(j).toAttr();
-                if (!a.isNull()) {
-                    kDebug() << " FILTER; adding :" << a.name() << ":" << a.value();
-                    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
-    QDomNodeList producers = westley.toElement().elementsByTagName("producer");
-    max = producers.count();
-    for (int i = 0; i < max; i++) {
-        QDomElement prod = producers.at(i).toElement();
-        if (prod.attribute("mlt_service") == "framebuffer") {
-            QString slowmotionprod = prod.attribute("resource");
-            slowmotionprod.replace(':', '?');
-            kDebug() << "// FOUND WRONG SLOWMO, new: " << slowmotionprod;
-            prod.setAttribute("resource", slowmotionprod);
-        }
-    }
-    // move producers to correct place, markers to a global list, fix clip descriptions
-    QDomElement markers = m_doc.createElement("markers");
-    // This will get the xml producers:
-    producers = m_doc.elementsByTagName("producer");
-    max = producers.count();
-    for (int i = 0; i < max; i++) {
-        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()) {
-            if (m.toElement().tagName() == "markers") {
-                QDomNodeList prodchilds = m.childNodes();
-                int maxchild = prodchilds.count();
-                for (int k = 0; k < maxchild; k++) {
-                    QDomElement mark = prodchilds.at(0).toElement();
-                    mark.setAttribute("id", prod.attribute("id"));
-                    markers.insertAfter(mark, QDomNode());
-                }
-                prod.removeChild(m);
-            } else if (prod.attribute("type").toInt() == TEXT) {
-                // convert title clip
-                if (m.toElement().tagName() == "textclip") {
-                    QDomDocument tdoc;
-                    QDomElement titleclip = m.toElement();
-                    QDomElement title = tdoc.createElement("kdenlivetitle");
-                    tdoc.appendChild(title);
-                    QDomNodeList objects = titleclip.childNodes();
-                    int maxchild = objects.count();
-                    for (int k = 0; k < maxchild; k++) {
-                        QString objectxml;
-                        QDomElement ob = objects.at(k).toElement();
-                        if (ob.attribute("type") == "3") {
-                            // text object - all of this goes into "xmldata"...
-                            QDomElement item = tdoc.createElement("item");
-                            item.setAttribute("z-index", ob.attribute("z"));
-                            item.setAttribute("type", "QGraphicsTextItem");
-                            QDomElement position = tdoc.createElement("position");
-                            position.setAttribute("x", ob.attribute("x"));
-                            position.setAttribute("y", ob.attribute("y"));
-                            QDomElement content = tdoc.createElement("content");
-                            content.setAttribute("font", ob.attribute("font_family"));
-                            content.setAttribute("font-size", ob.attribute("font_size"));
-                            content.setAttribute("font-bold", ob.attribute("bold"));
-                            content.setAttribute("font-italic", ob.attribute("italic"));
-                            content.setAttribute("font-underline", ob.attribute("underline"));
-                            QString col = ob.attribute("color");
-                            QColor c(col);
-                            content.setAttribute("font-color", colorToString(c));
-                            // todo: These fields are missing from the newly generated xmldata:
-                            // transform, startviewport, endviewport, background
-
-                            QDomText conttxt = tdoc.createTextNode(ob.attribute("text"));
-                            content.appendChild(conttxt);
-                            item.appendChild(position);
-                            item.appendChild(content);
-                            title.appendChild(item);
-                        } else if (ob.attribute("type") == "5") {
-                            // rectangle object
-                            QDomElement item = tdoc.createElement("item");
-                            item.setAttribute("z-index", ob.attribute("z"));
-                            item.setAttribute("type", "QGraphicsRectItem");
-                            QDomElement position = tdoc.createElement("position");
-                            position.setAttribute("x", ob.attribute("x"));
-                            position.setAttribute("y", ob.attribute("y"));
-                            QDomElement content = tdoc.createElement("content");
-                            QString col = ob.attribute("color");
-                            QColor c(col);
-                            content.setAttribute("brushcolor", colorToString(c));
-                            QString rect = "0,0,";
-                            rect.append(ob.attribute("width"));
-                            rect.append(",");
-                            rect.append(ob.attribute("height"));
-                            content.setAttribute("rect", rect);
-                            item.appendChild(position);
-                            item.appendChild(content);
-                            title.appendChild(item);
-                        }
-                    }
-                    prod.setAttribute("xmldata", tdoc.toString());
-                    // 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));
-                    //kDebug()<<"TITLE DATA:\n"<<tdoc.toString();
-                    prod.removeChild(m);
-                } // End conversion of title clips.
-
-            } else if (m.isText()) {
-                QString comment = m.nodeValue();
-                if (!comment.isEmpty()) {
-                    prod.setAttribute("description", comment);
-                }
-                prod.removeChild(m);
-            }
-        }
-        int duration = prod.attribute("duration").toInt();
-        if (duration > 0) prod.setAttribute("out", QString::number(duration));
-        // The clip goes back in, but text clips should not go back in, at least not modified
-        westley.insertBefore(prod, QDomNode());
-
-    }
-
-    QDomNode westley0 = m_doc.elementsByTagName("westley").at(0);
-    if (!markers.firstChild().isNull()) westley0.appendChild(markers);
-
-
-    // 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(kdenlivedoc);
-    QDomElement kdenlivedoc_new = m_doc.createElement("kdenlivedoc");
-    kdenlivedoc_new.setAttribute("profile", profile);
-
-    // Add tracks info
-    QDomNodeList tracks = m_doc.elementsByTagName("track");
-    max = tracks.count();
-    QDomElement tracksinfo = m_doc.createElement("tracksinfo");
-    for (int i = 0; i < max; i++) {
-        QDomElement trackinfo = m_doc.createElement("trackinfo");
-        QDomElement t = tracks.at(i).toElement();
-        if (t.attribute("hide") == "video") {
-            trackinfo.setAttribute("type", "audio");
-            trackinfo.setAttribute("blind", true);
-        } else trackinfo.setAttribute("blind", false);
-        trackinfo.setAttribute("mute", false);
-        trackinfo.setAttribute("locked", false);
-        if (t.attribute("producer") != "black_track") tracksinfo.appendChild(trackinfo);
-    }
-    kdenlivedoc_new.appendChild(tracksinfo);
-
-    // Add all the producers that has a resource in westley
-    QDomElement westley_element = westley0.toElement();
-    if (westley_element.isNull()) {
-        kWarning() << "westley0 element in document was not a QDomElement - unable to add producers to new kdenlivedoc";
-    } else {
-        QDomNodeList wproducers = westley_element.elementsByTagName("producer");
-        int kmax = wproducers.count();
-        for (int i = 0; i < kmax; i++) {
-            QDomElement wproducer = wproducers.at(i).toElement();
-            if (wproducer.isNull()) {
-                kWarning() << "Found producer in westley0, that was not a QDomElement";
-                continue;
-            }
-            if (wproducer.attribute("id") == "black") continue;
-            // We have to do slightly different things, depending on the type
-            kDebug() << "Converting producer element with type" << wproducer.attribute("type");
-            if (wproducer.attribute("type").toInt() == TEXT) {
-                kDebug() << "Found TEXT element in producer" << endl;
-                QDomElement kproducer = wproducer.cloneNode(true).toElement();
-                kproducer.setTagName("kdenlive_producer");
-                kdenlivedoc_new.appendChild(kproducer);
-                // TODO: Perhaps needs some more changes here to "frequency", aspect ratio as a float, frame_size, channels, and later, ressource and title name
-            } else {
-                QDomElement kproducer = m_doc.createElement("kdenlive_producer");
-                kproducer.setAttribute("id", wproducer.attribute("id"));
-                if (!wproducer.attribute("description").isEmpty())
-                    kproducer.setAttribute("description", wproducer.attribute("description"));
-                kproducer.setAttribute("resource", wproducer.attribute("resource"));
-                kproducer.setAttribute("type", wproducer.attribute("type"));
-                // Testing fix for 358
-                if (!wproducer.attribute("aspect_ratio").isEmpty()) {
-                    kproducer.setAttribute("aspect_ratio", wproducer.attribute("aspect_ratio"));
-                }
-                if (!wproducer.attribute("source_fps").isEmpty()) {
-                    kproducer.setAttribute("fps", wproducer.attribute("source_fps"));
-                }
-                if (!wproducer.attribute("length").isEmpty()) {
-                    kproducer.setAttribute("duration", wproducer.attribute("length"));
-                }
-                kdenlivedoc_new.appendChild(kproducer);
-            }
-            if (wproducer.attribute("id").toInt() > max_kproducer_id) {
-                max_kproducer_id = wproducer.attribute("id").toInt();
-            }
-        }
-    }
-#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 folders shows up missing, and clips with no folder
-    // does not show up.
-    //    QDomElement kdenlivedoc_old = kdenlivedoc.toElement();
-    if (!kdenlivedoc_old.isNull()) {
-        QDomNodeList folders = kdenlivedoc_old.elementsByTagName("folder");
-        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()) {
-                QString groupName = folder.attribute("name");
-                kDebug() << "groupName: " << groupName << " with groupId: " << groupId;
-                QDomNodeList fproducers = folder.elementsByTagName("producer");
-                int psize = fproducers.size();
-                for (int j = 0; j < psize; ++j) {
-                    QDomElement fproducer = fproducers.at(j).toElement();
-                    if (!fproducer.isNull()) {
-                        QString id = fproducer.attribute("id");
-                        // This is not very effective, but compared to loading the clips, its a breeze
-                        QDomNodeList kdenlive_producers = kdenlivedoc_new.elementsByTagName("kdenlive_producer");
-                        int kpsize = kdenlive_producers.size();
-                        for (int k = 0; k < kpsize; ++k) {
-                            QDomElement kproducer = kdenlive_producers.at(k).toElement(); // Its an element for sure
-                            if (id == kproducer.attribute("id")) {
-                                // We do not check that it already is part of a folder
-                                kproducer.setAttribute("groupid", groupId);
-                                kproducer.setAttribute("groupname", groupName);
-                                break;
-                            }
-                        }
-                    }
-                }
-                ++groupId;
-            }
-        }
-    }
-#endif
-    westley0.appendChild(kdenlivedoc_new);
-
-    QDomNodeList elements = westley.childNodes();
-    max = elements.count();
-    for (int i = 0; i < max; i++) {
-        QDomElement prod = elements.at(0).toElement();
-        westley0.insertAfter(prod, QDomNode());
-    }
-
-    westley0.removeChild(westley);
-
-    // experimental and probably slow
-    // adds <avfile /> information to <kdenlive_producer />
-    QDomNodeList kproducers = m_doc.elementsByTagName("kdenlive_producer");
-    QDomNodeList avfiles = kdenlivedoc_old.elementsByTagName("avfile");
-    kDebug() << "found" << avfiles.count() << "<avfile />s and" << kproducers.count() << "<kdenlive_producer />s";
-    for (int i = 0; i < avfiles.count(); ++i) {
-        QDomElement avfile = avfiles.at(i).toElement();
-        QDomElement kproducer;
-        if (avfile.isNull())
-            kWarning() << "found an <avfile /> that is not a QDomElement";
-        else {
-            QString id = avfile.attribute("id");
-            // this is horrible, must be rewritten, it's just for test
-            for (int j = 0; j < kproducers.count(); ++j) {
-                //kDebug() << "checking <kdenlive_producer /> with id" << kproducers.at(j).toElement().attribute("id");
-                if (kproducers.at(j).toElement().attribute("id") == id) {
-                    kproducer = kproducers.at(j).toElement();
-                    break;
-                }
-            }
-            if (kproducer == QDomElement())
-                kWarning() << "no match for <avfile /> with id =" << id;
-            else {
-                //kDebug() << "ready to set additional <avfile />'s attributes (id =" << id << ")";
-                kproducer.setAttribute("channels", avfile.attribute("channels"));
-                kproducer.setAttribute("duration", avfile.attribute("duration"));
-                kproducer.setAttribute("frame_size", avfile.attribute("width") + 'x' + avfile.attribute("height"));
-                kproducer.setAttribute("frequency", avfile.attribute("frequency"));
-                if (kproducer.attribute("description").isEmpty() && !avfile.attribute("description").isEmpty())
-                    kproducer.setAttribute("description", avfile.attribute("description"));
-            }
-        }
-    }
-
-    /*kDebug() << "/////////////////  CONVERTED DOC:";
-    kDebug() << m_doc.toString();
-    kDebug() << "/////////////////  END CONVERTED DOC:";
-
-    QFile file("converted.kdenlive");
-    if (file.open(QIODevice::WriteOnly)) {
-        QTextStream stream(&file);
-        stream << m_doc.toString().toUtf8();
-        file.close();
-    } else {
-        kDebug() << "Unable to dump file to converted.kdenlive";
-    }*/
-
-    //kDebug() << "/////////////////  END CONVERTED DOC:";
-    convertToMelt();
-    return true;
-}
-
-QString DocumentConvert::colorToString(const QColor& c)
-{
-    QString ret = "%1,%2,%3,%4";
-    ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
-    return ret;
-}
-
-bool DocumentConvert::isModified() const
-{
-    return m_modified;
-}
-
-void DocumentConvert::convertToMelt()
-{
-    QDomNodeList list = m_doc.elementsByTagName("westley");
-    int max = list.count();
-    for (int i = 0; i < max; i++) {
-        QDomElement elem = list.at(i).toElement();
-        elem.setTagName("mlt");
-    }
-}
-
diff --git a/src/documentvalidator.cpp b/src/documentvalidator.cpp
new file mode 100644 (file)
index 0000000..fd10011
--- /dev/null
@@ -0,0 +1,695 @@
+/***************************************************************************
+ *   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          *
+ ***************************************************************************/
+
+
+#include "documentvalidator.h"
+#include "definitions.h"
+
+#include <KDebug>
+#include <KMessageBox>
+#include <KApplication>
+#include <KLocale>
+
+#include <QColor>
+
+DocumentValidator::DocumentValidator(QDomDocument doc):
+        m_doc(doc),
+        m_modified(false)
+{}
+
+bool DocumentValidator::validate(const double currentVersion)
+{
+    // Check if we're validating a Kdenlive project
+    if (!isProject())
+        return false;
+
+    // Upgrade the document to the latest version
+    QDomNode kdenlivedocNode = m_doc.elementsByTagName("kdenlivedoc").at(0);
+    QDomElement kdenlivedocElm = kdenlivedocNode.toElement();
+    if (!upgrade(kdenlivedocElm.attribute("version").toDouble(), currentVersion))
+        return false;
+
+       /*
+     * Check the syntax (this will be replaced by XSD validation with Qt 4.6)
+     * and correct some errors
+     */
+    QDomNode mltNode = m_doc.elementsByTagName("mlt").at(0);
+    QDomElement mltElm = mltNode.toElement();
+    if (mltElm.isNull()) // At least the root element must be there
+        return false;
+    else {
+        // Return (or create) the tractor
+        QDomNode tractorNode = m_doc.elementsByTagName("tractor").at(0);
+        QDomElement tractorElm = tractorNode.toElement();
+        if (tractorElm.isNull()) {
+            m_modified = true;
+            tractorElm = m_doc.createElement("tractor");
+            tractorElm.setAttribute("global_feed", "1");
+            tractorElm.setAttribute("in", "0");
+            tractorElm.setAttribute("out", "-1");
+            tractorElm.setAttribute("id", "maintractor");
+            mltElm.appendChild(tractorElm);
+        }
+
+        /*
+         * Make sure at least one track exists, and they're equal in number to
+         * to the maximum between MLT and Kdenlive playlists and tracks
+         */
+        QDomNodeList playlists = m_doc.elementsByTagName("playlist");
+        int tracksMax = playlists.count() - 1; // Remove the black track
+        QDomNodeList tracks = m_doc.elementsByTagName("track");
+        tracksMax = qMax(tracks.count() - 1, tracksMax);
+        QDomNodeList tracksinfo = m_doc.elementsByTagName("trackinfo");
+        tracksMax = qMax(tracksinfo.count(), tracksMax);
+        tracksMax = qMax(1, tracksMax); // Force existance of one track
+        if (playlists.count() - 1 < tracksMax ||
+            tracks.count() - 1 < tracksMax ||
+            tracksinfo.count() < tracksMax) {
+            m_modified = true;
+            int difference;
+            if (playlists.count() - 1 < tracksMax) {
+                difference = tracksMax - (playlists.count() - 1);
+                for (int i = 0; i < difference; ++i) {
+                    QDomElement playlist = m_doc.createElement("playlist");
+                    mltElm.appendChild(playlist);
+                }
+            }
+            if (tracks.count() - 1 < tracksMax) {
+                difference = tracksMax - (tracks.count() - 1);
+                for (int i = 0; i < difference; ++i) {
+                    QDomElement track = m_doc.createElement("track");
+                    tractorElm.appendChild(track);
+                }
+            }
+            if (tracksinfo.count() < tracksMax) {
+                QDomNode tracksinfoNode = m_doc.elementsByTagName("tracksinfo").at(0);
+                QDomElement tracksinfoElm = tracksinfoNode.toElement();
+                if (tracksinfoElm.isNull()) {
+                    tracksinfoElm = m_doc.createElement("tracksinfo");
+                    kdenlivedocElm.appendChild(tracksinfoElm);
+                }
+                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);
+                }
+            }
+        }
+
+        // TODO: check the tracks references
+        // TODO: check internal mix transitions
+    }
+
+    return true;
+}
+
+bool DocumentValidator::upgrade(double version, const double currentVersion)
+{
+    kDebug() << "Opening a document with version " << version;
+
+    // No conversion needed
+    if (version == currentVersion)
+        return true;
+
+    // The document is too new
+    if (version > currentVersion) {
+        kDebug() << "Unable to open document with version " << version;
+        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"));
+        return false;
+    }
+
+    // <kdenlivedoc />
+    QDomNode infoXmlNode = m_doc.elementsByTagName("kdenlivedoc").at(0);
+    QDomElement infoXml = infoXmlNode.toElement();
+
+    // Unsupported document versions
+    if (version == 0.5 || version == 0.7) {
+        kDebug() << "Unable to open document with version " << version;
+        KMessageBox::sorry(kapp->activeWindow(), i18n("This project type is unsupported (version %1) and can't be loaded.", version), i18n("Unable to open project"));
+        return false;
+    }
+
+    if (version <= 0.6) {
+        QDomElement infoXml_old = infoXmlNode.cloneNode(true).toElement(); // Needed for folders
+        QDomNode westley = m_doc.elementsByTagName("westley").at(1);
+        QDomNode tractor = m_doc.elementsByTagName("tractor").at(0);
+        QDomNode multitrack = m_doc.elementsByTagName("multitrack").at(0);
+        QDomNodeList playlists = m_doc.elementsByTagName("playlist");
+
+        QDomNode props = m_doc.elementsByTagName("properties").at(0).toElement();
+        QString profile = props.toElement().attribute("videoprofile");
+        int startPos = props.toElement().attribute("timeline_position").toInt();
+        if (profile == "dv_wide")
+            profile = "dv_pal_wide";
+
+        // move playlists outside of tractor and add the tracks instead
+        int max = playlists.count();
+        if (westley.isNull()) {
+            westley = m_doc.createElement("westley");
+            m_doc.documentElement().appendChild(westley);
+        }
+        if (tractor.isNull()) {
+            kDebug() << "// NO MLT PLAYLIST, building empty one";
+            QDomElement blank_tractor = m_doc.createElement("tractor");
+            westley.appendChild(blank_tractor);
+            QDomElement blank_playlist = m_doc.createElement("playlist");
+            blank_playlist.setAttribute("id", "black_track");
+            westley.insertBefore(blank_playlist, QDomNode());
+            QDomElement blank_track = m_doc.createElement("track");
+            blank_track.setAttribute("producer", "black_track");
+            blank_tractor.appendChild(blank_track);
+
+            QDomNodeList kdenlivetracks = m_doc.elementsByTagName("kdenlivetrack");
+            for (int i = 0; i < kdenlivetracks.count(); i++) {
+                blank_playlist = m_doc.createElement("playlist");
+                blank_playlist.setAttribute("id", "playlist" + QString::number(i));
+                westley.insertBefore(blank_playlist, QDomNode());
+                blank_track = m_doc.createElement("track");
+                blank_track.setAttribute("producer", "playlist" + QString::number(i));
+                blank_tractor.appendChild(blank_track);
+                if (kdenlivetracks.at(i).toElement().attribute("cliptype") == "Sound") {
+                    blank_playlist.setAttribute("hide", "video");
+                    blank_track.setAttribute("hide", "video");
+                }
+            }
+        } else for (int i = 0; i < max; i++) {
+            QDomNode n = playlists.at(i);
+            westley.insertBefore(n, QDomNode());
+            QDomElement pl = n.toElement();
+            QDomElement track = m_doc.createElement("track");
+            QString trackType = pl.attribute("hide");
+            if (!trackType.isEmpty())
+                track.setAttribute("hide", trackType);
+            QString playlist_id =  pl.attribute("id");
+            if (playlist_id.isEmpty()) {
+                playlist_id = "black_track";
+                pl.setAttribute("id", playlist_id);
+            }
+            track.setAttribute("producer", playlist_id);
+            //tractor.appendChild(track);
+#define KEEP_TRACK_ORDER 1
+#ifdef KEEP_TRACK_ORDER
+            tractor.insertAfter(track, QDomNode());
+#else
+            // 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());
+                            inserted = true;
+                            break;
+                        } else {
+                            kDebug() << "playlist_id: " << playlist_id << " producer:" << track_elem.attribute("producer");
+                            if (playlist_id < track_elem.attribute("producer")) {
+                                tractor.insertBefore(track, track_elem);
+                                inserted = true;
+                                break;
+                            }
+                        }
+                    }
+                    // Reach here, no insertion, insert last
+                    if (!inserted) {
+                        tractor.insertAfter(track, QDomNode());
+                    }
+                }
+            } else {
+                kWarning() << "tractor was not a QDomElement";
+                tractor.insertAfter(track, QDomNode());
+            }
+#endif
+        }
+        tractor.removeChild(multitrack);
+
+        // audio track mixing transitions should not be added to track view, so add required attribute
+        QDomNodeList transitions = m_doc.elementsByTagName("transition");
+        max = transitions.count();
+        for (int i = 0; i < max; i++) {
+            QDomElement tr = transitions.at(i).toElement();
+            if (tr.attribute("combine") == "1" && tr.attribute("mlt_service") == "mix") {
+                QDomElement property = m_doc.createElement("property");
+                property.setAttribute("name", "internal_added");
+                QDomText value = m_doc.createTextNode("237");
+                property.appendChild(value);
+                tr.appendChild(property);
+                property = m_doc.createElement("property");
+                property.setAttribute("name", "mlt_service");
+                value = m_doc.createTextNode("mix");
+                property.appendChild(value);
+                tr.appendChild(property);
+            } else {
+                // convert transition
+                QDomNamedNodeMap attrs = tr.attributes();
+                for (int j = 0; j < attrs.count(); j++) {
+                    QString attrName = attrs.item(j).nodeName();
+                    if (attrName != "in" && attrName != "out" && attrName != "id") {
+                        QDomElement property = m_doc.createElement("property");
+                        property.setAttribute("name", attrName);
+                        QDomText value = m_doc.createTextNode(attrs.item(j).nodeValue());
+                        property.appendChild(value);
+                        tr.appendChild(property);
+                    }
+                }
+            }
+        }
+
+        // move transitions after tracks
+        for (int i = 0; i < max; i++) {
+            tractor.insertAfter(transitions.at(0), QDomNode());
+        }
+
+        // Fix filters format
+        QDomNodeList entries = m_doc.elementsByTagName("entry");
+        max = entries.count();
+        for (int i = 0; i < max; i++) {
+            QString last_id;
+            int effectix = 0;
+            QDomNode m = entries.at(i).firstChild();
+            while (!m.isNull()) {
+                if (m.toElement().tagName() == "filter") {
+                    QDomElement filt = m.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(effectix));
+                    e.appendChild(value);
+                    filt.appendChild(e);
+                    for (int j = 0; j < attrs.count(); j++) {
+                        QDomAttr a = attrs.item(j).toAttr();
+                        if (!a.isNull()) {
+                            kDebug() << " FILTER; adding :" << a.name() << ":" << a.value();
+                            QDomElement e = m_doc.createElement("property");
+                            e.setAttribute("name", a.name());
+                            QDomText value = m_doc.createTextNode(a.value());
+                            e.appendChild(value);
+                            filt.appendChild(e);
+
+                        }
+                    }
+                }
+                m = m.nextSibling();
+            }
+        }
+
+        /*
+            QDomNodeList filters = m_doc.elementsByTagName("filter");
+            max = filters.count();
+            QString last_id;
+            int effectix = 0;
+            for (int i = 0; i < max; i++) {
+                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);
+                for (int j = 0; j < attrs.count(); j++) {
+                    QDomAttr a = attrs.item(j).toAttr();
+                    if (!a.isNull()) {
+                        kDebug() << " FILTER; adding :" << a.name() << ":" << a.value();
+                        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
+        QDomNodeList producers = westley.toElement().elementsByTagName("producer");
+        max = producers.count();
+        for (int i = 0; i < max; i++) {
+            QDomElement prod = producers.at(i).toElement();
+            if (prod.attribute("mlt_service") == "framebuffer") {
+                QString slowmotionprod = prod.attribute("resource");
+                slowmotionprod.replace(':', '?');
+                kDebug() << "// FOUND WRONG SLOWMO, new: " << slowmotionprod;
+                prod.setAttribute("resource", slowmotionprod);
+            }
+        }
+        // move producers to correct place, markers to a global list, fix clip descriptions
+        QDomElement markers = m_doc.createElement("markers");
+        // This will get the xml producers:
+        producers = m_doc.elementsByTagName("producer");
+        max = producers.count();
+        for (int i = 0; i < max; i++) {
+            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()) {
+                if (m.toElement().tagName() == "markers") {
+                    QDomNodeList prodchilds = m.childNodes();
+                    int maxchild = prodchilds.count();
+                    for (int k = 0; k < maxchild; k++) {
+                        QDomElement mark = prodchilds.at(0).toElement();
+                        mark.setAttribute("id", prod.attribute("id"));
+                        markers.insertAfter(mark, QDomNode());
+                    }
+                    prod.removeChild(m);
+                } else if (prod.attribute("type").toInt() == TEXT) {
+                    // convert title clip
+                    if (m.toElement().tagName() == "textclip") {
+                        QDomDocument tdoc;
+                        QDomElement titleclip = m.toElement();
+                        QDomElement title = tdoc.createElement("kdenlivetitle");
+                        tdoc.appendChild(title);
+                        QDomNodeList objects = titleclip.childNodes();
+                        int maxchild = objects.count();
+                        for (int k = 0; k < maxchild; k++) {
+                            QString objectxml;
+                            QDomElement ob = objects.at(k).toElement();
+                            if (ob.attribute("type") == "3") {
+                                // text object - all of this goes into "xmldata"...
+                                QDomElement item = tdoc.createElement("item");
+                                item.setAttribute("z-index", ob.attribute("z"));
+                                item.setAttribute("type", "QGraphicsTextItem");
+                                QDomElement position = tdoc.createElement("position");
+                                position.setAttribute("x", ob.attribute("x"));
+                                position.setAttribute("y", ob.attribute("y"));
+                                QDomElement content = tdoc.createElement("content");
+                                content.setAttribute("font", ob.attribute("font_family"));
+                                content.setAttribute("font-size", ob.attribute("font_size"));
+                                content.setAttribute("font-bold", ob.attribute("bold"));
+                                content.setAttribute("font-italic", ob.attribute("italic"));
+                                content.setAttribute("font-underline", ob.attribute("underline"));
+                                QString col = ob.attribute("color");
+                                QColor c(col);
+                                content.setAttribute("font-color", colorToString(c));
+                                // todo: These fields are missing from the newly generated xmldata:
+                                // transform, startviewport, endviewport, background
+
+                                QDomText conttxt = tdoc.createTextNode(ob.attribute("text"));
+                                content.appendChild(conttxt);
+                                item.appendChild(position);
+                                item.appendChild(content);
+                                title.appendChild(item);
+                            } else if (ob.attribute("type") == "5") {
+                                // rectangle object
+                                QDomElement item = tdoc.createElement("item");
+                                item.setAttribute("z-index", ob.attribute("z"));
+                                item.setAttribute("type", "QGraphicsRectItem");
+                                QDomElement position = tdoc.createElement("position");
+                                position.setAttribute("x", ob.attribute("x"));
+                                position.setAttribute("y", ob.attribute("y"));
+                                QDomElement content = tdoc.createElement("content");
+                                QString col = ob.attribute("color");
+                                QColor c(col);
+                                content.setAttribute("brushcolor", colorToString(c));
+                                QString rect = "0,0,";
+                                rect.append(ob.attribute("width"));
+                                rect.append(",");
+                                rect.append(ob.attribute("height"));
+                                content.setAttribute("rect", rect);
+                                item.appendChild(position);
+                                item.appendChild(content);
+                                title.appendChild(item);
+                            }
+                        }
+                        prod.setAttribute("xmldata", tdoc.toString());
+                        // 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));
+                        //kDebug()<<"TITLE DATA:\n"<<tdoc.toString();
+                        prod.removeChild(m);
+                    } // End conversion of title clips.
+
+                } else if (m.isText()) {
+                    QString comment = m.nodeValue();
+                    if (!comment.isEmpty()) {
+                        prod.setAttribute("description", comment);
+                    }
+                    prod.removeChild(m);
+                }
+            }
+            int duration = prod.attribute("duration").toInt();
+            if (duration > 0) prod.setAttribute("out", QString::number(duration));
+            // The clip goes back in, but text clips should not go back in, at least not modified
+            westley.insertBefore(prod, QDomNode());
+        }
+
+        QDomNode westley0 = m_doc.elementsByTagName("westley").at(0);
+        if (!markers.firstChild().isNull()) westley0.appendChild(markers);
+
+        /*
+         * 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);
+        QDomElement infoXml_new = m_doc.createElement("kdenlivedoc");
+        infoXml_new.setAttribute("profile", profile);
+        infoXml.setAttribute("position", startPos);
+
+        // Add all the producers that has a resource in westley
+        QDomElement westley_element = westley0.toElement();
+        if (westley_element.isNull()) {
+            kWarning() << "westley0 element in document was not a QDomElement - unable to add producers to new kdenlivedoc";
+        } else {
+            QDomNodeList wproducers = westley_element.elementsByTagName("producer");
+            int kmax = wproducers.count();
+            for (int i = 0; i < kmax; i++) {
+                QDomElement wproducer = wproducers.at(i).toElement();
+                if (wproducer.isNull()) {
+                    kWarning() << "Found producer in westley0, that was not a QDomElement";
+                    continue;
+                }
+                if (wproducer.attribute("id") == "black") continue;
+                // We have to do slightly different things, depending on the type
+                kDebug() << "Converting producer element with type" << wproducer.attribute("type");
+                if (wproducer.attribute("type").toInt() == TEXT) {
+                    kDebug() << "Found TEXT element in producer" << endl;
+                    QDomElement kproducer = wproducer.cloneNode(true).toElement();
+                    kproducer.setTagName("kdenlive_producer");
+                    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 {
+                    QDomElement kproducer = m_doc.createElement("kdenlive_producer");
+                    kproducer.setAttribute("id", wproducer.attribute("id"));
+                    if (!wproducer.attribute("description").isEmpty())
+                        kproducer.setAttribute("description", wproducer.attribute("description"));
+                    kproducer.setAttribute("resource", wproducer.attribute("resource"));
+                    kproducer.setAttribute("type", wproducer.attribute("type"));
+                    // Testing fix for 358
+                    if (!wproducer.attribute("aspect_ratio").isEmpty()) {
+                        kproducer.setAttribute("aspect_ratio", wproducer.attribute("aspect_ratio"));
+                    }
+                    if (!wproducer.attribute("source_fps").isEmpty()) {
+                        kproducer.setAttribute("fps", wproducer.attribute("source_fps"));
+                    }
+                    if (!wproducer.attribute("length").isEmpty()) {
+                        kproducer.setAttribute("duration", wproducer.attribute("length"));
+                    }
+                    infoXml_new.appendChild(kproducer);
+                }
+                if (wproducer.attribute("id").toInt() > max_kproducer_id) {
+                    max_kproducer_id = wproducer.attribute("id").toInt();
+                }
+            }
+        }
+#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()) {
+            QDomNodeList folders = infoXml_old.elementsByTagName("folder");
+            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()) {
+                    QString groupName = folder.attribute("name");
+                    kDebug() << "groupName: " << groupName << " with groupId: " << groupId;
+                    QDomNodeList fproducers = folder.elementsByTagName("producer");
+                    int psize = fproducers.size();
+                    for (int j = 0; j < psize; ++j) {
+                        QDomElement fproducer = fproducers.at(j).toElement();
+                        if (!fproducer.isNull()) {
+                            QString id = fproducer.attribute("id");
+                            // This is not very effective, but compared to loading the clips, its a breeze
+                            QDomNodeList kdenlive_producers = infoXml_new.elementsByTagName("kdenlive_producer");
+                            int kpsize = kdenlive_producers.size();
+                            for (int k = 0; k < kpsize; ++k) {
+                                QDomElement kproducer = kdenlive_producers.at(k).toElement(); // Its an element for sure
+                                if (id == kproducer.attribute("id")) {
+                                    // We do not check that it already is part of a folder
+                                    kproducer.setAttribute("groupid", groupId);
+                                    kproducer.setAttribute("groupname", groupName);
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    ++groupId;
+                }
+            }
+        }
+#endif
+        QDomNodeList elements = westley.childNodes();
+        max = elements.count();
+        for (int i = 0; i < max; i++) {
+            QDomElement prod = elements.at(0).toElement();
+            westley0.insertAfter(prod, QDomNode());
+        }
+
+        westley0.appendChild(infoXml_new);
+
+        westley0.removeChild(westley);
+
+        // adds <avfile /> information to <kdenlive_producer />
+        QDomNodeList kproducers = m_doc.elementsByTagName("kdenlive_producer");
+        QDomNodeList avfiles = infoXml_old.elementsByTagName("avfile");
+        kDebug() << "found" << avfiles.count() << "<avfile />s and" << kproducers.count() << "<kdenlive_producer />s";
+        for (int i = 0; i < avfiles.count(); ++i) {
+            QDomElement avfile = avfiles.at(i).toElement();
+            QDomElement kproducer;
+            if (avfile.isNull())
+                kWarning() << "found an <avfile /> that is not a QDomElement";
+            else {
+                QString id = avfile.attribute("id");
+                // this is horrible, must be rewritten, it's just for test
+                for (int j = 0; j < kproducers.count(); ++j) {
+                    //kDebug() << "checking <kdenlive_producer /> with id" << kproducers.at(j).toElement().attribute("id");
+                    if (kproducers.at(j).toElement().attribute("id") == id) {
+                        kproducer = kproducers.at(j).toElement();
+                        break;
+                    }
+                }
+                if (kproducer == QDomElement())
+                    kWarning() << "no match for <avfile /> with id =" << id;
+                else {
+                    //kDebug() << "ready to set additional <avfile />'s attributes (id =" << id << ")";
+                    kproducer.setAttribute("channels", avfile.attribute("channels"));
+                    kproducer.setAttribute("duration", avfile.attribute("duration"));
+                    kproducer.setAttribute("frame_size", avfile.attribute("width") + 'x' + avfile.attribute("height"));
+                    kproducer.setAttribute("frequency", avfile.attribute("frequency"));
+                    if (kproducer.attribute("description").isEmpty() && !avfile.attribute("description").isEmpty())
+                        kproducer.setAttribute("description", avfile.attribute("description"));
+                }
+            }
+        }
+        infoXml = infoXml_new;
+    }
+
+    if (version <= 0.81) {
+        // Add the tracks information
+        QString tracksOrder = infoXml.attribute("tracks");
+        if (tracksOrder.isEmpty()) {
+            QDomNodeList tracks = m_doc.elementsByTagName("track");
+            for (int i = 0; i < tracks.count(); i++) {
+                QDomElement track = tracks.at(i).toElement();
+                if (track.attribute("producer") != "black_track") {
+                    if (track.attribute("hide") == "video")
+                        tracksOrder.append('a');
+                    else
+                        tracksOrder.append('v');
+                }
+            }
+        }
+        QDomElement tracksinfo = m_doc.createElement("tracksinfo");
+        for (int i = 0; i < tracksOrder.size(); i++) {
+            QDomElement trackinfo = m_doc.createElement("trackinfo");
+            if (tracksOrder.data()[i] == 'a') {
+                trackinfo.setAttribute("type", "audio");
+                trackinfo.setAttribute("blind", true);
+            } else
+                trackinfo.setAttribute("blind", false);
+            trackinfo.setAttribute("mute", false);
+            trackinfo.setAttribute("locked", false);
+            tracksinfo.appendChild(trackinfo);
+        }
+        infoXml.appendChild(tracksinfo);
+    }
+
+    if (version <= 0.82) {
+        // Convert <westley />s in <mlt />s (MLT extreme makeover)
+        QDomNodeList westleyNodes = m_doc.elementsByTagName("westley");
+        for (int i = 0; i < westleyNodes.count(); i++) {
+            QDomElement westley = westleyNodes.at(i).toElement();
+            westley.setTagName("mlt");
+        }
+    }
+
+    // The document has been converted: mark it as modified
+    infoXml.setAttribute("version", currentVersion);
+    m_modified = true;
+
+    return true;
+}
+
+QString DocumentValidator::colorToString(const QColor& c)
+{
+    QString ret = "%1,%2,%3,%4";
+    ret = ret.arg(c.red()).arg(c.green()).arg(c.blue()).arg(c.alpha());
+    return ret;
+}
+
+bool DocumentValidator::isProject() const
+{
+    QDomNode infoXmlNode = m_doc.elementsByTagName("kdenlivedoc").at(0);
+    return !infoXmlNode.isNull();
+}
+
+bool DocumentValidator::isModified() const
+{
+    return m_modified;
+}
similarity index 85%
rename from src/documentconvert.h
rename to src/documentvalidator.h
index a06d85b0c6e8a259db162d3b4add8a20e603e667..680af5467023e79d82b9ce9a1774e76e3ed70a36 100644 (file)
  ***************************************************************************/
 
 
-#ifndef DOCUMENTCONVERT_H
-#define DOCUMENTCONVERT_H
+#ifndef DOCUMENTVALIDATOR_H
+#define DOCUMENTVALIDATOR_H
 
 #include <QDomDocument>
 #include <QColor>
 
-class DocumentConvert
+class DocumentValidator
 {
 
 public:
-    DocumentConvert(QDomDocument doc);
-    bool doConvert(double version, const double current_version);
+    DocumentValidator(QDomDocument doc);
+    bool isProject() const;
+    bool validate(const double currentVersion);
     bool isModified() const;
 
 private:
     bool m_modified;
     QDomDocument m_doc;
+    bool upgrade(double version, const double currentVersion);
     QString colorToString(const QColor& c);
-    void convertToMelt();
 };
 
 #endif
index 9eda3d36f5493f4867ae912d408739cea3d9840b..d746f87bedbacc20724210eb131d6b635b34f093 100644 (file)
@@ -27,7 +27,7 @@
 #include "titlewidget.h"
 #include "mainwindow.h"
 #include "documentchecker.h"
-#include "documentconvert.h"
+#include "documentvalidator.h"
 #include "kdenlive-config.h"
 
 #include <KDebug>
@@ -65,180 +65,166 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
     m_clipManager = new ClipManager(this);
     m_autoSaveTimer = new QTimer(this);
     m_autoSaveTimer->setSingleShot(true);
+    bool success = false;
     if (!url.isEmpty()) {
         QString tmpFile;
-        bool success = KIO::NetAccess::download(url.path(), tmpFile, parent);
-        if (success) {
+        success = KIO::NetAccess::download(url.path(), tmpFile, parent);
+        if (!success) // The file cannot be opened
+            KMessageBox::error(parent, KIO::NetAccess::lastErrorString());
+        else {
             QFile file(tmpFile);
             QString errorMsg;
             success = m_document.setContent(&file, false, &errorMsg);
             file.close();
-            if (success == false) {
-                // File is corrupted, warn user
+            KIO::NetAccess::removeTempFile(tmpFile);
+            if (!success) // It is corrupted
                 KMessageBox::error(parent, errorMsg);
-            }
-        } else KMessageBox::error(parent, KIO::NetAccess::lastErrorString());
-
-        if (success) {
-            QDomNode infoXmlNode = m_document.elementsByTagName("kdenlivedoc").at(0);
-            if (!infoXmlNode.isNull()) {
-                QDomElement infoXml = infoXmlNode.toElement();
-                double version = infoXml.attribute("version").toDouble();
-
-                // Upgrade old Kdenlive documents to current version
-                DocumentConvert converter(m_document);
-                if (!converter.doConvert(version, DOCUMENTVERSION)) {
-                    m_url.clear();
-                    m_document = createEmptyDocument(tracks.x(), tracks.y());
-                    setProfilePath(profileName);
-                } else {
+            else {
+                DocumentValidator validator(m_document);
+                success = validator.isProject();
+                if (!success) // It is not a project file
+                    parent->slotGotProgressInfo(i18n("File %1 is not a Kdenlive project file.", m_url.path()), 100);
+                else {
                     /*
-                     * read again <kdenlivedoc> to get all the new stuff
-                     * (convertDocument() can now do anything without breaking
-                     * document loading)
+                     * Validate the file against the current version (upgrade
+                     * and recover it if needed). It is NOT a passive operation
                      */
-                    setModified(converter.isModified());
-                    infoXmlNode = m_document.elementsByTagName("kdenlivedoc").at(0);
-                    infoXml = infoXmlNode.toElement();
-                    version = infoXml.attribute("version").toDouble();
-                    QDomNode mlt = m_document.elementsByTagName("mlt").at(0);
-
-                    QString profilePath = infoXml.attribute("profile");
-                    QString projectFolderPath = infoXml.attribute("projectfolder");
-                    if (!projectFolderPath.isEmpty()) m_projectFolder = KUrl(projectFolderPath);
-
-                    if (m_projectFolder.isEmpty() || !KIO::NetAccess::exists(m_projectFolder.path(), KIO::NetAccess::DestinationSide, parent)) {
-                        // Make sure the project folder is usable
-                        KMessageBox::information(parent, i18n("Document project folder is invalid, setting it to the default one: %1", KdenliveSettings::defaultprojectfolder()));
-                        m_projectFolder = KUrl(KdenliveSettings::defaultprojectfolder());
-                    }
-                    m_startPos = infoXml.attribute("position").toInt();
-                    m_zoom = infoXml.attribute("zoom", "7").toInt();
-                    m_zoneStart = infoXml.attribute("zonein", "0").toInt();
-                    m_zoneEnd = infoXml.attribute("zoneout", "100").toInt();
-                    setProfilePath(profilePath);
-
-                    // Build tracks
-                    QDomElement e;
-                    QDomNode tracksinfo = m_document.elementsByTagName("tracksinfo").at(0);
-                    TrackInfo projectTrack;
-                    if (!tracksinfo.isNull()) {
-                        QDomNodeList trackslist = tracksinfo.childNodes();
-                        int maxchild = trackslist.count();
-                        for (int k = 0; k < maxchild; k++) {
-                            e = trackslist.at(k).toElement();
-                            if (e.tagName() == "trackinfo") {
-                                if (e.attribute("type") == "audio") projectTrack.type = AUDIOTRACK;
-                                else projectTrack.type = VIDEOTRACK;
-                                projectTrack.isMute = e.attribute("mute").toInt();
-                                projectTrack.isBlind = e.attribute("blind").toInt();
-                                projectTrack.isLocked = e.attribute("locked").toInt();
-                                m_tracksList.append(projectTrack);
+                    // TODO: backup the document or alert the user?
+                    success = validator.validate(DOCUMENTVERSION);
+                    if (success) { // Let the validator handle error messages
+                        setModified(validator.isModified());
+                        QDomNode infoXmlNode = m_document.elementsByTagName("kdenlivedoc").at(0);
+                        QDomElement infoXml = infoXmlNode.toElement();
+                        QDomNode mlt = m_document.elementsByTagName("mlt").at(0);
+
+                        QString profilePath = infoXml.attribute("profile");
+                        m_projectFolder = infoXml.attribute("projectfolder");
+
+                        m_startPos = infoXml.attribute("position").toInt();
+                        m_zoom = infoXml.attribute("zoom", "7").toInt();
+                        m_zoneStart = infoXml.attribute("zonein", "0").toInt();
+                        m_zoneEnd = infoXml.attribute("zoneout", "100").toInt();
+
+                        // Build tracks
+                        QDomElement e;
+                        QDomNode tracksinfo = m_document.elementsByTagName("tracksinfo").at(0);
+                        TrackInfo projectTrack;
+                        if (!tracksinfo.isNull()) {
+                            QDomNodeList trackslist = tracksinfo.childNodes();
+                            int maxchild = trackslist.count();
+                            for (int k = 0; k < maxchild; k++) {
+                                e = trackslist.at(k).toElement();
+                                if (e.tagName() == "trackinfo") {
+                                    if (e.attribute("type") == "audio") projectTrack.type = AUDIOTRACK;
+                                    else projectTrack.type = VIDEOTRACK;
+                                    projectTrack.isMute = e.attribute("mute").toInt();
+                                    projectTrack.isBlind = e.attribute("blind").toInt();
+                                    projectTrack.isLocked = e.attribute("locked").toInt();
+                                    m_tracksList.append(projectTrack);
+                                }
                             }
+                            mlt.removeChild(tracksinfo);
+                        }
+                        QDomNodeList producers = m_document.elementsByTagName("producer");
+                        QDomNodeList infoproducers = m_document.elementsByTagName("kdenlive_producer");
+                        if (checkDocumentClips(infoproducers) == false) m_abortLoading = true;
+                        const int max = producers.count();
+                        const int infomax = infoproducers.count();
+
+                        QDomNodeList folders = m_document.elementsByTagName("folder");
+                        for (int i = 0; i < folders.count(); i++) {
+                            e = folders.item(i).cloneNode().toElement();
+                            m_clipManager->addFolder(e.attribute("id"), e.attribute("name"));
                         }
-                        mlt.removeChild(tracksinfo);
-                    }
-                    QDomNodeList producers = m_document.elementsByTagName("producer");
-                    QDomNodeList infoproducers = m_document.elementsByTagName("kdenlive_producer");
-                    if (checkDocumentClips(infoproducers) == false) m_abortLoading = true;
-                    const int max = producers.count();
-                    const int infomax = infoproducers.count();
-
-                    QDomNodeList folders = m_document.elementsByTagName("folder");
-                    for (int i = 0; i < folders.count(); i++) {
-                        e = folders.item(i).cloneNode().toElement();
-                        m_clipManager->addFolder(e.attribute("id"), e.attribute("name"));
-                    }
 
-                    if (max > 0) {
-                        m_documentLoadingStep = 100.0 / (max + infomax + m_document.elementsByTagName("entry").count());
-                        parent->slotGotProgressInfo(i18n("Loading project clips"), (int) m_documentLoadingProgress);
-                    }
+                        if (max > 0) {
+                            m_documentLoadingStep = 100.0 / (max + infomax + m_document.elementsByTagName("entry").count());
+                            parent->slotGotProgressInfo(i18n("Loading project clips"), (int) m_documentLoadingProgress);
+                        }
 
 
-                    for (int i = 0; i < infomax && !m_abortLoading; i++) {
-                        e = infoproducers.item(i).cloneNode().toElement();
-                        if (m_documentLoadingStep > 0) {
-                            m_documentLoadingProgress += m_documentLoadingStep;
-                            parent->slotGotProgressInfo(QString(), (int) m_documentLoadingProgress);
-                            //qApp->processEvents();
-                        }
-                        QString prodId = e.attribute("id");
-                        if (!e.isNull() && prodId != "black" && !prodId.startsWith("slowmotion") && !m_abortLoading) {
-                            e.setTagName("producer");
-                            // Get MLT's original producer properties
-                            QDomElement orig;
-                            for (int j = 0; j < max; j++) {
-                                QDomElement o = producers.item(j).cloneNode().toElement();
-                                QString origId = o.attribute("id").section('_', 0, 0);
-                                if (origId == prodId) {
-                                    orig = o;
-                                    break;
+                        for (int i = 0; i < infomax && !m_abortLoading; i++) {
+                            e = infoproducers.item(i).cloneNode().toElement();
+                            if (m_documentLoadingStep > 0) {
+                                m_documentLoadingProgress += m_documentLoadingStep;
+                                parent->slotGotProgressInfo(QString(), (int) m_documentLoadingProgress);
+                                //qApp->processEvents();
+                            }
+                            QString prodId = e.attribute("id");
+                            if (!e.isNull() && prodId != "black" && !prodId.startsWith("slowmotion") && !m_abortLoading) {
+                                e.setTagName("producer");
+                                // Get MLT's original producer properties
+                                QDomElement orig;
+                                for (int j = 0; j < max; j++) {
+                                    QDomElement o = producers.item(j).cloneNode().toElement();
+                                    QString origId = o.attribute("id").section('_', 0, 0);
+                                    if (origId == prodId) {
+                                        orig = o;
+                                        break;
+                                    }
                                 }
+                                addClipInfo(e, orig, prodId);
+                                kDebug() << "// KDENLIVE PRODUCER: " << prodId;
                             }
-                            addClipInfo(e, orig, prodId);
-                            kDebug() << "// NLIVE PROD: " << prodId;
                         }
-                    }
-                    if (m_abortLoading) {
-                        //parent->slotGotProgressInfo(i18n("File %1 is not a Kdenlive project file."), 100);
-                        emit resetProjectList();
-                        m_startPos = 0;
-                        m_url = KUrl();
-                        m_tracksList.clear();
-                        kWarning() << "Aborted loading of: " << url.path();
-                        m_document = createEmptyDocument(KdenliveSettings::videotracks(), KdenliveSettings::audiotracks());
-                        setProfilePath(KdenliveSettings::default_profile());
-                        m_clipManager->clear();
-                    } else {
-                        QDomNode markers = m_document.elementsByTagName("markers").at(0);
-                        if (!markers.isNull()) {
-                            QDomNodeList markerslist = markers.childNodes();
-                            int maxchild = markerslist.count();
-                            for (int k = 0; k < maxchild; k++) {
-                                e = markerslist.at(k).toElement();
-                                if (e.tagName() == "marker") {
-                                    m_clipManager->getClipById(e.attribute("id"))->addSnapMarker(GenTime(e.attribute("time").toDouble()), e.attribute("comment"));
+                        if (m_abortLoading) {
+                            //parent->slotGotProgressInfo(i18n("File %1 is not a Kdenlive project file."), 100);
+                            emit resetProjectList();
+                            m_startPos = 0;
+                            m_url = KUrl();
+                            m_tracksList.clear();
+                            kWarning() << "Aborted loading of: " << url.path();
+                            m_document = createEmptyDocument(KdenliveSettings::videotracks(), KdenliveSettings::audiotracks());
+                            setProfilePath(KdenliveSettings::default_profile());
+                            m_clipManager->clear();
+                        } else {
+                            QDomNode markers = m_document.elementsByTagName("markers").at(0);
+                            if (!markers.isNull()) {
+                                QDomNodeList markerslist = markers.childNodes();
+                                int maxchild = markerslist.count();
+                                for (int k = 0; k < maxchild; k++) {
+                                    e = markerslist.at(k).toElement();
+                                    if (e.tagName() == "marker") {
+                                        m_clipManager->getClipById(e.attribute("id"))->addSnapMarker(GenTime(e.attribute("time").toDouble()), e.attribute("comment"));
+                                    }
                                 }
+                                mlt.removeChild(markers);
                             }
-                            mlt.removeChild(markers);
+                            m_document.removeChild(infoXmlNode);
+                            kDebug() << "Reading file: " << url.path() << ", found clips: " << producers.count();
                         }
-                        m_document.removeChild(infoXmlNode);
-                        kDebug() << "Reading file: " << url.path() << ", found clips: " << producers.count();
                     }
                 }
-            } else {
-                parent->slotGotProgressInfo(i18n("File %1 is not a Kdenlive project file."), 100);
-                kWarning() << "  NO KDENLIVE INFO FOUND IN FILE: " << url.path();
-                m_document = createEmptyDocument(KdenliveSettings::videotracks(), KdenliveSettings::audiotracks());
-                m_url = KUrl();
-                setProfilePath(KdenliveSettings::default_profile());
             }
-            KIO::NetAccess::removeTempFile(tmpFile);
-        } else {
-            parent->slotGotProgressInfo(i18n("File %1 is not a Kdenlive project file."), 100);
-            m_url = KUrl();
-            m_document = createEmptyDocument(KdenliveSettings::videotracks(), KdenliveSettings::audiotracks());
-            setProfilePath(KdenliveSettings::default_profile());
         }
-    } else {
+    }
+
+    // Something went wrong, or a new file was requested: create a new project
+    if (!success) {
+        m_url = KUrl();
         m_document = createEmptyDocument(tracks.x(), tracks.y());
-        setProfilePath(profileName);
     }
-    if (m_projectFolder.isEmpty()) m_projectFolder = KUrl(KdenliveSettings::defaultprojectfolder());
 
-    // make sure that the necessary folders exist
+    // Set the video profile (empty == default)
+    setProfilePath(profileName);
+
+    // Make sure the project folder is usable
+    if (m_projectFolder.isEmpty() || !KIO::NetAccess::exists(m_projectFolder.path(), KIO::NetAccess::DestinationSide, parent)) {
+        KMessageBox::information(parent, i18n("Document project folder is invalid, setting it to the default one: %1", KdenliveSettings::defaultprojectfolder()));
+        m_projectFolder = KUrl(KdenliveSettings::defaultprojectfolder());
+    }
+
+    // Make sure that the necessary folders exist
     KStandardDirs::makeDir(m_projectFolder.path() + "/titles/");
     KStandardDirs::makeDir(m_projectFolder.path() + "/thumbs/");
     KStandardDirs::makeDir(m_projectFolder.path() + "/ladspa/");
 
-    kDebug() << "KDEnlive document, init timecode: " << m_fps;
+    kDebug() << "Kdenlive document, init timecode: " << m_fps;
     if (m_fps == 30000.0 / 1001.0) m_timecode.setFormat(30, true);
     else m_timecode.setFormat((int) m_fps);
 
     //kDebug() << "// SETTING SCENE LIST:\n\n" << m_document.toString();
     connect(m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
-
 }
 
 KdenliveDoc::~KdenliveDoc()
@@ -430,7 +416,7 @@ bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene)
     mlt.appendChild(addedXml);
 
     QDomElement markers = sceneList.createElement("markers");
-    addedXml.setAttribute("version", "0.82");
+    addedXml.setAttribute("version", DOCUMENTVERSION);
     addedXml.setAttribute("kdenliveversion", VERSION);
     addedXml.setAttribute("profile", profilePath());
     addedXml.setAttribute("position", m_render->seekPosition().frames(m_fps));
@@ -577,7 +563,7 @@ void KdenliveDoc::setProfilePath(QString path)
     KdenliveSettings::setProject_fps(m_fps);
     m_width = m_profile.width;
     m_height = m_profile.height;
-    kDebug() << "KDEnnlive document, init timecode from path: " << path << ",  " << m_fps;
+    kDebug() << "Kdenlive document, init timecode from path: " << path << ",  " << m_fps;
     if (m_fps == 30000.0 / 1001.0) m_timecode.setFormat(30, true);
     else m_timecode.setFormat((int) m_fps);
 }