]> git.sesse.net Git - kdenlive/blobdiff - src/projectlist.cpp
Merge branch 'master' into effectstack
[kdenlive] / src / projectlist.cpp
index 95c06db00bdfa9f19e952a25550eec39f141e046..3ebba4c6fa5c00fbdd50808d05d28b4f40e27a63 100644 (file)
@@ -36,6 +36,7 @@
 #include "projectlistview.h"
 #include "timecodedisplay.h"
 #include "profilesdialog.h"
+#include "clipstabilize.h"
 #include "commands/editclipcommand.h"
 #include "commands/editclipcutcommand.h"
 #include "commands/editfoldercommand.h"
@@ -563,7 +564,10 @@ void ProjectList::editClipSelection(QList<QTreeWidgetItem *> list)
         p.next();
         kDebug() << "Result: " << p.key() << " = " << p.value();
     }*/
-    emit showClipProperties(clipList, commonproperties);
+    if (clipList.isEmpty()) {
+        emit displayMessage(i18n("No available clip selected"), -2);        
+    }
+    else emit showClipProperties(clipList, commonproperties);
 }
 
 void ProjectList::slotOpenClip()
@@ -867,7 +871,9 @@ void ProjectList::adjustProxyActions(ProjectItem *clip) const
         m_proxyAction->setEnabled(false);
         return;
     }
-    m_proxyAction->setEnabled(useProxy());
+    bool enabled = useProxy();
+    if (clip->referencedClip() && !clip->referencedClip()->getProperty("_missingsource").isEmpty()) enabled = false;
+    m_proxyAction->setEnabled(enabled);
     m_proxyAction->blockSignals(true);
     m_proxyAction->setChecked(clip->hasProxy());
     m_proxyAction->blockSignals(false);
@@ -1108,7 +1114,7 @@ void ProjectList::slotRemoveClip()
         } else {
             ProjectItem *item = static_cast <ProjectItem *>(selected.at(i));
             ids << item->clipId();
-            if (item->numReferences() > 0 && KMessageBox::questionYesNo(kapp->activeWindow(), i18np("Delete clip <b>%2</b>?<br />This will also remove the clip in timeline", "Delete clip <b>%2</b>?<br />This will also remove its %1 clips in timeline", item->numReferences(), item->names().at(1)), i18n("Delete Clip"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "DeleteAll") == KMessageBox::No) {
+            if (item->numReferences() > 0 && KMessageBox::questionYesNo(kapp->activeWindow(), i18np("Delete clip <b>%2</b>?<br />This will also remove the clip in timeline", "Delete clip <b>%2</b>?<br />This will also remove its %1 clips in timeline", item->numReferences(), item->text(1)), i18n("Delete Clip"), KStandardGuiItem::yes(), KStandardGuiItem::no(), "DeleteAll") == KMessageBox::No) {
                 KMessageBox::enableMessage("DeleteAll");
                 return;
             }
@@ -1193,9 +1199,9 @@ void ProjectList::editFolder(const QString folderName, const QString oldfolderNa
     m_doc->setModified(true);
 }
 
-void ProjectList::slotAddFolder()
+void ProjectList::slotAddFolder(const QString &name)
 {
-    AddFolderCommand *command = new AddFolderCommand(this, i18n("Folder"), QString::number(m_doc->clipManager()->getFreeFolderId()), true);
+    AddFolderCommand *command = new AddFolderCommand(this, name.isEmpty() ? i18n("Folder") : name, QString::number(m_doc->clipManager()->getFreeFolderId()), true);
     m_commandStack->push(command);
 }
 
@@ -1650,11 +1656,18 @@ void ProjectList::slotAddClip(const QList <QUrl> givenList, const QString &group
                         while (fileName.at(fileName.size() - 1).isDigit()) {
                             fileName.chop(1);
                         }
-
-                        m_doc->slotCreateSlideshowClipFile(fileName, pattern, count, m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()),
-                                                           false, false, false,
-                                                           m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))), QString(), 0,
-                                                           QString(), groupInfo.at(0), groupInfo.at(1));
+                        QMap <QString, QString> properties;
+                        properties.insert("name", fileName);
+                        properties.insert("resource", pattern);
+                        properties.insert("in", "0");
+                        QString duration = m_timecode.reformatSeparators(KdenliveSettings::sequence_duration());
+                        properties.insert("out", QString::number(m_doc->getFramePos(duration) * count));
+                        properties.insert("ttl", QString::number(m_doc->getFramePos(duration)));
+                        properties.insert("loop", QString::number(false));
+                        properties.insert("crop", QString::number(false));
+                        properties.insert("fade", QString::number(false));
+                        properties.insert("luma_duration", QString::number(m_doc->getFramePos(m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))))));
+                        m_doc->slotCreateSlideshowClipFile(properties, groupInfo.at(0), groupInfo.at(1));
                         return;
                     }
                 }
