Commit 806031da authored by Nicolas Carion's avatar Nicolas Carion
Browse files

model updates are now applied independently

parent bc489c07
......@@ -15,6 +15,8 @@ else()
PURPOSE "")
endif()
SET(CMAKE_CXX_STANDARD 14)
SET(CMAKE_CXX_STANDARD_REQUIRED ON)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -Wall -pedantic -Wextra")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wcast-qual -Wcast-align -Wfloat-equal -Wpointer-arith")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunreachable-code -Wchar-subscripts -Wcomment -Wformat")
......
......@@ -264,13 +264,13 @@ std::shared_ptr<AbstractProjectItem> AbstractProjectItem::getEnclosingFolder(boo
return std::shared_ptr<AbstractProjectItem>();
}
bool AbstractProjectItem::selfSoftDelete(Fun &undo, Fun &redo)
bool AbstractProjectItem::selfSoftDelete(Fun &undo, Fun &redo, Updates &list)
{
pCore->jobManager()->slotDiscardClipJobs(clipId());
Fun local_undo = []() { return true; };
Fun local_redo = []() { return true; };
for (const auto &child : m_childItems) {
bool res = std::static_pointer_cast<AbstractProjectItem>(child)->selfSoftDelete(local_undo, local_redo);
bool res = std::static_pointer_cast<AbstractProjectItem>(child)->selfSoftDelete(local_undo, local_redo, list);
if (!res) {
bool undone = local_undo();
Q_ASSERT(undone);
......
......@@ -24,6 +24,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define ABSTRACTPROJECTITEM_H
#include "abstractmodel/treeitem.hpp"
#include "timeline2/model/modelupdater.hpp"
#include "undohelper.hpp"
#include <QDateTime>
......@@ -84,7 +85,7 @@ public:
However, the object is NOT actually deleted, and the tree structure is preserved.
@param Undo,Redo are the lambdas accumulating the update.
*/
virtual bool selfSoftDelete(Fun &undo, Fun &redo);
virtual bool selfSoftDelete(Fun &undo, Fun &redo, Updates &list);
/** @brief Returns the clip's id. */
const QString &clipId() const;
......
......@@ -48,6 +48,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "projectitemmodel.h"
#include "projectsortproxymodel.h"
#include "projectsubclip.h"
#include "timeline2/model/modelupdater.hpp"
#include "titler/titlewidget.h"
#include "ui_qtextclip_ui.h"
#include "undohelper.hpp"
......@@ -994,9 +995,11 @@ void Bin::slotDeleteClip()
}
Fun undo = []() { return true; };
Fun redo = []() { return true; };
Updates list;
for (const auto &item : items) {
m_itemModel->requestBinClipDeletion(item, undo, redo);
m_itemModel->requestBinClipDeletion(item, undo, redo, list);
}
ModelUpdater::applyUpdates(undo, redo, list);
pCore->pushUndo(undo, redo, i18n("Delete bin Clips"));
}
......@@ -1777,7 +1780,6 @@ void Bin::slotRemoveInvalidClip(const QString &id, bool replace, const QString &
emit requesteInvalidRemoval(id, clip->url(), errorMessage);
}
// TODO refac cleanup
/*
void Bin::slotProducerReady(const requestClipInfo &info, std::shared_ptr<Mlt::Producer> producer)
......@@ -2804,10 +2806,12 @@ void Bin::slotQueryRemoval(const QString &id, const QString &url, const QString
const QStringList ids = m_invalidClipDialog->getIds();
Fun undo = []() { return true; };
Fun redo = []() { return true; };
Updates list;
for (const QString &i : ids) {
auto item = m_itemModel->getClipByBinID(i);
m_itemModel->requestBinClipDeletion(item, undo, redo);
m_itemModel->requestBinClipDeletion(item, undo, redo, list);
}
ModelUpdater::applyUpdates(undo, redo, list);
}
delete m_invalidClipDialog;
m_invalidClipDialog = nullptr;
......
......@@ -1161,7 +1161,7 @@ QList<int> ProjectClip::timelineInstances() const
return ids;
}
bool ProjectClip::selfSoftDelete(Fun &undo, Fun &redo)
bool ProjectClip::selfSoftDelete(Fun &undo, Fun &redo, Updates &list)
{
auto toDelete = m_registeredClips; // we cannot use m_registeredClips directly, because it will be modified during loop
for (const auto &clip : toDelete) {
......@@ -1170,14 +1170,14 @@ bool ProjectClip::selfSoftDelete(Fun &undo, Fun &redo)
continue;
}
if (auto timeline = clip.second.lock()) {
timeline->requestItemDeletion(clip.first, undo, redo);
timeline->requestItemDeletion(clip.first, undo, redo, list);
} else {
qDebug() << "Error while deleting clip: timeline unavailable";
Q_ASSERT(false);
return false;
}
}
return AbstractProjectItem::selfSoftDelete(undo, redo);
return AbstractProjectItem::selfSoftDelete(undo, redo, list);
}
bool ProjectClip::isIncludedInTimeline()
......
......@@ -103,7 +103,7 @@ public:
/** @brief Returns the clip type as defined in definitions.h */
ClipType::ProducerType clipType() const;
bool selfSoftDelete(Fun &undo, Fun &redo) override;
bool selfSoftDelete(Fun &undo, Fun &redo, Updates &list) override;
/** @brief Check if clip has a parent folder with id id */
bool hasParent(const QString &id) const;
......
......@@ -385,9 +385,12 @@ void ProjectItemModel::clean()
}
Fun undo = []() { return true; };
Fun redo = []() { return true; };
Updates list;
for (const auto &child : toDelete) {
requestBinClipDeletion(child, undo, redo);
requestBinClipDeletion(child, undo, redo, list);
}
ModelUpdater::applyUpdates(undo, redo, list);
Q_ASSERT(rootItem->childCount() == 0);
m_nextId = 1;
m_fileWatcher->clear();
......@@ -436,14 +439,14 @@ std::shared_ptr<AbstractProjectItem> ProjectItemModel::getBinItemByIndex(const Q
return std::static_pointer_cast<AbstractProjectItem>(getItemById((int)index.internalId()));
}
bool ProjectItemModel::requestBinClipDeletion(std::shared_ptr<AbstractProjectItem> clip, Fun &undo, Fun &redo)
bool ProjectItemModel::requestBinClipDeletion(std::shared_ptr<AbstractProjectItem> clip, Fun &undo, Fun &redo, Updates &list)
{
QWriteLocker locker(&m_lock);
Q_ASSERT(clip);
if (!clip) return false;
int parentId = -1;
if (auto ptr = clip->parent()) parentId = ptr->getId();
clip->selfSoftDelete(undo, redo);
clip->selfSoftDelete(undo, redo, list);
int id = clip->getId();
Fun operation = removeItem_lambda(id);
Fun reverse = addItem_lambda(clip, parentId);
......@@ -660,6 +663,7 @@ bool ProjectItemModel::requestCleanup()
{
Fun undo = []() { return true; };
Fun redo = []() { return true; };
Updates list;
bool res = true;
std::vector<std::shared_ptr<AbstractProjectItem>> to_delete;
// Iterate to find clips that are not in timeline
......@@ -672,13 +676,14 @@ bool ProjectItemModel::requestCleanup()
// it is important to execute deletion in a separate loop, because otherwise
// the iterators of m_allItems get messed up
for (const auto &c : to_delete) {
res = requestBinClipDeletion(c, undo, redo);
res = requestBinClipDeletion(c, undo, redo, list);
if (!res) {
bool undone = undo();
Q_ASSERT(undone);
return false;
}
}
ModelUpdater::applyUpdates(undo, redo, list);
pCore->pushUndo(undo, redo, i18n("Clean Project"));
return true;
}
......
......@@ -26,6 +26,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "abstractmodel/abstracttreemodel.hpp"
#include "definitions.h"
#include "timeline2/model/modelupdater.hpp"
#include "undohelper.hpp"
#include <QDomElement>
#include <QIcon>
......@@ -134,7 +135,7 @@ public:
@param clip : pointer to the clip to delete
@param undo,redo: lambdas that are updated to accumulate operation.
*/
bool requestBinClipDeletion(std::shared_ptr<AbstractProjectItem> clip, Fun &undo, Fun &redo);
bool requestBinClipDeletion(std::shared_ptr<AbstractProjectItem> clip, Fun &undo, Fun &redo, Updates &list);
/* @brief Request creation of a bin folder
@param id Id of the requested bin. If this is empty or invalid (already used, for example), it will be used as a return parameter to give the automatic
......
......@@ -25,6 +25,7 @@
#include <QProcess>
#include "definitions.h"
#include "timeline2/model/modelupdater.hpp"
#include "undohelper.hpp"
#include <memory>
......@@ -74,7 +75,7 @@ public:
By design, the job should store the result of the computation but not share it with the rest of the code. This happens when we call commitResult
This methods return true on success
*/
virtual bool commitResult(Fun &undo, Fun &redo) = 0;
virtual bool commitResult(Fun &undo, Fun &redo, Updates &list) = 0;
// brief run a given job
static bool execute(std::shared_ptr<AbstractClipJob> job);
......
......@@ -196,7 +196,7 @@ bool AudioThumbJob::computeWithFFMPEG()
if (steps != 0) {
channelsData[k] /= steps;
}
m_audioLevels << (int) (channelsData[k] * factor);
m_audioLevels << (int)(channelsData[k] * factor);
}
int p = 80 + (i * 20 / m_lengthInFrames);
if (p != progress) {
......@@ -308,7 +308,7 @@ bool AudioThumbJob::startJob()
return false;
}
bool AudioThumbJob::commitResult(Fun &undo, Fun &redo)
bool AudioThumbJob::commitResult(Fun &undo, Fun &redo, Updates &list)
{
Q_ASSERT(!m_resultConsumed);
if (!m_done) {
......
......@@ -50,7 +50,7 @@ public:
/** @brief This is to be called after the job finished.
By design, the job should store the result of the computation but not share it with the rest of the code. This happens when we call commitResult */
bool commitResult(Fun &undo, Fun &redo) override;
bool commitResult(Fun &undo, Fun &redo, Updates &list) override;
protected:
bool computeWithFFMPEG();
......
......@@ -287,6 +287,7 @@ void JobManager::slotManageFinishedJob(int id)
}
Fun undo = []() { return true; };
Fun redo = []() { return true; };
Updates list;
if (!ok) {
qDebug() << " * * * ** * * *\nWARNING + + +\nJOB NOT CORRECT FINISH: " << id << "\n------------------------";
// TODO: delete child jobs
......@@ -300,19 +301,20 @@ void JobManager::slotManageFinishedJob(int id)
auto clipItem = std::static_pointer_cast<ProjectClip>(item);
if (!clipItem->isReady()) {
// We were trying to load a new clip, delete it
pCore->projectItemModel()->requestBinClipDeletion(item, undo, redo);
pCore->projectItemModel()->requestBinClipDeletion(item, undo, redo, list);
}
}
}
}
updateJobCount();
ModelUpdater::applyUpdates(undo, redo, list);
return;
}
// unlock mutex to allow further processing
// TODO: the lock mechanism should handle this better!
locker.unlock();
for (const auto &j : m_jobs[id]->m_job) {
ok = ok && j->commitResult(undo, redo);
ok = ok && j->commitResult(undo, redo, list);
}
m_jobs[id]->m_processed = true;
if (!ok) {
......@@ -321,6 +323,7 @@ void JobManager::slotManageFinishedJob(int id)
}
m_jobs[id]->m_completionMutex.unlock();
if (ok && !m_jobs[id]->m_undoString.isEmpty()) {
ModelUpdater::applyUpdates(undo, redo, list);
pCore->pushUndo(undo, redo, m_jobs[id]->m_undoString);
}
if (m_jobsByParents.count(id) > 0) {
......
......@@ -412,7 +412,7 @@ void LoadJob::processMultiStream()
qDebug() << "Warning, something went wrong while accessing parent of bin clip";
}
// This helper lambda request addition of a given stream
auto addStream = [ this, parentId = std::move(parent) ](int vindex, int aindex, Fun &undo, Fun &redo)
auto addStream = [ this, parentId = std::move(parent) ](int vindex, int aindex, Fun &undo, Fun &redo, Updates &list)
{
auto clone = Clip::clone(m_producer);
clone->set("video_index", vindex);
......@@ -423,6 +423,7 @@ void LoadJob::processMultiStream()
};
Fun undo = []() { return true; };
Fun redo = []() { return true; };
Updates list;
if (KdenliveSettings::automultistreams()) {
for (int i = 1; i < m_video_list.count(); ++i) {
......@@ -431,7 +432,7 @@ void LoadJob::processMultiStream()
if (i <= m_audio_list.count() - 1) {
aindex = m_audio_list.at(i);
}
addStream(vindex, aindex, undo, redo);
addStream(vindex, aindex, undo, redo, list);
}
return;
}
......@@ -499,14 +500,15 @@ void LoadJob::processMultiStream()
// only check audio index if we have several audio streams
aindex = comboList.at(ax)->itemData(comboList.at(ax)->currentIndex()).toInt();
}
addStream(vindex, aindex, undo, redo);
addStream(vindex, aindex, undo, redo, list);
}
}
}
ModelUpdater::applyUpdates(undo, redo, list);
pCore->pushUndo(undo, redo, i18n("Add additional streams for clip"));
}
bool LoadJob::commitResult(Fun &undo, Fun &redo)
bool LoadJob::commitResult(Fun &undo, Fun &redo, Updates &list)
{
qDebug() << "################### loadjob COMMIT";
Q_ASSERT(!m_resultConsumed);
......@@ -518,7 +520,7 @@ bool LoadJob::commitResult(Fun &undo, Fun &redo)
auto m_binClip = pCore->projectItemModel()->getClipByBinID(m_clipId);
if (!m_successful) {
// TODO: Deleting cannot happen at this stage or we endup in a mutex lock
pCore->projectItemModel()->requestBinClipDeletion(m_binClip, undo, redo);
pCore->projectItemModel()->requestBinClipDeletion(m_binClip, undo, redo, list);
return false;
}
if (m_xml.hasAttribute(QStringLiteral("_checkProfile")) && m_producer->get_int("video_index") > -1) {
......
......@@ -51,7 +51,7 @@ public:
/** @brief This is to be called after the job finished.
By design, the job should store the result of the computation but not share it with the rest of the code. This happens when we call commitResult */
bool commitResult(Fun &undo, Fun &redo) override;
bool commitResult(Fun &undo, Fun &redo, Updates &list) override;
protected:
// helper to load some kind of resources such as color. This will modify resource if needs be (for eg., in the case of color, it will prepend "color:" if
......
......@@ -307,7 +307,7 @@ void ProxyJob::processLogInfo()
}
}
bool ProxyJob::commitResult(Fun &undo, Fun &redo)
bool ProxyJob::commitResult(Fun &undo, Fun &redo, Updates &list)
{
Q_ASSERT(!m_resultConsumed);
if (!m_done) {
......
......@@ -38,7 +38,7 @@ public:
bool startJob() override;
/** @brief This is to be called after the job finished.
By design, the job should store the result of the computation but not share it with the rest of the code. This happens when we call commitResult */
bool commitResult(Fun &undo, Fun &redo) override;
bool commitResult(Fun &undo, Fun &redo, Updates &list) override;
private slots:
void processLogInfo();
......
......@@ -106,7 +106,7 @@ int SceneSplitJob::prepareJob(std::shared_ptr<JobManager> ptr, const std::vector
return ptr->startJob_noprepare<SceneSplitJob>(binIds, parentId, std::move(undoString), subclips, markersType, minInterval);
}
bool SceneSplitJob::commitResult(Fun &undo, Fun &redo)
bool SceneSplitJob::commitResult(Fun &undo, Fun &redo, Updates &list)
{
Q_UNUSED(undo)
Q_UNUSED(redo)
......
......@@ -50,7 +50,7 @@ public:
// Then the job is automatically put in queue. Its id is returned
static int prepareJob(std::shared_ptr<JobManager> ptr, const std::vector<QString> &binIds, int parentId, QString undoString);
bool commitResult(Fun &undo, Fun &redo) override;
bool commitResult(Fun &undo, Fun &redo, Updates &list) override;
const QString getDescription() const override;
protected:
......
......@@ -99,7 +99,7 @@ int SpeedJob::prepareJob(std::shared_ptr<JobManager> ptr, const std::vector<QStr
return ptr->startJob<SpeedJob>(binIds, parentId, std::move(undoString), local_createFn_t(std::move(createFn)));
}
bool SpeedJob::commitResult(Fun &undo, Fun &redo)
bool SpeedJob::commitResult(Fun &undo, Fun &redo, Updates &list)
{
Q_ASSERT(!m_resultConsumed);
if (!m_done) {
......
......@@ -49,7 +49,7 @@ public:
// Then the job is automatically put in queue. Its id is returned
static int prepareJob(std::shared_ptr<JobManager> ptr, const std::vector<QString> &binIds, int parentId, QString undoString);
bool commitResult(Fun &undo, Fun &redo) override;
bool commitResult(Fun &undo, Fun &redo, Updates &list) override;
const QString getDescription() const override;
protected:
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment