]> git.sesse.net Git - kdenlive/blobdiff - src/kdenlivedoc.cpp
Don't crash when wrong sdl driver was selected by user (needs MLT patch):
[kdenlive] / src / kdenlivedoc.cpp
index 34286682f9a0f86207658464ec8a8c411bd0ee47..5494ab718e40252d7f1c497452433a955ab8c938 100644 (file)
@@ -51,22 +51,25 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
         QObject(parent),
         m_autosave(NULL),
         m_url(url),
-        m_zoom(7),
-        m_startPos(0),
         m_render(render),
         m_commandStack(new QUndoStack(undoGroup)),
         m_modified(false),
         m_projectFolder(projectFolder),
         m_documentLoadingStep(0.0),
         m_documentLoadingProgress(0),
-        m_abortLoading(false),
-        m_zoneStart(0),
-        m_zoneEnd(100)
+        m_abortLoading(false)
 {
     m_clipManager = new ClipManager(this);
     m_autoSaveTimer = new QTimer(this);
     m_autoSaveTimer->setSingleShot(true);
     bool success = false;
+
+    // init default document properties
+    m_documentProperties["zoom"] = "7";
+    m_documentProperties["verticalzoom"] = "1";
+    m_documentProperties["zonein"] = "0";
+    m_documentProperties["zoneout"] = "100";
+
     if (!url.isEmpty()) {
         QString tmpFile;
         success = KIO::NetAccess::download(url.path(), tmpFile, parent);
@@ -93,18 +96,16 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
                     // TODO: backup the document or alert the user?
                     success = validator.validate(DOCUMENTVERSION);
                     if (success) { // Let the validator handle error messages
-                        setModified(validator.isModified());
                         QDomElement mlt = m_document.firstChildElement("mlt");
                         QDomElement infoXml = mlt.firstChildElement("kdenlivedoc");
 
                         profileName = 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();
-
+                        m_projectFolder = KUrl(infoXml.attribute("projectfolder"));
+                        QDomElement docproperties = infoXml.firstChildElement("documentproperties");
+                        QDomNamedNodeMap props = docproperties.attributes();
+                        for (int i = 0; i < props.count(); i++) {
+                            m_documentProperties.insert(props.item(i).nodeName(), props.item(i).nodeValue());
+                        }
                         // Build tracks
                         QDomElement e;
                         QDomElement tracksinfo = infoXml.firstChildElement("tracksinfo");
@@ -170,7 +171,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
                         if (m_abortLoading) {
                             //parent->slotGotProgressInfo(i18n("File %1 is not a Kdenlive project file."), 100);
                             emit resetProjectList();
-                            m_startPos = 0;
+                            m_documentProperties.remove("position");
                             m_url = KUrl();
                             m_tracksList.clear();
                             kWarning() << "Aborted loading of: " << url.path();
@@ -191,6 +192,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
                                 infoXml.removeChild(markers);
                             }
                             setProfilePath(profileName);
+                            setModified(validator.isModified());
                             kDebug() << "Reading file: " << url.path() << ", found clips: " << producers.count();
                         }
                     }
@@ -214,9 +216,9 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
     }
 
     // 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/");
+    KStandardDirs::makeDir(m_projectFolder.path(KUrl::AddTrailingSlash) + "titles/");
+    KStandardDirs::makeDir(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/");
+    KStandardDirs::makeDir(m_projectFolder.path(KUrl::AddTrailingSlash) + "ladspa/");
 
     kDebug() << "Kdenlive document, init timecode: " << m_fps;
     if (m_fps == 30000.0 / 1001.0) m_timecode.setFormat(30, true);
@@ -237,12 +239,17 @@ KdenliveDoc::~KdenliveDoc()
     }
 }
 
-void KdenliveDoc::setSceneList()
+int KdenliveDoc::setSceneList()
 {
-    m_render->setSceneList(m_document.toString(), m_startPos);
+    if (m_render->setSceneList(m_document.toString(), m_documentProperties.value("position").toInt()) == -1) {
+        // INVALID MLT Consumer, something is wrong
+        return -1;
+    }
+    m_documentProperties.remove("position");
     // m_document xml is now useless, clear it
     m_document.clear();
     checkProjectClips();
+    return 0;
 }
 
 QDomDocument KdenliveDoc::createEmptyDocument(const int videotracks, const int audiotracks)
@@ -385,25 +392,26 @@ void KdenliveDoc::slotAutoSave()
     }
 }
 
-void KdenliveDoc::setZoom(int factor)
+void KdenliveDoc::setZoom(int horizontal, int vertical)
 {
-    m_zoom = factor;
+    m_documentProperties["zoom"] = QString::number(horizontal);
+    m_documentProperties["verticalzoom"] = QString::number(vertical);
 }
 
