]> git.sesse.net Git - kdenlive/blobdiff - src/kdenlivedoc.cpp
Fix title clip duration has 1 frame offset: http://www.kdenlive.org/mantis/view.php...
[kdenlive] / src / kdenlivedoc.cpp
index 8e1aea5637a6d63a4389bbd92cbbadd18026a0e1..e74fbfaf1883a0c1bf835a6972c598889b4a844e 100644 (file)
@@ -28,7 +28,7 @@
 #include "mainwindow.h"
 #include "documentchecker.h"
 #include "documentvalidator.h"
-#include "kdenlive-config.h"
+#include "config-kdenlive.h"
 #include "initeffects.h"
 
 #include <KDebug>
@@ -58,7 +58,7 @@
 
 const double DOCUMENTVERSION = 0.88;
 
-KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, QString profileName, QMap <QString, QString> properties, const QPoint &tracks, Render *render, KTextEdit *notes, bool *openBackup, MainWindow *parent, KProgressDialog *progressDialog) :
+KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup *undoGroup, QString profileName, QMap <QString, QString> properties, QMap <QString, QString> metadata, const QPoint &tracks, Render *render, KTextEdit *notes, bool *openBackup, MainWindow *parent, KProgressDialog *progressDialog) :
     QObject(parent),
     m_autosave(NULL),
     m_url(url),
@@ -68,15 +68,28 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
     m_modified(false),
     m_projectFolder(projectFolder)
 {
+    // init m_profile struct
+    m_profile.frame_rate_num = 0;
+    m_profile.frame_rate_den = 0;
+    m_profile.width = 0;
+    m_profile.height = 0;
+    m_profile.progressive = 0;
+    m_profile.sample_aspect_num = 0;
+    m_profile.sample_aspect_den = 0;
+    m_profile.display_aspect_num = 0;
+    m_profile.display_aspect_den = 0;
+    m_profile.colorspace = 0;
+
     m_clipManager = new ClipManager(this);
     m_autoSaveTimer = new QTimer(this);
     m_autoSaveTimer->setSingleShot(true);
+    connect(m_clipManager, SIGNAL(displayMessage(QString, int)), parent, SLOT(slotGotProgressInfo(QString,int)));
     bool success = false;
 
     // init default document properties
-    m_documentProperties["zoom"] = "7";
-    m_documentProperties["verticalzoom"] = "1";
-    m_documentProperties["zonein"] = "0";
+    m_documentProperties["zoom"] = '7';
+    m_documentProperties["verticalzoom"] = '1';
+    m_documentProperties["zonein"] = '0';
     m_documentProperties["zoneout"] = "100";
     m_documentProperties["enableproxy"] = QString::number((int) KdenliveSettings::enableproxy());
     m_documentProperties["proxyparams"] = KdenliveSettings::proxyparams();
@@ -98,14 +111,21 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
         i.next();
         m_documentProperties[i.key()] = i.value();
     }
+    
+    // Load metadata
+    QMapIterator<QString, QString> j(metadata);
+    while (j.hasNext()) {
+        j.next();
+        m_documentMetadata[j.key()] = j.value();
+    }
 