@@ -1665,25 +1678,53 @@ void ProjectList::slotAddClip(const QList <QUrl> givenList, const QString &group
         for (int i = 0; i < givenList.count(); i++)
             list << givenList.at(i);
     }
+    QList <KUrl::List> foldersList;
 
     foreach(const KUrl & file, list) {
         // Check there is no folder here
         KMimeType::Ptr type = KMimeType::findByUrl(file);
         if (type->is("inode/directory")) {
-            // user dropped a folder
+            // user dropped a folder, import its files
             list.removeAll(file);
+            QDir dir(file.path());
+            QStringList result = dir.entryList(QDir::Files);
+            KUrl::List folderFiles;
+            folderFiles << file;
+            foreach(const QString & path, result) {
+                KUrl newFile = file;
+                newFile.addPath(path);
+                folderFiles.append(newFile);
+            }
+            if (folderFiles.count() > 1) foldersList.append(folderFiles);
         }
     }
 
-    if (list.isEmpty())
-        return;
-
-    if (givenList.isEmpty()) {
+    if (givenList.isEmpty() && !list.isEmpty()) {
         QStringList groupInfo = getGroup();
         m_doc->slotAddClipList(list, groupInfo.at(0), groupInfo.at(1));
-    } else {
+    } else if (!list.isEmpty()) {
         m_doc->slotAddClipList(list, groupName, groupId);
     }
+    
+    if (!foldersList.isEmpty()) {
+        // create folders 
+        for (int i = 0; i < foldersList.count(); i++) {
+            KUrl::List urls = foldersList.at(i);
+            KUrl folderUrl = urls.takeFirst();
+            QString folderName = folderUrl.fileName();
+            FolderProjectItem *folder = NULL;
+            if (!folderName.isEmpty()) {
+                folder = getFolderItemByName(folderName);
+                if (folder == NULL) {
+                    slotAddFolder(folderName);
+                    folder = getFolderItemByName(folderName);
+                }
+            }
+            if (folder)
+                m_doc->slotAddClipList(urls, folder->groupName(), folder->clipId());
+            else m_doc->slotAddClipList(urls);
+        }
+    }
 }
 
 void ProjectList::slotRemoveInvalidClip(const QString &id, bool replace)
@@ -1787,10 +1828,22 @@ void ProjectList::slotAddSlideshowClip()
 
     if (dia->exec() == QDialog::Accepted) {
         QStringList groupInfo = getGroup();
-        m_doc->slotCreateSlideshowClipFile(dia->clipName(), dia->selectedPath(), dia->imageCount(), dia->clipDuration(),
-                                           dia->loop(), dia->crop(), dia->fade(),
-                                           dia->lumaDuration(), dia->lumaFile(), dia->softness(),
-                                           dia->animation(), groupInfo.at(0), groupInfo.at(1));
+        
+        QMap <QString, QString> properties;
+        properties.insert("name", dia->clipName());
+        properties.insert("resource", dia->selectedPath());
+        properties.insert("in", "0");
+        properties.insert("out", QString::number(m_doc->getFramePos(dia->clipDuration()) * dia->imageCount()));
+        properties.insert("ttl", QString::number(m_doc->getFramePos(dia->clipDuration())));
+        properties.insert("loop", QString::number(dia->loop()));
+        properties.insert("crop", QString::number(dia->crop()));
+        properties.insert("fade", QString::number(dia->fade()));
+        properties.insert("luma_duration", dia->lumaDuration());
+        properties.insert("luma_file", dia->lumaFile());
+        properties.insert("softness", QString::number(dia->softness()));
+        properties.insert("animation", dia->animation());
+        
+        m_doc->slotCreateSlideshowClipFile(properties, groupInfo.at(0), groupInfo.at(1));
     }
     delete dia;
 }
@@ -2291,6 +2344,19 @@ ProjectItem *ProjectList::getItemById(const QString &id)
     return NULL;
 }
 
