X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=src%2Fprojectlist.cpp;h=73f91d4fdf6efd94333c18bfca4ba26b8fba21e7;hb=d428e8bbbc881f61872743893518f568401df958;hp=2b0999539d55621a67033f08dce024fc68b5d169;hpb=09aae6cd42927b370af1b7bc7a94db03fd6a7cf6;p=kdenlive diff --git a/src/projectlist.cpp b/src/projectlist.cpp index 2b099953..73f91d4f 100644 --- a/src/projectlist.cpp +++ b/src/projectlist.cpp @@ -19,7 +19,7 @@ #include "projectlist.h" #include "projectitem.h" -#include "addfoldercommand.h" +#include "commands/addfoldercommand.h" #include "kdenlivesettings.h" #include "slideshowclip.h" #include "ui_colorclip_ui.h" @@ -33,10 +33,10 @@ #include "projectlistview.h" #include "timecodedisplay.h" #include "profilesdialog.h" -#include "editclipcommand.h" -#include "editclipcutcommand.h" -#include "editfoldercommand.h" -#include "addclipcutcommand.h" +#include "commands/editclipcommand.h" +#include "commands/editclipcutcommand.h" +#include "commands/editfoldercommand.h" +#include "commands/addclipcutcommand.h" #include "ui_templateclip_ui.h" @@ -115,6 +115,7 @@ ProjectList::ProjectList(QWidget *parent) : m_transcodeAction(NULL), m_doc(NULL), m_refreshed(false), + m_allClipsProcessed(false), m_thumbnailQueue(), m_abortAllProxies(false), m_invalidClipDialog(NULL) @@ -129,10 +130,6 @@ ProjectList::ProjectList(QWidget *parent) : QHBoxLayout *box = new QHBoxLayout; KTreeWidgetSearchLine *searchView = new KTreeWidgetSearchLine; - m_refreshMonitorTimer.setSingleShot(true); - m_refreshMonitorTimer.setInterval(100); - connect(&m_refreshMonitorTimer, SIGNAL(timeout()), this, SLOT(slotRefreshMonitor())); - box->addWidget(searchView); //int s = style()->pixelMetric(QStyle::PM_SmallIconSize); //m_toolbar->setIconSize(QSize(s, s)); @@ -160,7 +157,7 @@ ProjectList::ProjectList(QWidget *parent) : connect(this, SIGNAL(processNextThumbnail()), this, SLOT(slotProcessNextThumbnail())); connect(m_listView, SIGNAL(projectModified()), this, SIGNAL(projectModified())); connect(m_listView, SIGNAL(itemSelectionChanged()), this, SLOT(slotClipSelected())); - connect(m_listView, SIGNAL(focusMonitor()), this, SLOT(slotClipSelected())); + connect(m_listView, SIGNAL(focusMonitor()), this, SIGNAL(raiseClipMonitor())); connect(m_listView, SIGNAL(pauseMonitor()), this, SLOT(slotPauseMonitor())); connect(m_listView, SIGNAL(requestMenu(const QPoint &, QTreeWidgetItem *)), this, SLOT(slotContextMenu(const QPoint &, QTreeWidgetItem *))); connect(m_listView, SIGNAL(addClip()), this, SLOT(slotAddClip())); @@ -257,6 +254,10 @@ void ProjectList::setupGeneratorMenu(QMenu *addMenu, QMenu *transcodeMenu, QMenu m_menu->insertSeparator(m_deleteButton->defaultAction()); } +void ProjectList::clearSelection() +{ + m_listView->clearSelection(); +} QByteArray ProjectList::headerInfo() const { @@ -500,8 +501,8 @@ void ProjectList::slotReloadClip(const QString &id) item = static_cast (selected.at(i)); if (item && !item->isProxyRunning()) { DocClipBase *clip = item->referencedClip(); - if (!clip->isClean()) { - // The clip is currently under processing (replacement in timeline), we cannot reload it now. + if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) { + kDebug()<<"//// TRYING TO RELOAD: "<clipId()<<", but it is busy"; continue; } CLIPTYPE t = item->clipType(); @@ -523,9 +524,7 @@ void ProjectList::slotReloadClip(const QString &id) e.setAttribute("length", length); } } - if (clip) { - clip->clearThumbProducer(); - } + resetThumbsProducer(clip); m_render->getFileProperties(e, item->clipId(), m_listView->iconSize().height(), true); } } @@ -579,7 +578,7 @@ void ProjectList::slotMissingClip(const QString &id) } item->referencedClip()->setProducer(newProd, true); item->slotSetToolTip(); - emit clipNeedsReload(id, true); + emit clipNeedsReload(id); } } update(); @@ -627,7 +626,6 @@ void ProjectList::setRenderer(Render *projectRender) void ProjectList::slotClipSelected() { - m_refreshMonitorTimer.stop(); QTreeWidgetItem *item = m_listView->currentItem(); ProjectItem *clip = NULL; if (item) { @@ -1087,7 +1085,7 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties) m_listView->processLayout(); QDomElement e = clip->toXML().cloneNode().toElement(); e.removeAttribute("file_hash"); - clip->clearThumbProducer(); + resetThumbsProducer(clip); m_render->getFileProperties(e, clip->getId(), m_listView->iconSize().height(), true); } else if (item->hasProxy() && !item->isProxyRunning()) { @@ -1127,11 +1125,11 @@ void ProjectList::slotAddClip(DocClipBase *clip, bool getProperties) void ProjectList::slotGotProxy(const QString &proxyPath) { - if (proxyPath.isEmpty() || !m_refreshed || m_abortAllProxies) return; + if (proxyPath.isEmpty() || m_abortAllProxies) return; QTreeWidgetItemIterator it(m_listView); ProjectItem *item; - while (*it) { + while (*it && !m_abortAllProxies) { if ((*it)->type() == PROJECTCLIPTYPE) { item = static_cast (*it); if (item->referencedClip()->getProperty("proxy") == proxyPath) @@ -1145,11 +1143,12 @@ void ProjectList::slotGotProxy(ProjectItem *item) { if (item == NULL || !m_refreshed) return; DocClipBase *clip = item->referencedClip(); - if (!clip->isClean()) { - //WARNING: might result in clip said marked as proxy but not using proxy? - // The clip is currently under processing (replacement in timeline), we cannot reload it now. + if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) { + // Clip is being reprocessed, abort + kDebug()<<"//// TRYING TO PROXY: "<clipId()<<", but it is busy"; return; } + // Proxy clip successfully created QDomElement e = clip->toXML().cloneNode().toElement(); @@ -1161,20 +1160,24 @@ void ProjectList::slotGotProxy(ProjectItem *item) e.setAttribute("length", length); } } - clip->clearThumbProducer(); + resetThumbsProducer(clip); m_render->getFileProperties(e, clip->getId(), m_listView->iconSize().height(), true); } void ProjectList::slotResetProjectList() { + m_listView->blockSignals(true); m_abortAllProxies = true; m_proxyThreads.waitForFinished(); m_proxyThreads.clearFutures(); m_thumbnailQueue.clear(); m_listView->clear(); + m_listView->setEnabled(true); emit clipSelected(NULL); m_refreshed = false; + m_allClipsProcessed = false; m_abortAllProxies = false; + m_listView->blockSignals(false); } void ProjectList::slotUpdateClip(const QString &id) @@ -1199,13 +1202,35 @@ void ProjectList::getCachedThumbnail(ProjectItem *item) } else item->setData(0, Qt::DecorationRole, pix); } - else requestClipThumbnail(item->clipId()); + else { + requestClipThumbnail(item->clipId()); + } +} + +void ProjectList::getCachedThumbnail(SubProjectItem *item) +{ + if (!item) return; + ProjectItem *parentItem = static_cast (item->parent()); + if (!parentItem) return; + DocClipBase *clip = parentItem->referencedClip(); + if (!clip) return; + int pos = item->zone().x(); + QString cachedPixmap = m_doc->projectFolder().path(KUrl::AddTrailingSlash) + "thumbs/" + clip->getClipHash() + "#" + QString::number(pos) + ".png"; + if (QFile::exists(cachedPixmap)) { + QPixmap pix(cachedPixmap); + if (pix.isNull()) { + KIO::NetAccess::del(KUrl(cachedPixmap), this); + requestClipThumbnail(parentItem->clipId() + '#' + QString::number(pos)); + } + else item->setData(0, Qt::DecorationRole, pix); + } + else requestClipThumbnail(parentItem->clipId() + '#' + QString::number(pos)); } void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged) { + if (!m_allClipsProcessed) m_listView->setEnabled(false); m_listView->setSortingEnabled(false); - QTreeWidgetItemIterator it(m_listView); DocClipBase *clip; ProjectItem *item; @@ -1218,15 +1243,23 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged) QPainter p(&missingPixmap); p.drawPixmap(3, 3, icon.pixmap(width - 6, height - 6)); p.end(); - kDebug()<<"//////////////7 UPDATE ALL CLPS"; + + int max = m_doc->clipManager()->clipsCount(); + max = qMax(1, max); + int ct = 0; + while (*it) { + emit displayMessage(i18n("Loading thumbnails"), (int)(100 *(max - ct++) / max)); if ((*it)->type() == PROJECTSUBCLIPTYPE) { // subitem SubProjectItem *sub = static_cast (*it); - if (displayRatioChanged || sub->data(0, Qt::DecorationRole).isNull()) { + if (displayRatioChanged) { item = static_cast ((*it)->parent()); requestClipThumbnail(item->clipId() + '#' + QString::number(sub->zone().x())); } + else if (sub->data(0, Qt::DecorationRole).isNull()) { + getCachedThumbnail(sub); + } ++it; continue; } else if ((*it)->type() == PROJECTFOLDERTYPE) { @@ -1237,7 +1270,7 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged) item = static_cast (*it); clip = item->referencedClip(); if (item->referencedClip()->getProducer() == NULL) { - if (clip->isPlaceHolder() == false) { + if (clip->isPlaceHolder() == false && !item->isProxyRunning()) { QDomElement xml = clip->toXML(); if (fpsChanged) { xml.removeAttribute("out"); @@ -1245,10 +1278,10 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged) xml.removeAttribute("proxy_out"); } bool replace = xml.attribute("replace") == "1"; - if (replace) clip->clearThumbProducer(); + if (replace) resetThumbsProducer(clip); m_render->getFileProperties(xml, clip->getId(), m_listView->iconSize().height(), replace); } - else { + else if (clip->isPlaceHolder()) { item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDropEnabled); if (item->data(0, Qt::DecorationRole).isNull()) { item->setData(0, Qt::DecorationRole, missingPixmap); @@ -1288,6 +1321,7 @@ void ProjectList::updateAllClips(bool displayRatioChanged, bool fpsChanged) } m_listView->setSortingEnabled(true); + m_allClipsProcessed = true; if (m_render->processingItems() == 0) { monitorItemEditing(true); slotProcessNextThumbnail(); @@ -1569,6 +1603,7 @@ void ProjectList::setDocument(KdenliveDoc *doc) m_listView->setSortingEnabled(false); emit clipSelected(NULL); m_refreshed = false; + m_allClipsProcessed = false; m_fps = doc->fps(); m_timecode = doc->timecode(); m_commandStack = doc->commandStack(); @@ -1585,7 +1620,11 @@ void ProjectList::setDocument(KdenliveDoc *doc) } QList list = doc->clipManager()->documentClipList(); - if (list.isEmpty()) m_refreshed = true; + if (list.isEmpty()) { + // blank document + m_refreshed = true; + m_allClipsProcessed = true; + } for (int i = 0; i < list.count(); i++) slotAddClip(list.at(i), false); @@ -1610,7 +1649,6 @@ QDomElement ProjectList::producersList() QDomDocument doc; QDomElement prods = doc.createElement("producerlist"); doc.appendChild(prods); - kDebug() << "//////////// PRO LIST BUILD PRDSLIST "; QTreeWidgetItemIterator it(m_listView); while (*it) { if ((*it)->type() != PROJECTCLIPTYPE) { @@ -1627,10 +1665,12 @@ QDomElement ProjectList::producersList() void ProjectList::slotCheckForEmptyQueue() { if (m_render->processingItems() == 0 && m_thumbnailQueue.isEmpty()) { - if (!m_refreshed) { - emit loadingIsOver(); - emit displayMessage(QString(), -1); + if (!m_refreshed && m_allClipsProcessed) { m_refreshed = true; + m_listView->setEnabled(true); + slotClipSelected(); + QTimer::singleShot(500, this, SIGNAL(loadingIsOver())); + emit displayMessage(QString(), -1); } updateButtons(); } else if (!m_refreshed) { @@ -1645,6 +1685,14 @@ void ProjectList::requestClipThumbnail(const QString id) slotProcessNextThumbnail(); } +void ProjectList::resetThumbsProducer(DocClipBase *clip) +{ + if (!clip) return; + clip->clearThumbProducer(); + QString id = clip->getId(); + m_thumbnailQueue.removeAll(id); +} + void ProjectList::slotProcessNextThumbnail() { if (m_render->processingItems() > 0) { @@ -1707,11 +1755,14 @@ void ProjectList::slotRefreshClipThumbnail(QTreeWidgetItem *it, bool update) monitorItemEditing(false); it->setData(0, Qt::DecorationRole, pix); monitorItemEditing(true); - - if (!isSubItem) - m_doc->cachePixmap(item->getClipHash(), pix); - else - m_doc->cachePixmap(item->getClipHash() + '#' + QString::number(frame), pix); + + QString clipId = item->getClipHash(); + if (!clipId.isEmpty()) { + if (!isSubItem) + m_doc->cachePixmap(clipId, pix); + else + m_doc->cachePixmap(clipId + '#' + QString::number(frame), pix); + } } if (update) emit projectModified(); @@ -1719,26 +1770,13 @@ void ProjectList::slotRefreshClipThumbnail(QTreeWidgetItem *it, bool update) } } -void ProjectList::slotRefreshMonitor() -{ - if (m_listView->selectedItems().count() == 1 && m_render && m_render->processingItems() == 0) { - if (m_listView->currentItem() && m_listView->currentItem()->type() != PROJECTFOLDERTYPE) { - ProjectItem *item = static_cast (m_listView->currentItem()); - DocClipBase *clip = item->referencedClip(); - if (clip && clip->isClean()) emit clipSelected(clip); - } - } -} -void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Producer *producer, const stringMap &properties, const stringMap &metadata, bool replace, bool refreshThumbnail) +void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Producer *producer, const stringMap &properties, const stringMap &metadata, bool replace) { QString toReload; ProjectItem *item = getItemById(clipId); int queue = m_render->processingItems(); - if (queue == 0) { - m_listView->setEnabled(true); - } if (item && producer) { monitorItemEditing(false); DocClipBase *clip = item->referencedClip(); @@ -1749,10 +1787,10 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce } item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsEditable | Qt::ItemIsDropEnabled); } - clip->setProducer(producer, replace); item->setProperties(properties, metadata); + clip->setProducer(producer, replace); clip->askForAudioThumbs(); - if (refreshThumbnail) getCachedThumbnail(item); + // Proxy stuff QString size = properties.value("frame_size"); if (!useProxy() && clip->getProperty("proxy").isEmpty()) setProxyStatus(item, NOPROXY); @@ -1780,8 +1818,8 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce } } - if (!replace && item->data(0, Qt::DecorationRole).isNull() && !refreshThumbnail) { - requestClipThumbnail(clipId); + if (!replace && m_allClipsProcessed && item->data(0, Qt::DecorationRole).isNull()) { + getCachedThumbnail(item); } if (!toReload.isEmpty()) item->slotSetToolTip(); @@ -1794,7 +1832,7 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce if (item->parent()) { if (item->parent()->type() == PROJECTFOLDERTYPE) static_cast (item->parent())->switchIcon(); - } else if (KdenliveSettings::checkfirstprojectclip() && m_listView->topLevelItemCount() == 1) { + } else if (KdenliveSettings::checkfirstprojectclip() && m_listView->topLevelItemCount() == 1 && m_refreshed && m_allClipsProcessed) { // this is the first clip loaded in project, check if we want to adjust project settings to the clip updatedProfile = adjustProjectProfileToItem(item); } @@ -1803,23 +1841,18 @@ void ProjectList::slotReplyGetFileProperties(const QString &clipId, Mlt::Produce } } else { int max = m_doc->clipManager()->clipsCount(); - emit displayMessage(i18n("Loading clips"), (int)(100 *(max - queue) / max)); + if (max > 0) emit displayMessage(i18n("Loading clips"), (int)(100 *(max - queue) / max)); } - processNextThumbnail(); - } - if (replace && item) { - if (item->numReferences() > 0) toReload = clipId; - else item->referencedClip()->cleanupProducers(); - // update clip in clip monitor - if (queue == 0 && item->isSelected() && m_listView->selectedItems().count() == 1) - m_refreshMonitorTimer.start(); + if (m_allClipsProcessed) emit processNextThumbnail(); } if (!item) { // no item for producer, delete it delete producer; + return; } + if (replace) toReload = clipId; if (!toReload.isEmpty()) - emit clipNeedsReload(toReload, true); + emit clipNeedsReload(toReload); } bool ProjectList::adjustProjectProfileToItem(ProjectItem *item) @@ -1921,7 +1954,8 @@ void ProjectList::setThumbnail(const QString &clipId, const QPixmap &pix) item->setData(0, Qt::DecorationRole, pix); monitorItemEditing(true); //update(); - m_doc->cachePixmap(item->getClipHash(), pix); + QString clipId = item->getClipHash(); + if (!clipId.isEmpty()) m_doc->cachePixmap(clipId, pix); } } @@ -2120,7 +2154,8 @@ void ProjectList::addClipCut(const QString &id, int in, int out, const QString d } QPixmap p = clip->referencedClip()->extractImage(in, (int)(sub->sizeHint(0).height() * m_render->dar()), sub->sizeHint(0).height() - 2); sub->setData(0, Qt::DecorationRole, p); - m_doc->cachePixmap(clip->getClipHash() + '#' + QString::number(in), p); + QString clipId = clip->getClipHash(); + if (!clipId.isEmpty()) m_doc->cachePixmap(clipId + '#' + QString::number(in), p); monitorItemEditing(true); } emit projectModified(); @@ -2308,6 +2343,19 @@ void ProjectList::slotGenerateProxy() QFile::remove(info.dest); setProxyStatus(info.dest, CREATINGPROXY); + + // Get the list of clips that will need to get progress info + QTreeWidgetItemIterator it(m_listView); + QList processingItems; + while (*it && !m_abortAllProxies) { + if ((*it)->type() == PROJECTCLIPTYPE) { + ProjectItem *item = static_cast (*it); + if (item->referencedClip()->getProperty("proxy") == info.dest) { + processingItems.append(item); + } + } + ++it; + } // Special case: playlist clips (.mlt or .kdenlive project files) if (info.type == PLAYLIST) { @@ -2352,7 +2400,7 @@ void ProjectList::slotGenerateProxy() } else { QString log = QString(myProcess.readAll()); - processLogInfo(info.dest, &duration, log); + processLogInfo(processingItems, &duration, log); } myProcess.waitForFinished(500); } @@ -2368,8 +2416,8 @@ void ProjectList::slotGenerateProxy() // Proxy process crashed QFile::remove(info.dest); setProxyStatus(info.dest, PROXYCRASHED); - } - + } + return; } if (info.type == IMAGE) { @@ -2435,13 +2483,13 @@ void ProjectList::slotGenerateProxy() // Make sure we don't block when proxy file already exists parameters << "-y"; parameters << info.dest; - kDebug()<<"// STARTING PROXY GEN: "<items, int *duration, const QString &log) { int progress; if (*duration == 0) { @@ -2494,7 +2542,8 @@ void ProjectList::processLogInfo(const QString &path, int *duration, const QStri progress = numbers.at(0).toInt() * 3600 + numbers.at(1).toInt() * 60 + numbers.at(2).toDouble(); } else progress = (int) time.toDouble(); - setProxyStatus(path, CREATINGPROXY, (int) (100.0 * progress / (*duration))); + for (int i = 0; i < items.count(); i++) + setProxyStatus(items.at(i), CREATINGPROXY, (int) (100.0 * progress / (*duration))); } } @@ -2601,12 +2650,19 @@ void ProjectList::slotProxyCurrentItem(bool doProxy) CLIPTYPE t = item->clipType(); if ((t == VIDEO || t == AV || t == UNKNOWN || t == IMAGE || t == PLAYLIST) && item->referencedClip()) { if ((doProxy && item->hasProxy()) || (!doProxy && !item->hasProxy())) continue; - oldProps = item->referencedClip()->properties(); + DocClipBase *clip = item->referencedClip(); + if (!clip || !clip->isClean() || m_render->isProcessing(item->clipId())) { + kDebug()<<"//// TRYING TO PROXY: "<clipId()<<", but it is busy"; + continue; + } + + resetThumbsProducer(clip); + oldProps = clip->properties(); if (doProxy) { newProps.clear(); - QString path = proxydir + item->referencedClip()->getClipHash() + "." + (t == IMAGE ? "png" : m_doc->getDocumentProperty("proxyextension")); + QString path = proxydir + clip->getClipHash() + "." + (t == IMAGE ? "png" : m_doc->getDocumentProperty("proxyextension")); // insert required duration for proxy - newProps.insert("proxy_out", item->referencedClip()->producerProperty("out")); + newProps.insert("proxy_out", clip->producerProperty("out")); newProps.insert("proxy", path); // We need to insert empty proxy so that undo will work oldProps.insert("proxy", QString()); @@ -2653,7 +2709,7 @@ void ProjectList::setProxyStatus(const QString proxyPath, PROXYSTATUS status, in if (proxyPath.isEmpty() || m_abortAllProxies) return; QTreeWidgetItemIterator it(m_listView); ProjectItem *item; - while (*it) { + while (*it && !m_abortAllProxies) { if ((*it)->type() == PROJECTCLIPTYPE) { item = static_cast (*it); if (item->referencedClip()->getProperty("proxy") == proxyPath) {