-    if (QLocale() != QLocale::system()) {
+    if (QLocale().decimalPoint() != QLocale::system().decimalPoint()) {
         setlocale(LC_NUMERIC, "");
         QLocale systemLocale = QLocale::system();
         systemLocale.setNumberOptions(QLocale::OmitGroupSeparator);
         QLocale::setDefault(systemLocale);
         // locale conversion might need to be redone
-        initEffects::parseEffectFiles();
+       initEffects::parseEffectFiles(setlocale(LC_NUMERIC, NULL));
     }
 
     *openBackup = false;
@@ -123,8 +143,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
         else {
             QFile file(tmpFile);
             QString errorMsg;
-            QDomImplementation impl;
-            impl.setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
+            QDomImplementation::setInvalidDataPolicy(QDomImplementation::DropInvalidChars);
             success = m_document.setContent(&file, false, &errorMsg);
             file.close();
             KIO::NetAccess::removeTempFile(tmpFile);
@@ -139,7 +158,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
             else {
                 parent->slotGotProgressInfo(i18n("Validating"), 0);
                 qApp->processEvents();
-                DocumentValidator validator(m_document);
+                DocumentValidator validator(m_document, url);
                 success = validator.isProject();
                 if (!success) {
                     // It is not a project file
@@ -198,6 +217,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
                                         projectTrack.isBlind = e.attribute("blind").toInt();
                                         projectTrack.isLocked = e.attribute("locked").toInt();
                                         projectTrack.trackName = e.attribute("trackname");
+                                       projectTrack.effectsList = EffectsList(true);
                                         m_tracksList.append(projectTrack);
                                     }
                                 }
@@ -262,8 +282,12 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
                                     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 (e.tagName() == "marker") {
+                                           CommentedTime marker(GenTime(e.attribute("time").toDouble()), e.attribute("comment"), e.attribute("type").toInt());
+                                           DocClipBase *baseClip = m_clipManager->getClipById(e.attribute("id"));
+                                            if (baseClip) baseClip->addSnapMarker(marker);
+                                           else kDebug()<< " / / Warning, missing clip: "<< e.attribute("id");
+                                       }
                                     }
                                     infoXml.removeChild(markers);
                                 }
@@ -273,6 +297,10 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
                                 QDomNamedNodeMap props = docproperties.attributes();
                                 for (int i = 0; i < props.count(); i++)
                                     m_documentProperties.insert(props.item(i).nodeName(), props.item(i).nodeValue());
+                                docproperties = infoXml.firstChildElement("documentmetadata");
+                                props = docproperties.attributes();
+                                for (int i = 0; i < props.count(); i++)
+                                    m_documentMetadata.insert(props.item(i).nodeName(), props.item(i).nodeValue());
 
                                 if (validator.isModified()) setModified(true);
                                 kDebug() << "Reading file: " << url.path() << ", found clips: " << producers.count();
@@ -318,6 +346,7 @@ KdenliveDoc::KdenliveDoc(const KUrl &url, const KUrl &projectFolder, QUndoGroup
 
     //kDebug() << "// SETTING SCENE LIST:\n\n" << m_document.toString();
     connect(m_autoSaveTimer, SIGNAL(timeout()), this, SLOT(slotAutoSave()));
+    connect(m_render, SIGNAL(addClip(const KUrl &, stringMap)), this, SLOT(slotAddClipFile(const KUrl &, stringMap)));
 }
 
 KdenliveDoc::~KdenliveDoc()
@@ -362,6 +391,7 @@ QDomDocument KdenliveDoc::createEmptyDocument(int videotracks, int audiotracks)
         audioTrack.isLocked = false;
         audioTrack.trackName = QString("Audio ") + QString::number(audiotracks - i);
         audioTrack.duration = 0;
+       audioTrack.effectsList = EffectsList(true);
         m_tracksList.append(audioTrack);
 
     }
@@ -373,6 +403,7 @@ QDomDocument KdenliveDoc::createEmptyDocument(int videotracks, int audiotracks)
         videoTrack.isLocked = false;
         videoTrack.trackName = QString("Video ") + QString::number(videotracks - i);
         videoTrack.duration = 0;
+       videoTrack.effectsList = EffectsList(true);
         m_tracksList.append(videoTrack);
     }
     return createEmptyDocument(m_tracksList);
@@ -631,6 +662,14 @@ QDomDocument KdenliveDoc::xmlSceneList(const QString &scene, const QStringList &
     }
     docproperties.setAttribute("position", m_render->seekPosition().frames(m_fps));
     addedXml.appendChild(docproperties);
+    
+    QDomElement docmetadata = sceneList.createElement("documentmetadata");
+    QMapIterator<QString, QString> j(m_documentMetadata);
+    while (j.hasNext()) {
+        j.next();
+        docmetadata.setAttribute(j.key(), j.value());
+    }
+    addedXml.appendChild(docmetadata);
 
     QDomElement docnotes = sceneList.createElement("documentnotes");
     QDomText value = sceneList.createTextNode(m_notesWidget->toHtml());
@@ -681,7 +720,7 @@ QDomDocument KdenliveDoc::xmlSceneList(const QString &scene, const QStringList &
     QDomElement e;
     QList <DocClipBase*> list = m_clipManager->documentClipList();
     for (int i = 0; i < list.count(); i++) {
-        e = list.at(i)->toXML();
+        e = list.at(i)->toXML(true);
         e.setTagName("kdenlive_producer");
         addedXml.appendChild(sceneList.importNode(e, true));
         QList < CommentedTime > marks = list.at(i)->commentedSnapMarkers();
@@ -690,6 +729,7 @@ QDomDocument KdenliveDoc::xmlSceneList(const QString &scene, const QStringList &
             marker.setAttribute("time", marks.at(j).time().ms() / 1000);
             marker.setAttribute("comment", marks.at(j).comment());
             marker.setAttribute("id", e.attribute("id"));
+           marker.setAttribute("type", marks.at(j).markerType());
             markers.appendChild(marker);
         }
     }
@@ -735,7 +775,7 @@ bool KdenliveDoc::saveSceneList(const QString &path, const QString &scene, const
         cleanupBackupFiles();
         QFileInfo info(file);
         QString fileName = KUrl(path).fileName().section('.', 0, -2);   
-        fileName.append("-" + m_documentProperties.value("documentid"));
+        fileName.append('-' + m_documentProperties.value("documentid"));
         fileName.append(info.lastModified().toString("-yyyy-MM-dd-hh-mm"));
         fileName.append(".kdenlive.png");
         KUrl backupFile = m_projectFolder;
@@ -764,7 +804,7 @@ void KdenliveDoc::setProjectFolder(KUrl url)
     KStandardDirs::makeDir(url.path());
     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);
+    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?"m_projectFolder.path(), url.path())) == KMessageBox::Yes) moveProjectData(url);
     m_projectFolder = url;
 
     updateProjectFolderPlacesEntry();
@@ -1021,8 +1061,10 @@ bool KdenliveDoc::addClip(QDomElement elem, QString clipId, bool createClipItem)
             extension = KUrl(path).fileName();
             path = KUrl(path).directory();
         }