-int KdenliveDoc::zoom() const
+QPoint KdenliveDoc::zoom() const
 {
-    return m_zoom;
+    return QPoint(m_documentProperties.value("zoom").toInt(), m_documentProperties.value("verticalzoom").toInt());
 }
 
 void KdenliveDoc::setZone(int start, int end)
 {
-    m_zoneStart = start;
-    m_zoneEnd = end;
+    m_documentProperties["zonein"] = QString::number(start);
+    m_documentProperties["zoneout"] = QString::number(end);
 }
 
 QPoint KdenliveDoc::zone() const
 {
-    return QPoint(m_zoneStart, m_zoneEnd);
+    return QPoint(m_documentProperties.value("zonein").toInt(), m_documentProperties.value("zoneout").toInt());
 }
 
 bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene)
@@ -418,11 +426,16 @@ bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene)
     addedXml.setAttribute("version", DOCUMENTVERSION);
     addedXml.setAttribute("kdenliveversion", VERSION);
     addedXml.setAttribute("profile", profilePath());
-    addedXml.setAttribute("position", m_render->seekPosition().frames(m_fps));
-    addedXml.setAttribute("zonein", m_zoneStart);
-    addedXml.setAttribute("zoneout", m_zoneEnd);
     addedXml.setAttribute("projectfolder", m_projectFolder.path());
-    addedXml.setAttribute("zoom", m_zoom);
+
+    QDomElement docproperties = sceneList.createElement("documentproperties");
+    QMapIterator<QString, QString> i(m_documentProperties);
+    while (i.hasNext()) {
+        i.next();
+        docproperties.setAttribute(i.key(), i.value());
+    }
+    docproperties.setAttribute("position", m_render->seekPosition().frames(m_fps));
+    addedXml.appendChild(docproperties);
 
     // Add profile info
     QDomElement profileinfo = sceneList.createElement("profileinfo");
@@ -521,8 +534,8 @@ void KdenliveDoc::setProjectFolder(KUrl url)
     if (url == m_projectFolder) return;
     setModified(true);
     KStandardDirs::makeDir(url.path());
-    KStandardDirs::makeDir(url.path() + "/titles/");
-    KStandardDirs::makeDir(url.path() + "/thumbs/");
+    KStandardDirs::makeDir(url.path(KUrl::AddTrailingSlash) + "titles/");
+    KStandardDirs::makeDir(url.path(KUrl::AddTrailingSlash) + "thumbs/");
     if (KMessageBox::questionYesNo(kapp->activeWindow(), i18n("You have changed the project folder. Do you want to copy the cached data from %1 to the new folder %2?").arg(m_projectFolder.path(), url.path())) == KMessageBox::Yes) moveProjectData(url);
     m_projectFolder = url;
 }
@@ -536,20 +549,20 @@ void KdenliveDoc::moveProjectData(KUrl url)
         if (clip->clipType() == TEXT) {
             // the image for title clip must be moved
             KUrl oldUrl = clip->fileURL();
-            KUrl newUrl = KUrl(url.path() + "/titles/" + oldUrl.fileName());
+            KUrl newUrl = KUrl(url.path(KUrl::AddTrailingSlash) + "titles/" + oldUrl.fileName());
             KIO::Job *job = KIO::copy(oldUrl, newUrl);
             if (KIO::NetAccess::synchronousRun(job, 0)) clip->setProperty("resource", newUrl.path());
         }
         QString hash = clip->getClipHash();
-        KUrl oldVideoThumbUrl = KUrl(m_projectFolder.path() + "/thumbs/" + hash + ".png");
-        KUrl oldAudioThumbUrl = KUrl(m_projectFolder.path() + "/thumbs/" + hash + ".thumb");
+        KUrl oldVideoThumbUrl = KUrl(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + hash + ".png");
+        KUrl oldAudioThumbUrl = KUrl(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + hash + ".thumb");
         if (KIO::NetAccess::exists(oldVideoThumbUrl, KIO::NetAccess::SourceSide, 0)) {
-            KUrl newUrl = KUrl(url.path() + "/thumbs/" + hash + ".png");
+            KUrl newUrl = KUrl(url.path(KUrl::AddTrailingSlash) + "thumbs/" + hash + ".png");
             KIO::Job *job = KIO::copy(oldVideoThumbUrl, newUrl);
             KIO::NetAccess::synchronousRun(job, 0);
         }
         if (KIO::NetAccess::exists(oldAudioThumbUrl, KIO::NetAccess::SourceSide, 0)) {
-            KUrl newUrl = KUrl(url.path() + "/thumbs/" + hash + ".thumb");
+            KUrl newUrl = KUrl(url.path(KUrl::AddTrailingSlash) + "thumbs/" + hash + ".thumb");
             KIO::Job *job = KIO::copy(oldAudioThumbUrl, newUrl);
             if (KIO::NetAccess::synchronousRun(job, 0)) clip->refreshThumbUrl();
         }
@@ -665,45 +678,6 @@ void KdenliveDoc::checkProjectClips()
     kDebug() << "+++++++++++++ + + + + CHK PCLIPS";
     if (m_render == NULL) return;
     m_clipManager->resetProducersList(m_render->producersList());
-    return;
-
-    // Useless now...
-    QList <Mlt::Producer *> prods = m_render->producersList();
-    QString id ;
-    QString prodId ;
-    QString prodTrack ;
-    for (int i = 0; i < prods.count(); i++) {
-        id = prods.at(i)->get("id");
-        prodId = id.section('_', 0, 0);
-        prodTrack = id.section('_', 1, 1);
-        DocClipBase *clip = m_clipManager->getClipById(prodId);
-        if (clip) clip->setProducer(prods.at(i));
-        if (clip && clip->clipType() == TEXT && !QFile::exists(clip->fileURL().path())) {
-            // regenerate text clip image if required
-            //kDebug() << "// TITLE: " << clip->getProperty("titlename") << " Preview file: " << clip->getProperty("resource") << " DOES NOT EXIST";
-            QString titlename = clip->getProperty("name");
-            QString titleresource;
-            if (titlename.isEmpty()) {
-                QStringList titleInfo = TitleWidget::getFreeTitleInfo(projectFolder());
-                titlename = titleInfo.at(0);
-                titleresource = titleInfo.at(1);
-                clip->setProperty("name", titlename);
-                kDebug() << "// New title set to: " << titlename;
-            } else {
-                titleresource = TitleWidget::getFreeTitleInfo(projectFolder()).at(1);
-                //titleresource = TitleWidget::getTitleResourceFromName(projectFolder(), titlename);
-            }
-            TitleWidget *dia_ui = new TitleWidget(KUrl(), KUrl(titleresource).directory(), m_render, kapp->activeWindow());
-            QDomDocument doc;
-            doc.setContent(clip->getProperty("xmldata"));
-            dia_ui->setXml(doc);
-            QImage pix = dia_ui->renderedPixmap();
-            pix.save(titleresource);
-            clip->setProperty("resource", titleresource);
-            delete dia_ui;
-            clip->producer()->set("force_reload", 1);
-        }
-    }
 }
 
 void KdenliveDoc::updatePreviewSettings()
@@ -908,7 +882,7 @@ void KdenliveDoc::addClip(QDomElement elem, QString clipId, bool createClipItem)
     if (createClipItem) {
         emit addProjectClip(clip);
         qApp->processEvents();
-        m_render->getFileProperties(clip->toXML(), clip->getId());
+        m_render->getFileProperties(clip->toXML(), clip->getId(), true);
     }
 }
 
@@ -1030,7 +1004,6 @@ void KdenliveDoc::slotAddClipList(const KUrl::List urls, const QString group, co
 
 void KdenliveDoc::slotAddClipFile(const KUrl url, const QString group, const QString &groupId)
 {
-    //kDebug() << "/////////  DOCUM, ADD CLP: " << url;
     m_clipManager->slotAddClipFile(url, group, groupId);
     emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
     setModified(true);
@@ -1046,22 +1019,57 @@ DocClipBase *KdenliveDoc::getBaseClip(const QString &clipId)
     return m_clipManager->getClipById(clipId);
 }
 
-void KdenliveDoc::slotCreateTextClip(QString /*group*/, const QString &/*groupId*/)
+void KdenliveDoc::slotCreateColorClip(const QString &name, const QString &color, const QString &duration, QString group, const QString &groupId)
+{
+    m_clipManager->slotAddColorClipFile(name, color, duration, group, groupId);
+    setModified(true);
+    emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
+}
+
+void KdenliveDoc::slotCreateSlideshowClipFile(const QString name, const QString path, int count, const QString duration, const bool loop, const bool fade, const QString &luma_duration, const QString &luma_file, const int softness, QString group, const QString &groupId)
+{
+    m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop, fade, luma_duration, luma_file, softness, group, groupId);
+    setModified(true);
+    emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
+}
+
+void KdenliveDoc::slotCreateTextClip(QString group, const QString &groupId, const QString &templatePath)
 {
-    QString titlesFolder = projectFolder().path() + "/titles/";
+    QString titlesFolder = projectFolder().path(KUrl::AddTrailingSlash) + "titles/";
     KStandardDirs::makeDir(titlesFolder);
-    TitleWidget *dia_ui = new TitleWidget(KUrl(), titlesFolder, m_render, kapp->activeWindow());
+    TitleWidget *dia_ui = new TitleWidget(templatePath, titlesFolder, m_render, kapp->activeWindow());
     if (dia_ui->exec() == QDialog::Accepted) {
         QStringList titleInfo = TitleWidget::getFreeTitleInfo(projectFolder());
         QImage pix = dia_ui->renderedPixmap();
         pix.save(titleInfo.at(1));
         //dia_ui->saveTitle(path + ".kdenlivetitle");
-        m_clipManager->slotAddTextClipFile(titleInfo.at(0), titleInfo.at(1), dia_ui->xml().toString(), QString(), QString());
+        m_clipManager->slotAddTextClipFile(titleInfo.at(0), titleInfo.at(1), dia_ui->xml().toString(), group, groupId);
         setModified(true);
+        emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
     }
     delete dia_ui;
 }
 
