X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fprojectlist.cpp;h=8f42095eb9b5c3805320b325cdf397aa0c9cf255;hb=cbb9753eeb0a66dff9371ae9c0e31438ccfd4158;hp=b61b8ca1fc78b2ba56fa6aefce10c6fe61198714;hpb=d7e79e1131d5355bc606522988b8de301b4b7004;p=kdenlive diff --git a/src/projectlist.cpp b/src/projectlist.cpp index b61b8ca1..8f42095e 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -202,6 +202,11 @@ void ProjectList::setHeaderInfo(const QByteArray &state) m_listView->header()->restoreState(state); } +void ProjectList::updateProjectFormat(Timecode t) +{ + m_timecode = t; +} + void ProjectList::slotEditClip() { QList list = m_listView->selectedItems(); @@ -233,6 +238,8 @@ void ProjectList::editClipSelection(QList list) commonproperties.insert("video_index", "-"); commonproperties.insert("audio_index", "-"); + bool allowDurationChange = true; + int commonDuration = -1; ProjectItem *item; for (int i = 0; i < list.count(); i++) { item = NULL; @@ -245,6 +252,16 @@ void ProjectList::editClipSelection(QList list) // check properties DocClipBase *clip = item->referencedClip(); if (clipList.contains(clip)) continue; + if (clip->clipType() != COLOR && clip->clipType() != IMAGE && clip->clipType() != TEXT) { + allowDurationChange = false; + } + if (allowDurationChange && commonDuration != 0) { + if (commonDuration == -1) { + commonDuration = clip->duration().frames(m_fps); + } else if (commonDuration != clip->duration().frames(m_fps)) { + commonDuration = 0; + } + } clipList.append(clip); QMap clipprops = clip->properties(); QMapIterator p(commonproperties); @@ -258,6 +275,7 @@ void ProjectList::editClipSelection(QList list) } } } + if (allowDurationChange) commonproperties.insert("out", QString::number(commonDuration)); QMapIterator p(commonproperties); while (p.hasNext()) { p.next(); @@ -337,7 +355,7 @@ void ProjectList::trashUnusedClips() it2++; } - m_doc->deleteProjectClip(ids); + emit deleteProjectClips(ids, QMap ()); for (int i = 0; i < urls.count(); i++) { KIO::NetAccess::del(KUrl(urls.at(i)), this); } @@ -373,6 +391,7 @@ void ProjectList::setRenderer(Render *projectRender) void ProjectList::slotClipSelected() { + if (!m_listView->isEnabled()) return; if (m_listView->currentItem()) { if (m_listView->currentItem()->type() == PROJECTFOLDERTYPE) { emit clipSelected(NULL); @@ -390,21 +409,24 @@ void ProjectList::slotClipSelected() if (clip == NULL) kDebug() << "-----------ERROR"; SubProjectItem *sub = static_cast (m_listView->currentItem()); emit clipSelected(clip->referencedClip(), sub->zone()); + m_transcodeAction->setEnabled(false); return; } clip = static_cast (m_listView->currentItem()); - emit clipSelected(clip->referencedClip()); + if (clip) emit clipSelected(clip->referencedClip()); m_editAction->setEnabled(true); m_deleteAction->setEnabled(true); m_reloadAction->setEnabled(true); m_transcodeAction->setEnabled(true); - if (clip->clipType() == IMAGE && !KdenliveSettings::defaultimageapp().isEmpty()) { + if (clip && clip->clipType() == IMAGE && !KdenliveSettings::defaultimageapp().isEmpty()) { m_openAction->setIcon(KIcon(KdenliveSettings::defaultimageapp())); m_openAction->setEnabled(true); - } else if (clip->clipType() == AUDIO && !KdenliveSettings::defaultaudioapp().isEmpty()) { + } else if (clip && clip->clipType() == AUDIO && !KdenliveSettings::defaultaudioapp().isEmpty()) { m_openAction->setIcon(KIcon(KdenliveSettings::defaultaudioapp())); m_openAction->setEnabled(true); } else m_openAction->setEnabled(false); + // Display relevant transcoding actions only + adjustTranscodeActions(clip); } } else { emit clipSelected(NULL); @@ -416,6 +438,27 @@ void ProjectList::slotClipSelected() } } +void ProjectList::adjustTranscodeActions(ProjectItem *clip) const +{ + if (clip == NULL || clip->type() != PROJECTCLIPTYPE || clip->clipType() == COLOR || clip->clipType() == TEXT || clip->clipType() == PLAYLIST) { + m_transcodeAction->setEnabled(false); + return; + } + m_transcodeAction->setEnabled(true); + QList transcodeActions = m_transcodeAction->actions(); + QStringList data; + QString condition; + for (int i = 0; i < transcodeActions.count(); i++) { + data = transcodeActions.at(i)->data().toStringList(); + if (data.count() > 2) { + condition = data.at(2); + if (condition.startsWith("vcodec")) transcodeActions.at(i)->setEnabled(clip->referencedClip()->hasVideoCodec(condition.section("=", 1, 1))); + else if (condition.startsWith("acodec")) transcodeActions.at(i)->setEnabled(clip->referencedClip()->hasVideoCodec(condition.section("=", 1, 1))); + } + } + +} + void ProjectList::slotPauseMonitor() { if (m_render) m_render->pause(); @@ -536,7 +579,12 @@ void ProjectList::slotContextMenu(const QPoint &pos, QTreeWidgetItem *item) ProjectItem *clip = NULL; if (m_listView->currentItem()->type() == PROJECTSUBCLIPTYPE) { clip = static_cast (item->parent()); - } else if (m_listView->currentItem()->type() == PROJECTCLIPTYPE) clip = static_cast (item); + m_transcodeAction->setEnabled(false); + } else if (m_listView->currentItem()->type() == PROJECTCLIPTYPE) { + clip = static_cast (item); + // Display relevant transcoding actions only + adjustTranscodeActions(clip); + } else m_transcodeAction->setEnabled(false); if (clip && clip->clipType() == IMAGE && !KdenliveSettings::defaultimageapp().isEmpty()) { m_openAction->setIcon(KIcon(KdenliveSettings::defaultimageapp())); m_openAction->setEnabled(true); @@ -544,6 +592,7 @@ void ProjectList::slotContextMenu(const QPoint &pos, QTreeWidgetItem *item) m_openAction->setIcon(KIcon(KdenliveSettings::defaultaudioapp())); m_openAction->setEnabled(true); } else m_openAction->setEnabled(false); + } else m_openAction->setEnabled(false); m_menu->popup(pos); } @@ -570,7 +619,7 @@ void ProjectList::slotRemoveClip() folderids[folder->groupName()] = folder->clipId(); int children = folder->childCount(); - if (children > 0 && KMessageBox::questionYesNo(this, i18np("Delete folder %2?
This will also remove the clip in that folder", "Delete folder %2?
This will also remove the %1 clips in that folder", children, folder->text(1)), i18n("Delete Folder")) != KMessageBox::Yes) return; + if (children > 0 && KMessageBox::questionYesNo(this, i18np("Delete folder %2?
This will also remove the clip in that folder", "Delete folder %2?
This will also remove the %1 clips in that folder", children, folder->text(1)), i18n("Delete Folder")) != KMessageBox::Yes) return; for (int i = 0; i < children; ++i) { ProjectItem *child = static_cast (folder->child(i)); ids << child->clipId(); @@ -579,22 +628,37 @@ void ProjectList::slotRemoveClip() ProjectItem *item = static_cast (selected.at(i)); ids << item->clipId(); if (item->numReferences() > 0) { - if (KMessageBox::questionYesNo(this, i18np("Delete clip %2?
This will also remove the clip in timeline", "Delete clip %2?
This will also remove its %1 clips in timeline", item->numReferences(), item->names().at(1)), i18n("Delete Clip")) != KMessageBox::Yes) return; + if (KMessageBox::questionYesNo(this, i18np("Delete clip %2?
This will also remove the clip in timeline", "Delete clip %2?
This will also remove its %1 clips in timeline", item->numReferences(), item->names().at(1)), i18n("Delete Clip")) != KMessageBox::Yes) return; } } } if (delCommand->childCount() == 0) delete delCommand; else m_commandStack->push(delCommand); - if (!ids.isEmpty()) m_doc->deleteProjectClip(ids); - if (!folderids.isEmpty()) deleteProjectFolder(folderids); + emit deleteProjectClips(ids, folderids); +} + +void ProjectList::updateButtons() const +{ if (m_listView->topLevelItemCount() == 0) { - m_editAction->setEnabled(false); m_deleteAction->setEnabled(false); - m_openAction->setEnabled(false); - m_reloadAction->setEnabled(false); - m_transcodeAction->setEnabled(false); + } else { + m_deleteAction->setEnabled(true); + if (!m_listView->currentItem()) m_listView->setCurrentItem(m_listView->topLevelItem(0)); + QTreeWidgetItem *item = m_listView->currentItem(); + if (item && item->type() == PROJECTCLIPTYPE) { + m_editAction->setEnabled(true); + m_openAction->setEnabled(true); + m_reloadAction->setEnabled(true); + m_transcodeAction->setEnabled(true); + return; + } } + + m_editAction->setEnabled(false); + m_openAction->setEnabled(false); + m_reloadAction->setEnabled(false); + m_transcodeAction->setEnabled(false); } void ProjectList::selectItemById(const QString &clipId) @@ -612,10 +676,13 @@ void ProjectList::slotDeleteClip(const QString &clipId) return; } m_listView->blockSignals(true); + QTreeWidgetItem *newSelectedItem = m_listView->itemAbove(item); + if (!newSelectedItem) newSelectedItem = m_listView->itemBelow(item); delete item; m_doc->clipManager()->deleteClip(clipId); m_listView->blockSignals(false); - slotClipSelected(); + if (newSelectedItem) m_listView->setCurrentItem(newSelectedItem); + else updateButtons(); } @@ -638,7 +705,11 @@ void ProjectList::slotAddFolder(const QString foldername, const QString &clipId, FolderProjectItem *item = getFolderItemById(clipId); if (item) { m_doc->clipManager()->deleteFolder(clipId); + QTreeWidgetItem *newSelectedItem = m_listView->itemAbove(item); + if (!newSelectedItem) newSelectedItem = m_listView->itemBelow(item); delete item; + if (newSelectedItem) m_listView->setCurrentItem(newSelectedItem); + else updateButtons(); } } else { if (edit) { @@ -662,6 +733,7 @@ void ProjectList::slotAddFolder(const QString foldername, const QString &clipId, m_doc->clipManager()->addFolder(clipId, foldername); m_listView->blockSignals(false); } + updateButtons(); } m_doc->setModified(true); } @@ -690,6 +762,7 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties) QDomElement e = clip->toXML().cloneNode().toElement(); e.removeAttribute("file_hash"); m_infoQueue.insert(clip->getId(), e); + clip->askForAudioThumbs(); //m_render->getFileProperties(clip->toXML(), clip->getId(), true); } const QString parent = clip->getProperty("groupid"); @@ -714,7 +787,9 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties) if (getProperties == false && !clip->getClipHash().isEmpty()) { QString cachedPixmap = m_doc->projectFolder().path(KUrl::AddTrailingSlash) + "thumbs/" + clip->getClipHash() + ".png"; if (QFile::exists(cachedPixmap)) { - item->setData(0, Qt::DecorationRole, QPixmap(cachedPixmap)); + QPixmap pix(cachedPixmap); + if (pix.isNull()) KIO::NetAccess::del(KUrl(cachedPixmap), this); + item->setData(0, Qt::DecorationRole, pix); } } #ifdef NEPOMUK @@ -734,13 +809,17 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties) if (!clip->getClipHash().isEmpty()) { QString cachedPixmap = m_doc->projectFolder().path(KUrl::AddTrailingSlash) + "thumbs/" + clip->getClipHash() + '#' + QString::number(cuts.at(i).zone.x()) + ".png"; if (QFile::exists(cachedPixmap)) { - sub->setData(0, Qt::DecorationRole, QPixmap(cachedPixmap)); + QPixmap pix(cachedPixmap); + if (pix.isNull()) KIO::NetAccess::del(KUrl(cachedPixmap), this); + sub->setData(0, Qt::DecorationRole, pix); } } } } - - if (getProperties && m_listView->isEnabled()) m_listView->blockSignals(false); + if (m_listView->isEnabled()) { + updateButtons(); + if (getProperties) m_listView->blockSignals(false); + } if (getProperties && !m_queueTimer.isActive()) m_queueTimer.start(); } @@ -780,7 +859,7 @@ void ProjectList::slotUpdateClip(const QString &id) { ProjectItem *item = getItemById(id); m_listView->blockSignals(true); - if (item) item->setData(1, UsageRole, QString::number(item->numReferences())); + if (item) item->setData(0, UsageRole, QString::number(item->numReferences())); m_listView->blockSignals(false); } @@ -813,7 +892,7 @@ void ProjectList::updateAllClips() if (item->referencedClip()->producer() == NULL) { if (clip->isPlaceHolder() == false) { requestClipInfo(clip->toXML(), clip->getId()); - } else item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); + } else if (!clip->isPlaceHolder()) item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled); } else { if (item->data(0, Qt::DecorationRole).isNull()) { requestClipThumbnail(clip->getId()); @@ -822,7 +901,7 @@ void ProjectList::updateAllClips() item->changeDuration(item->referencedClip()->producer()->get_playtime()); } } - item->setData(1, UsageRole, QString::number(item->numReferences())); + item->setData(0, UsageRole, QString::number(item->numReferences())); } //qApp->processEvents(); ++it; @@ -841,7 +920,7 @@ void ProjectList::slotAddClip(const QList givenList, const QString &group KUrl::List list; if (givenList.isEmpty()) { // Build list of mime types - QStringList mimeTypes = QStringList() << "application/x-kdenlive" << "application/x-kdenlivetitle" << "video/x-flv" << "application/vnd.rn-realmedia" << "video/x-dv" << "video/dv" << "video/x-msvideo" << "video/x-matroska" << "video/mlt-playlist" << "video/mpeg" << "video/ogg" << "video/x-ms-wmv" << "audio/x-flac" << "audio/x-matroska" << "audio/mp4" << "audio/mpeg" << "audio/x-mp3" << "audio/ogg" << "audio/x-wav" << "application/ogg" << "video/mp4" << "video/quicktime" << "image/gif" << "image/jpeg" << "image/png" << "image/x-tga" << "image/x-bmp" << "image/svg+xml" << "image/tiff" << "image/x-xcf-gimp" << "image/x-vnd.adobe.photoshop" << "image/x-pcx" << "image/x-exr"; + QStringList mimeTypes = QStringList() << "application/x-kdenlive" << "application/x-kdenlivetitle" << "video/x-flv" << "application/vnd.rn-realmedia" << "video/x-dv" << "video/dv" << "video/x-msvideo" << "video/x-matroska" << "video/mlt-playlist" << "video/mpeg" << "video/ogg" << "video/x-ms-wmv" << "audio/x-flac" << "audio/x-matroska" << "audio/mp4" << "audio/mpeg" << "audio/x-mp3" << "audio/ogg" << "audio/x-wav" << "application/ogg" << "video/mp4" << "video/quicktime" << "image/gif" << "image/jpeg" << "image/png" << "image/x-tga" << "image/x-bmp" << "image/svg+xml" << "image/tiff" << "image/x-xcf" << "image/x-xcf-gimp" << "image/x-vnd.adobe.photoshop" << "image/x-pcx" << "image/x-exr"; QString allExtensions; foreach(const QString& mimeType, mimeTypes) { @@ -882,15 +961,16 @@ void ProjectList::slotRemoveInvalidClip(const QString &id, bool replace) QTimer::singleShot(300, this, SLOT(slotProcessNextClipInQueue())); if (item) { const QString path = item->referencedClip()->fileURL().path(); + if (item->referencedClip()->isPlaceHolder()) replace = false; if (!path.isEmpty()) { - if (replace) KMessageBox::sorry(this, i18n("Clip %1
is invalid, will be removed from project.", path)); + if (replace) KMessageBox::sorry(this, i18n("Clip %1
is invalid, will be removed from project.", path)); else { - if (KMessageBox::questionYesNo(this, i18n("Clip %1
is missing or invalid. Remove it from project?", path), i18n("Invalid clip")) == KMessageBox::Yes) replace = true; + if (KMessageBox::questionYesNo(this, i18n("Clip %1
is missing or invalid. Remove it from project?", path), i18n("Invalid clip")) == KMessageBox::Yes) replace = true; } } QStringList ids; ids << id; - if (replace) m_doc->deleteProjectClip(ids); + if (replace) emit deleteProjectClips(ids, QMap ()); } } @@ -902,8 +982,10 @@ void ProjectList::slotAddColorClip() QDialog *dia = new QDialog(this); Ui::ColorClip_UI dia_ui; dia_ui.setupUi(dia); + dia->setWindowTitle(i18n("Color Clip")); dia_ui.clip_name->setText(i18n("Color Clip")); - dia_ui.clip_duration->setText(KdenliveSettings::color_duration()); + dia_ui.clip_duration->setInputMask(m_timecode.inputMask()); + dia_ui.clip_duration->setText(m_timecode.reformatSeparators(KdenliveSettings::color_duration())); if (dia->exec() == QDialog::Accepted) { QString color = dia_ui.clip_color->color().name(); color = color.replace(0, 1, "0x") + "ff"; @@ -1048,6 +1130,7 @@ void ProjectList::slotCheckForEmptyQueue() emit displayMessage(QString(), -1); m_listView->blockSignals(false); m_listView->setEnabled(true); + updateButtons(); } else if (!m_refreshed) QTimer::singleShot(300, this, SLOT(slotCheckForEmptyQueue())); } @@ -1140,12 +1223,19 @@ void ProjectList::slotRefreshClipThumbnail(QTreeWidgetItem *it, bool update) void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Producer *producer, const QMap < QString, QString > &properties, const QMap < QString, QString > &metadata, bool replace) { + QString toReload; ProjectItem *item = getItemById(clipId); if (item && producer) { m_listView->blockSignals(true); item->setProperties(properties, metadata); + if (item->referencedClip()->isPlaceHolder() && producer->is_valid()) { + item->referencedClip()->setValid(); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsEditable); + toReload = clipId; + } //Q_ASSERT_X(item->referencedClip(), "void ProjectList::slotReplyGetFileProperties", QString("Item with groupName %1 does not have a clip associated").arg(item->groupName()).toLatin1()); item->referencedClip()->setProducer(producer, replace); + item->referencedClip()->askForAudioThumbs(); if (!replace && item->data(0, Qt::DecorationRole).isNull()) { requestClipThumbnail(clipId); } @@ -1154,6 +1244,8 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce // update clip in clip monitor emit clipSelected(NULL); emit clipSelected(item->referencedClip()); + //TODO: Make sure the line below has no side effect + toReload = clipId; } /*else { // Check if duration changed. @@ -1166,12 +1258,12 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce }*/ } else kDebug() << "//////// COULD NOT FIND CLIP TO UPDATE PRPS..."; int max = m_doc->clipManager()->clipsCount(); - emit displayMessage(i18n("Loading clips"), (int)(100 *(max - m_infoQueue.count()) / max)); - // small delay so that the app can display the progress info if (item && m_infoQueue.isEmpty() && m_thumbnailQueue.isEmpty()) { m_listView->setCurrentItem(item); emit clipSelected(item->referencedClip()); - } + } else emit displayMessage(i18n("Loading clips"), (int)(100 *(max - m_infoQueue.count()) / max)); + if (!toReload.isEmpty()) emit clipNeedsReload(toReload, true); + // small delay so that the app can display the progress info QTimer::singleShot(30, this, SLOT(slotProcessNextClipInQueue())); }