-
-        if (path.isEmpty() == false && QFile::exists(path) == false && elem.attribute("type").toInt() != TEXT && !elem.hasAttribute("placeholder")) {
+        if (elem.hasAttribute("_missingsource")) {
+            // Clip has proxy but missing original source
+        }
+        else if (path.isEmpty() == false && QFile::exists(path) == false && elem.attribute("type").toInt() != TEXT && !elem.hasAttribute("placeholder")) {
             kDebug() << "// FOUND MISSING CLIP: " << path << ", TYPE: " << elem.attribute("type").toInt();
             const QString size = elem.attribute("file_size");
             const QString hash = elem.attribute("file_hash");
@@ -1180,17 +1222,17 @@ void KdenliveDoc::deleteClip(const QString &clipId)
     emit signalDeleteProjectClip(clipId);
 }
 
-void KdenliveDoc::slotAddClipList(const KUrl::List urls, const QString &group, const QString &groupId)
+void KdenliveDoc::slotAddClipList(const KUrl::List urls, stringMap data)
 {
-    m_clipManager->slotAddClipList(urls, group, groupId);
+    m_clipManager->slotAddClipList(urls, data);
     //emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
     setModified(true);
 }
 
 
-void KdenliveDoc::slotAddClipFile(const KUrl &url, const QString &group, const QString &groupId)
+void KdenliveDoc::slotAddClipFile(const KUrl &url, stringMap data)
 {
-    m_clipManager->slotAddClipFile(url, group, groupId);
+    m_clipManager->slotAddClipFile(url, data);
     emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
     setModified(true);
 }
@@ -1219,15 +1261,9 @@ void KdenliveDoc::slotCreateColorClip(const QString &name, const QString &color,
     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 crop, const bool fade,
-        const QString &luma_duration, const QString &luma_file, const int softness,
-        const QString &animation, QString group, const QString &groupId)
+void KdenliveDoc::slotCreateSlideshowClipFile(QMap <QString, QString> properties, QString group, const QString &groupId)
 {
-    m_clipManager->slotAddSlideshowClipFile(name, path, count, duration, loop,
-                                            crop, fade, luma_duration,
-                                            luma_file, softness,
-                                            animation, group, groupId);
+    m_clipManager->slotAddSlideshowClipFile(properties, group, groupId);
     setModified(true);
     emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
 }
@@ -1236,9 +1272,9 @@ void KdenliveDoc::slotCreateTextClip(QString group, const QString &groupId, cons
 {
     QString titlesFolder = projectFolder().path(KUrl::AddTrailingSlash) + "titles/";
     KStandardDirs::makeDir(titlesFolder);
-    TitleWidget *dia_ui = new TitleWidget(templatePath, m_timecode, titlesFolder, m_render, kapp->activeWindow());
+    QPointer<TitleWidget> dia_ui = new TitleWidget(templatePath, m_timecode, titlesFolder, m_render, kapp->activeWindow());
     if (dia_ui->exec() == QDialog::Accepted) {
-        m_clipManager->slotAddTextClipFile(i18n("Title clip"), dia_ui->outPoint(), dia_ui->xml().toString(), group, groupId);
+        m_clipManager->slotAddTextClipFile(i18n("Title clip"), dia_ui->duration(), dia_ui->xml().toString(), group, groupId);
         setModified(true);
         emit selectLastAddedClip(QString::number(m_clipManager->lastClipId()));
     }
@@ -1364,9 +1400,9 @@ QPoint KdenliveDoc::getTracksCount() const
     return QPoint(video, audio);
 }
 
-void KdenliveDoc::cachePixmap(const QString &fileId, const QPixmap &pix) const
+void KdenliveDoc::cacheImage(const QString &fileId, const QImage &img) const
 {
-    pix.save(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + fileId + ".png");
+    img.save(m_projectFolder.path(KUrl::AddTrailingSlash) + "thumbs/" + fileId + ".png");
 }
 
 bool KdenliveDoc::checkDocumentClips(QDomNodeList infoproducers)
@@ -1475,15 +1511,13 @@ void KdenliveDoc::removeTrackEffect(int ix, QDomElement effect)
         kWarning() << "Remove Track effect outisde of range";
         return;
     }
-    QString index;
-    QString toRemove = effect.attribute("kdenlive_ix");
+    int index;
+    int toRemove = effect.attribute("kdenlive_ix").toInt();
     for (int i = 0; i < m_tracksList.at(ix).effectsList.count(); ++i) {
-        index = m_tracksList.at(ix).effectsList.at(i).attribute("kdenlive_ix");
+        index = m_tracksList.at(ix).effectsList.at(i).attribute("kdenlive_ix").toInt();
         if (toRemove == index) {
-            m_tracksList[ix].effectsList.removeAt(i);
-            i--;
-        } else if (index.toInt() > toRemove.toInt()) {
-            m_tracksList[ix].effectsList.item(i).setAttribute("kdenlive_ix", index.toInt() - 1);
+            m_tracksList[ix].effectsList.removeAt(toRemove);
+            break;
         }
     }
 }
@@ -1494,12 +1528,28 @@ void KdenliveDoc::setTrackEffect(int trackIndex, int effectIndex, QDomElement ef
         kWarning() << "Set Track effect outisde of range";
         return;
     }