+void KdenliveDoc::slotCreateTextTemplateClip(QString group, const QString &groupId, KUrl path)
+{
+    QString titlesFolder = projectFolder().path(KUrl::AddTrailingSlash) + "titles/";
+    if (path.isEmpty()) {
+        path = KFileDialog::getOpenUrl(KUrl(titlesFolder), "*.kdenlivetitle", kapp->activeWindow(), i18n("Enter Template Path"));
+    }
+
+    if (path.isEmpty()) return;
+
+    QStringList titleInfo = TitleWidget::getFreeTitleInfo(projectFolder(), true);
+
+    TitleWidget *dia_ui = new TitleWidget(path, titlesFolder, m_render, kapp->activeWindow());
+    QImage pix = dia_ui->renderedPixmap();
+    pix.save(titleInfo.at(1));
+    delete dia_ui;
+    m_clipManager->slotAddTextTemplateClip(titleInfo.at(0), titleInfo.at(1), path, group, groupId);
+    setModified(true);
+    emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
+}
+
 int KdenliveDoc::tracksCount() const
 {
     return m_tracksList.count();
@@ -1129,18 +1137,18 @@ QPoint KdenliveDoc::getTracksCount() const
 
 void KdenliveDoc::cachePixmap(const QString &fileId, const QPixmap &pix) const
 {
-    pix.save(m_projectFolder.path() + "/thumbs/" + fileId + ".png");
+    pix.save(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + fileId + ".png");
 }
 
 QString KdenliveDoc::getLadspaFile() const
 {
     int ct = 0;
     QString counter = QString::number(ct).rightJustified(5, '0', false);
-    while (QFile::exists(m_projectFolder.path() + "/ladspa/" + counter + ".ladspa")) {
+    while (QFile::exists(m_projectFolder.path(KUrl::AddTrailingSlash) + "ladspa/" + counter + ".ladspa")) {
         ct++;
         counter = QString::number(ct).rightJustified(5, '0', false);
     }
-    return m_projectFolder.path() + "/ladspa/" + counter + ".ladspa";
+    return m_projectFolder.path(KUrl::AddTrailingSlash) + "ladspa/" + counter + ".ladspa";
 }
 
 bool KdenliveDoc::checkDocumentClips(QDomNodeList infoproducers)
@@ -1153,13 +1161,23 @@ bool KdenliveDoc::checkDocumentClips(QDomNodeList infoproducers)
     for (int i = 0; i < infoproducers.count(); i++) {
         e = infoproducers.item(i).toElement();
         clipType = e.attribute("type").toInt();
-        if (clipType == TEXT || clipType == COLOR) continue;
+        if (clipType == COLOR) continue;
+        if (clipType == TEXT) {
+            //TODO: Check is clip template is missing (xmltemplate) or hash changed
+            continue;
+        }
         id = e.attribute("id");
         resource = e.attribute("resource");
         if (clipType == SLIDESHOW) resource = KUrl(resource).directory();
         if (!KIO::NetAccess::exists(KUrl(resource), KIO::NetAccess::SourceSide, 0)) {
             // Missing clip found
             missingClips.append(e);
+        } else {
+            // Check if the clip has changed
+            if (clipType != SLIDESHOW && e.hasAttribute("file_hash")) {
+                if (e.attribute("file_hash") != DocClipBase::getHash(e.attribute("resource")))
+                    e.removeAttribute("file_hash");
+            }
         }
     }
     if (missingClips.isEmpty()) return true;
@@ -1167,6 +1185,15 @@ bool KdenliveDoc::checkDocumentClips(QDomNodeList infoproducers)
     return (d.exec() == QDialog::Accepted);
 }
 
+void KdenliveDoc::setDocumentProperty(const QString &name, const QString &value)
+{
+    m_documentProperties[name] = value;
+}
+
+const QString KdenliveDoc::getDocumentProperty(const QString &name) const
+{
+    return m_documentProperties.value(name);
+}
 
 #include "kdenlivedoc.moc"