+FolderProjectItem *ProjectList::getFolderItemByName(const QString &name)
+{
+    FolderProjectItem *item = NULL;
+    QList <QTreeWidgetItem *> hits = m_listView->findItems(name, Qt::MatchExactly, 0);
+    for (int i = 0; i < hits.count(); i++) {
+        if (hits.at(i)->type() == PROJECTFOLDERTYPE) {
+            item = static_cast<FolderProjectItem *>(hits.at(i));
+            break;
+        }
+    }
+    return item;
+}
+
 FolderProjectItem *ProjectList::getFolderItemById(const QString &id)
 {
     FolderProjectItem *item;
@@ -2557,10 +2623,19 @@ void ProjectList::slotAddOrUpdateSequence(const QString frameName)
         } else {
             // Create sequence
             QStringList groupInfo = getGroup();
-            m_doc->slotCreateSlideshowClipFile(fileName, pattern, count, m_timecode.reformatSeparators(KdenliveSettings::sequence_duration()),
-                                               false, false, false,
-                                               m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))), QString(), 0,
-                                               QString(), groupInfo.at(0), groupInfo.at(1));
+            QMap <QString, QString> properties;
+            properties.insert("name", fileName);
+            properties.insert("resource", pattern);
+            properties.insert("in", "0");
+            QString duration = m_timecode.reformatSeparators(KdenliveSettings::sequence_duration());
+            properties.insert("out", QString::number(m_doc->getFramePos(duration) * count));
+            properties.insert("ttl", QString::number(m_doc->getFramePos(duration)));
+            properties.insert("loop", QString::number(false));
+            properties.insert("crop", QString::number(false));
+            properties.insert("fade", QString::number(false));
+            properties.insert("luma_duration", m_timecode.getTimecodeFromFrames(int(ceil(m_timecode.fps()))));
+                        
+            m_doc->slotCreateSlideshowClipFile(properties, groupInfo.at(0), groupInfo.at(1));
         }
     } else emit displayMessage(i18n("Sequence not found"), -2);
 }
@@ -2689,13 +2764,16 @@ void ProjectList::slotCutClipJob(const QString &id, QPoint zone)
     slotCheckJobProcess();
 }
 