-    if (effectIndex < 0 || effectIndex > (m_tracksList.at(trackIndex).effectsList.count() - 1) || effect.isNull()) {
+    if (effectIndex <= 0 || effectIndex > (m_tracksList.at(trackIndex).effectsList.count()) || effect.isNull()) {
         kDebug() << "Invalid effect index: " << effectIndex;
         return;
     }
-    effect.setAttribute("kdenlive_ix", effectIndex + 1);
-    m_tracksList[trackIndex].effectsList.replace(effectIndex, effect);
+    m_tracksList[trackIndex].effectsList.removeAt(effect.attribute("kdenlive_ix").toInt());
+    effect.setAttribute("kdenlive_ix", effectIndex);
+    m_tracksList[trackIndex].effectsList.insert(effect);
+    //m_tracksList[trackIndex].effectsList.updateEffect(effect);
+}
+
+void KdenliveDoc::enableTrackEffects(int trackIndex, QList <int> effectIndexes, bool disable)
+{
+    if (trackIndex < 0 || trackIndex >= m_tracksList.count()) {
+        kWarning() << "Set Track effect outisde of range";
+        return;
+    }
+    EffectsList list = m_tracksList.at(trackIndex).effectsList;
+    QDomElement effect;
+    for (int i = 0; i < effectIndexes.count(); i++) {
+       effect = list.itemFromIndex(effectIndexes.at(i));
+       if (!effect.isNull()) effect.setAttribute("disable", (int) disable);
+    }
 }
 
 const EffectsList KdenliveDoc::getTrackEffects(int ix)
@@ -1518,8 +1568,18 @@ QDomElement KdenliveDoc::getTrackEffect(int trackIndex, int effectIndex) const
         return QDomElement();
     }
     EffectsList list = m_tracksList.at(trackIndex).effectsList;
-    if (effectIndex > list.count() - 1 || effectIndex < 0 || list.at(effectIndex).isNull()) return QDomElement();
-    return list.at(effectIndex).cloneNode().toElement();
+    if (effectIndex > list.count() || effectIndex < 1 || list.itemFromIndex(effectIndex).isNull()) return QDomElement();
+    return list.itemFromIndex(effectIndex).cloneNode().toElement();
+}
+
+int KdenliveDoc::hasTrackEffect(int trackIndex, const QString &tag, const QString &id) const
+{
+    if (trackIndex < 0 || trackIndex >= m_tracksList.count()) {
+        kWarning() << "Get Track effect outisde of range";
+        return -1;
+    }
+    EffectsList list = m_tracksList.at(trackIndex).effectsList;
+    return list.hasEffect(tag, id);
 }
 
 bool KdenliveDoc::saveCustomEffects(QDomNodeList customeffects)
@@ -1562,7 +1622,9 @@ void KdenliveDoc::updateProjectFolderPlacesEntry()
 
     const QString file = KStandardDirs::locateLocal("data", "kfileplaces/bookmarks.xml");
     KBookmarkManager *bookmarkManager = KBookmarkManager::managerForFile(file, "kfilePlaces");
+    if (!bookmarkManager) return;
     KBookmarkGroup root = bookmarkManager->root();
+    
     KBookmark bookmark = root.first();
 
     QString kdenliveName = KGlobal::mainComponent().componentName();
@@ -1637,7 +1699,7 @@ void KdenliveDoc::backupLastSavedVersion(const QString &path)
     KIO::NetAccess::mkdir(backupFile, kapp->activeWindow());
     QString fileName = KUrl(path).fileName().section('.', 0, -2);
     QFileInfo info(file);
-    fileName.append("-" + m_documentProperties.value("documentid"));
+    fileName.append('-' + m_documentProperties.value("documentid"));
     fileName.append(info.lastModified().toString("-yyyy-MM-dd-hh-mm"));
     fileName.append(".kdenlive");
     backupFile.addPath(fileName);
@@ -1657,7 +1719,7 @@ void KdenliveDoc::cleanupBackupFiles()
     backupFile.addPath(".backup/");
     QDir dir(backupFile.path());
     QString projectFile = url().fileName().section('.', 0, -2);
-    projectFile.append("-" + m_documentProperties.value("documentid"));
+    projectFile.append('-' + m_documentProperties.value("documentid"));
     projectFile.append("-??");
     projectFile.append("??");
     projectFile.append("-??");
@@ -1747,5 +1809,15 @@ void KdenliveDoc::cleanupBackupFiles()
     }
 }
 
+const QMap <QString, QString> KdenliveDoc::metadata() const
+{
+    return m_documentMetadata;
+}
+
+void KdenliveDoc::setMetadata(const QMap <QString, QString> meta)
+{
+    m_documentMetadata = meta;
+}
+
 #include "kdenlivedoc.moc"