-void ProjectList::slotTranscodeClipJob(QStringList ids, QString params, QString desc)
+void ProjectList::slotTranscodeClipJob(const QString &condition, QString params, QString desc)
 {
     QStringList existingFiles;
+    QStringList ids = getConditionalIds(condition);
+    QStringList destinations;
     foreach(const QString &id, ids) {
         ProjectItem *item = getItemById(id);
         if (!item) continue;
         QString newFile = params.section(' ', -1).replace("%1", item->clipUrl().path());
+        destinations << newFile;
         if (QFile::exists(newFile)) existingFiles << newFile;
     }
     if (!existingFiles.isEmpty()) {
@@ -2706,30 +2784,36 @@ void ProjectList::slotTranscodeClipJob(QStringList ids, QString params, QString
     Ui::CutJobDialog_UI ui;
     ui.setupUi(d);
     d->setWindowTitle(i18n("Transcoding"));
-    ui.destination_label->setVisible(false);
     ui.extra_params->setMaximumHeight(QFontMetrics(font()).lineSpacing() * 5);
-    ui.file_url->setVisible(false);
+    if (ids.count() == 1) {
+        ui.file_url->setUrl(KUrl(destinations.first()));
+    }
+    else {
+        ui.destination_label->setVisible(false);
+        ui.file_url->setVisible(false);
+    }
     ui.extra_params->setVisible(false);
+    d->adjustSize();
     ui.button_more->setIcon(KIcon("configure"));
     ui.add_clip->setChecked(KdenliveSettings::add_clip_cut());
-    ui.extra_params->setPlainText(params.simplified());
+    ui.extra_params->setPlainText(params.simplified().section(" ", 0, -2));
     QString mess = desc;
     mess.append(" " + i18np("(%1 clip)", "(%1 clips)", ids.count()));
     ui.info_label->setText(mess);
-    d->adjustSize();
     if (d->exec() != QDialog::Accepted) {
         delete d;
         return;
     }
     params = ui.extra_params->toPlainText().simplified();
     KdenliveSettings::setAdd_clip_cut(ui.add_clip->isChecked());
-    delete d;
     
     foreach(const QString &id, ids) {
         ProjectItem *item = getItemById(id);
         if (!item || !item->referencedClip()) continue;
         QString src = item->clipUrl().path();
-        QString dest = params.section(' ', -1).replace("%1", src);
+        QString dest;
+        if (ids.count() > 1) dest = params.section(' ', -1).replace("%1", src);
+        else dest = ui.file_url->url().path();
         QStringList jobParams;
         jobParams << dest << src << QString() << QString();
         double clipFps = item->referencedClip()->getProperty("fps").toDouble();
@@ -2738,7 +2822,7 @@ void ProjectList::slotTranscodeClipJob(QStringList ids, QString params, QString
         QString duration = QString::number(max);
         jobParams << duration;
         jobParams << QString::number(KdenliveSettings::add_clip_cut());
-        jobParams << params.section(' ', 0, -2);
+        jobParams << params;
         CutClipJob *job = new CutClipJob(item->clipType(), id, jobParams);
         if (job->isExclusive() && hasPendingJob(item, job->jobType)) {
             delete job;
@@ -2747,12 +2831,11 @@ void ProjectList::slotTranscodeClipJob(QStringList ids, QString params, QString
         m_jobList.append(job);
         setJobStatus(item, job->jobType, JOBWAITING, 0, job->statusMessage());
     }
+    delete d;
     slotCheckJobProcess();
     
 }
 
-
-
 void ProjectList::slotCheckJobProcess()
 {        
     if (!m_jobThreads.futures().isEmpty()) {
@@ -2855,7 +2938,7 @@ void ProjectList::slotProcessJobs()
             emit updateJobStatus(job->clipId(), job->jobType, JOBDONE);
             //TODO: replace with more generic clip replacement framework
             if (job->jobType == PROXYJOB) emit gotProxy(job->clipId());
-            if (job->addClipToProject) {
+            if (job->addClipToProject()) {
                 emit addClip(destination, QString(), QString());
             }
         } else if (job->jobStatus == JOBCRASHED || job->jobStatus == JOBABORTED) {
@@ -3262,17 +3345,82 @@ void ProjectList::slotStartFilterJob(ItemInfo info, const QString&id, const QStr
     if (!item) return;
     QStringList jobParams;
     jobParams << QString::number(info.cropStart.frames(m_fps)) << QString::number((info.cropStart + info.cropDuration).frames(m_fps));
-    jobParams << filterName << filterParams << consumer << consumerParams << properties << QString::number(info.startPos.frames(m_fps)) << QString::number(info.track) << finalFilterName;
+    jobParams << QString() << filterName << filterParams << consumer << consumerParams << properties << QString::number(info.startPos.frames(m_fps)) << QString::number(info.track) << finalFilterName;
     MeltJob *job = new MeltJob(item->clipType(), id, jobParams);
     if (job->isExclusive() && hasPendingJob(item, job->jobType)) {
         delete job;
         return;
     }
+    job->description = i18n("Filter %1", finalFilterName);
     m_jobList.append(job);
     setJobStatus(item, job->jobType, JOBWAITING, 0, job->statusMessage());
     slotCheckJobProcess();
 }
 
+void ProjectList::startClipFilterJob(const QString &filterName, const QString &condition)
+{
+    QStringList ids = getConditionalIds(condition);
+    QString destination;
+    ProjectItem *item = getItemById(ids.at(0));
+    if (!item) {
+        emit displayMessage(i18n("Cannot find clip to process filter %1", filterName), -2);
+        return;
+    }
+    if (ids.count() == 1) {
+        destination = item->clipUrl().path();
+    }
+    else {
+        destination = item->clipUrl().directory();
+    }
+    ClipStabilize *d = new ClipStabilize(destination, ids.count(), filterName);
+    if (d->exec() == QDialog::Accepted) {
+        processClipJob(ids, d->destination(), d->autoAddClip(), d->params(), d->desc());
+    }
+    delete d;
+}
+
+void ProjectList::processClipJob(QStringList ids, const QString&destination, bool autoAdd, QStringList jobParams, const QString &description)
+{
+    QStringList preParams;
+    // in and out
+    preParams << QString::number(0) << QString::number(-1);
+    // producer params
+    preParams << jobParams.takeFirst();
+    // filter name
+    preParams << jobParams.takeFirst();
+    // filter params
+    preParams << jobParams.takeFirst();
+    // consumer
+    QString consumer = jobParams.takeFirst();
+    
+    foreach(const QString&id, ids) {
+        ProjectItem *item = getItemById(id);
+        if (!item) continue;
+        if (ids.count() == 1) {
+            consumer += ":" + destination;
+        }
+        else {
+            consumer += ":" + destination + item->clipUrl().fileName() + ".mlt";
+        }
+        preParams << consumer << jobParams;
+        
+        MeltJob *job = new MeltJob(item->clipType(), id, preParams);
+        if (autoAdd) {
+            job->setAddClipToProject(true);
+            kDebug()<<"// ADDING TRUE";
+        }
+        else kDebug()<<"// ADDING FALSE!!!";
+        if (job->isExclusive() && hasPendingJob(item, job->jobType)) {
+            delete job;
+            return;
+        }
+        job->description = description;
+        m_jobList.append(job);
+        setJobStatus(item, job->jobType, JOBWAITING, 0, job->statusMessage());
+    }
+    slotCheckJobProcess();
+}
+
 void ProjectList::slotPrepareJobsMenu()
 {
     ProjectItem *item;