Commit 30b6f281 authored by Nicolas Carion's avatar Nicolas Carion
Browse files

Fix deletion of bin items

parent 90ae5621
......@@ -23,6 +23,7 @@
#include "treeitem.hpp"
#include <utility>
#include <QDebug>
int AbstractTreeModel::currentTreeId = 0;
AbstractTreeModel::AbstractTreeModel(QObject *parent)
......@@ -164,13 +165,37 @@ int AbstractTreeModel::getNextId()
void AbstractTreeModel::registerItem(const std::shared_ptr<TreeItem> &item)
{
int id = item->getId();
qDebug() << "bottom registering "<<item->getId();
Q_ASSERT(m_allItems.count(id) == 0);
m_allItems[id] = item;
/*if (!m_allItems[id]->isInModel()) {
qDebug() << "inserting in model"<<id;
m_allItems[id]->setIsInModel(true);
if (auto ptr = m_allItems[id]->parentItem().lock()) {
notifyRowAboutToAppend(ptr);
notifyRowAppended();
qDebug() << "notifying"<<id;
} else {
qDebug() << "no parent"<<id;
}
} else {
qDebug() << "already in model"<<id;
}*/
}
void AbstractTreeModel::deregisterItem(int id)
{
qDebug() << "bottom deregistering "<<id;
Q_ASSERT(m_allItems.count(id) > 0);
// if item is in model, we must send signal that it is deleted
/* if (m_allItems[id]->isInModel()) {
m_allItems[id]->setIsInModel(false);
if (auto ptr = m_allItems[id]->parentItem().lock()) {
notifyRowAboutToDelete(ptr, m_allItems[id]->row());
notifyRowDeleted();
}
} */
m_allItems.erase(id);
}
......
......@@ -83,13 +83,14 @@ public:
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
friend class TreeItem;
friend class AbstractProjectItem;
protected:
/* @brief Register a new item. This is a call-back meant to be called from TreeItem */
void registerItem(const std::shared_ptr<TreeItem> &item);
virtual void registerItem(const std::shared_ptr<TreeItem> &item);
/* @brief Deregister an item. This is a call-back meant to be called from TreeItem */
void deregisterItem(int id);
virtual void deregisterItem(int id);
/* @brief Returns the next valid id to give to a new element */
static int getNextId();
......
......@@ -23,6 +23,7 @@
#include "abstracttreemodel.hpp"
#include <QDebug>
#include <utility>
#include <numeric>
TreeItem::TreeItem(const QList<QVariant> &data, const std::shared_ptr<AbstractTreeModel> &model, const std::shared_ptr<TreeItem> &parent, int id)
: m_itemData(data)
......@@ -30,6 +31,7 @@ TreeItem::TreeItem(const QList<QVariant> &data, const std::shared_ptr<AbstractTr
, m_model(model)
, m_depth(0)
, m_id(id == -1 ? AbstractTreeModel::getNextId() : id)
, m_isInModel(false)
{
}
......@@ -44,6 +46,7 @@ std::shared_ptr<TreeItem> TreeItem::construct(const QList<QVariant> &data, std::
// static
void TreeItem::baseFinishConstruct(const std::shared_ptr<TreeItem> &self)
{
qDebug() << "FINISHED constructing "<<self->getId();
if (auto ptr = self->m_model.lock()) {
ptr->registerItem(self);
} else {
......@@ -66,12 +69,14 @@ std::shared_ptr<TreeItem> TreeItem::appendChild(const QList<QVariant> &data)
if (auto ptr = m_model.lock()) {
ptr->notifyRowAboutToAppend(shared_from_this());
auto child = construct(data, ptr, shared_from_this());
qDebug() << "appending child"<<child->getId() <<"to "<<m_id;
child->m_depth = m_depth + 1;
int id = child->getId();
m_childItems.push_back(child);
auto it = std::prev(m_childItems.end());
m_iteratorTable[id] = it;
ptr->notifyRowAppended();
m_isInModel = true;
return child;
}
qDebug() << "ERROR: Something went wrong when appending child in TreeItem. Model is not available anymore";
......@@ -85,10 +90,12 @@ void TreeItem::appendChild(std::shared_ptr<TreeItem> child)
ptr->notifyRowAboutToAppend(shared_from_this());
child->m_depth = m_depth + 1;
child->m_parentItem = shared_from_this();
qDebug() << "appending child2"<<child->getId() <<"to "<<m_id;
int id = child->getId();
auto it = m_childItems.insert(m_childItems.end(), std::move(child));
m_iteratorTable[id] = it;
ptr->notifyRowAppended();
m_isInModel = true;
} else {
qDebug() << "ERROR: Something went wrong when appending child in TreeItem. Model is not available anymore";
Q_ASSERT(false);
......@@ -98,6 +105,7 @@ void TreeItem::appendChild(std::shared_ptr<TreeItem> child)
void TreeItem::removeChild(const std::shared_ptr<TreeItem> &child)
{
if (auto ptr = m_model.lock()) {
qDebug() << "removing child"<<child->getId() <<"from "<<m_id;
ptr->notifyRowAboutToDelete(shared_from_this(), child->row());
// get iterator corresponding to child
auto it = m_iteratorTable[child->getId()];
......@@ -108,6 +116,7 @@ void TreeItem::removeChild(const std::shared_ptr<TreeItem> &child)
child->m_depth = 0;
child->m_parentItem.reset();
ptr->notifyRowDeleted();
m_isInModel = false;
} else {
qDebug() << "ERROR: Something went wrong when removing child in TreeItem. Model is not available anymore";
Q_ASSERT(false);
......@@ -116,6 +125,7 @@ void TreeItem::removeChild(const std::shared_ptr<TreeItem> &child)
void TreeItem::changeParent(std::shared_ptr<TreeItem> newParent)
{
qDebug() << "changing parent of "<<m_id;
if (auto ptr = m_parentItem.lock()) {
ptr->removeChild(shared_from_this());
}
......@@ -172,3 +182,12 @@ int TreeItem::getId() const
{
return m_id;
}
void TreeItem::setIsInModel(bool isInModel)
{
m_isInModel = isInModel;
}
bool TreeItem::isInModel() const
{
return m_isInModel;
}
......@@ -103,6 +103,18 @@ public:
/* @brief Return the id of the current item*/
int getId() const;
/* @brief This is similar to the std::accumulate function, except that it
operates on the whole subtree
@param init is the initial value of the operation
@param is the binary op to apply (signature should be (T, shared_ptr<TreeItem>)->T)
*/
template<class T, class BinaryOperation>
T accumulate(T init, BinaryOperation op);
/* @brief Returns true if the model has been notified about the existence of this object
*/
bool isInModel() const;
void setIsInModel(bool isInModel);
protected:
/* @brief Finish construction of object given its pointer
This is a separated function so that it can be called from derived classes */
......@@ -118,6 +130,14 @@ protected:
std::weak_ptr<AbstractTreeModel> m_model;
int m_depth;
int m_id;
bool m_isInModel;
};
template<class T, class BinaryOperation>
T TreeItem::accumulate(T init, BinaryOperation op)
{
T res = op(init, shared_from_this());
return std::accumulate(m_childItems.begin(), m_childItems.end(), res, op);
}
#endif
......@@ -35,7 +35,7 @@ AbstractProjectItem::AbstractProjectItem(PROJECTITEMTYPE type, const QString &id
, m_description()
, m_thumbnail(QIcon())
, m_date()
, m_id(id)
, m_binId(id)
, m_usage(0)
, m_clipStatus(StatusReady)
, m_jobType(AbstractClipJob::NOJOBTYPE)
......@@ -52,7 +52,7 @@ AbstractProjectItem::AbstractProjectItem(PROJECTITEMTYPE type, const QDomElement
, m_description()
, m_thumbnail(QIcon())
, m_date()
, m_id(description.attribute(QStringLiteral("id")))
, m_binId(description.attribute(QStringLiteral("id")))
, m_usage(0)
, m_clipStatus(StatusReady)
, m_jobType(AbstractClipJob::NOJOBTYPE)
......@@ -62,7 +62,6 @@ AbstractProjectItem::AbstractProjectItem(PROJECTITEMTYPE type, const QDomElement
{
}
AbstractProjectItem::~AbstractProjectItem() = default;
bool AbstractProjectItem::operator==(const std::shared_ptr<AbstractProjectItem> &projectItem) const
{
......@@ -105,7 +104,7 @@ void AbstractProjectItem::removeRef()
const QString &AbstractProjectItem::clipId() const
{
return m_id;
return m_binId;
}
QPixmap AbstractProjectItem::roundedPixmap(const QPixmap &source)
......@@ -231,3 +230,35 @@ std::shared_ptr<AbstractProjectItem> AbstractProjectItem::getEnclosingFolder(boo
}
return std::shared_ptr<AbstractProjectItem>();
}
bool AbstractProjectItem::selfSoftDelete(Fun &undo, Fun &redo)
{
for(const auto& child : m_childItems) {
std::static_pointer_cast<AbstractProjectItem>(child)->selfSoftDelete(undo, redo);
}
Fun operation = [this]() {
if (auto ptr = m_model.lock()) {
ptr->deregisterItem(m_id);
} else {
qDebug() << "ERROR: Something went wrong when deleting TreeItem. Model is not available anymore";
return false;
}
return true;
};
std::shared_ptr<TreeItem> self = shared_from_this();
Fun reverse = [this, self]() {
//self is capture explicitly to prevent deletion of the object
if (auto ptr = m_model.lock()) {
ptr->registerItem(self);
} else {
qDebug() << "ERROR: Something went wrong when deleting TreeItem. Model is not available anymore";
return false;
}
return true;
};
if(operation()) {
UPDATE_UNDO_REDO(operation, reverse, undo, redo);
return true;
}
return false;
}
......@@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "abstractmodel/treeitem.hpp"
#include "project/jobs/abstractclipjob.h"
#include "undohelper.hpp"
#include <QDateTime>
#include <QObject>
......@@ -66,7 +67,6 @@ public:
*/
AbstractProjectItem(PROJECTITEMTYPE type, const QDomElement &description, const std::shared_ptr<ProjectItemModel> &model,
const std::shared_ptr<AbstractProjectItem> &parent);
virtual ~AbstractProjectItem();
bool operator==(const std::shared_ptr<AbstractProjectItem> &projectItem) const;
......@@ -84,6 +84,15 @@ public:
/** @brief Recursively disable/enable bin effects. */
virtual void setBinEffectsEnabled(bool enabled) = 0;
/** @brief This function executes what should be done when the item is deleted
but without deleting effectively.
For example, the item will deregister itself from the model and delete the
clips from the timeline.
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);
/** @brief Returns the clip's id. */
const QString &clipId() const;
virtual QPoint zone() const;
......@@ -169,6 +178,11 @@ public:
*/
std::shared_ptr<AbstractProjectItem> getEnclosingFolder(bool strict = false);
/** @brief Returns true if a clip corresponding to this bin is inserted in a timeline.
Note that this function does not account for children, use TreeItem::accumulate if you want to get that information as well.
*/
virtual bool isIncludedInTimeline(){ return false; }
signals:
void childAdded(AbstractProjectItem *child);
void aboutToRemoveChild(AbstractProjectItem *child);
......@@ -179,7 +193,7 @@ protected:
QIcon m_thumbnail;
QString m_duration;
QDateTime m_date;
QString m_id;
QString m_binId;
uint m_usage;
CLIPSTATUS m_clipStatus;
AbstractClipJob::JOBTYPE m_jobType;
......
......@@ -48,6 +48,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "projectsubclip.h"
#include "titler/titlewidget.h"
#include "ui_qtextclip_ui.h"
#include "undohelper.hpp"
#include "utils/KoIconUtils.h"
#include <KColorScheme>
......@@ -1008,6 +1009,40 @@ std::shared_ptr<ProjectClip> Bin::getFirstSelectedClip()
void Bin::slotDeleteClip()
{
const QModelIndexList indexes = m_proxyModel->selectionModel()->selectedIndexes();
std::vector<std::shared_ptr<AbstractProjectItem>> items;
bool included = false;
bool usedFolder = false;
for (const QModelIndex &ix : indexes) {
if (!ix.isValid() || ix.column() != 0) {
continue;
}
std::shared_ptr<AbstractProjectItem> item = m_itemModel->getBinItemByIndex(m_proxyModel->mapToSource(ix));
if (!item) {
qDebug()<<"Suspicious: item not found when trying to delete";
continue;
}
auto checkInclusion = [](bool included, std::shared_ptr<TreeItem> item) {
return included || std::static_pointer_cast<AbstractProjectItem>(item)->isIncludedInTimeline();
};
included = included || item->accumulate(false, checkInclusion);
// Check if we are deleting non-empty folders:
usedFolder = usedFolder || item->childCount() > 0;
items.push_back(item);
}
if (included && (KMessageBox::warningContinueCancel(this, i18n("This will delete all selected clips from timeline")) != KMessageBox::Continue)) {
return;
}
if (usedFolder && (KMessageBox::warningContinueCancel(this, i18n("This will delete all folder content")) != KMessageBox::Continue)) {
return;
}
Fun undo = []() { return true; };
Fun redo = []() { return true; };
for (const auto& item : items) {
m_itemModel->requestBinClipDeletion(item->clipId(), undo, redo);
}
pCore->pushUndo(undo, redo, i18n("Delete bin Clips"));
/*
QStringList clipIds;
QStringList subClipIds;
QStringList foldersIds;
......@@ -1107,6 +1142,7 @@ void Bin::slotDeleteClip()
return;
}
m_doc->clipManager()->deleteProjectItems(clipIds, foldersIds, subClipIds);
*/
}
void Bin::slotReloadClip()
......
......@@ -116,7 +116,7 @@ ProjectClip::ProjectClip(const QDomElement &description, const QIcon &thumb, std
}
connect(this, &ProjectClip::updateJobStatus, this, &ProjectClip::setJobStatus);
connect(this, &ProjectClip::updateThumbProgress, model.get(), &ProjectItemModel::updateThumbProgress);
m_markerModel = std::make_shared<MarkerListModel>(m_id, pCore->projectManager()->current()->commandStack());
m_markerModel = std::make_shared<MarkerListModel>(m_binId, pCore->projectManager()->current()->commandStack());
}
std::shared_ptr<ProjectClip> ProjectClip::construct(const QDomElement &description, const QIcon &thumb, std::shared_ptr<ProjectItemModel> model,
......@@ -132,7 +132,7 @@ ProjectClip::~ProjectClip()
{
// controller is deleted in bincontroller
abortAudioThumbs();
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->abortAudioThumb(m_id, duration().ms());
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->abortAudioThumb(m_binId, duration().ms());
QMutexLocker audioLock(&m_audioMutex);
m_thumbMutex.lock();
m_requestedThumbs.clear();
......@@ -170,7 +170,7 @@ void ProjectClip::updateAudioThumbnail(const QVariantList &audioLevels)
{
audioFrameCache = audioLevels;
m_audioThumbCreated = true;
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->refreshAudioThumbs(m_id);
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->refreshAudioThumbs(m_binId);
emit gotAudioData();
}
......@@ -203,7 +203,7 @@ bool ProjectClip::hasParent(const QString &id) const
std::shared_ptr<ProjectClip> ProjectClip::clip(const QString &id)
{
if (id == m_id) {
if (id == m_binId) {
return std::static_pointer_cast<ProjectClip>(shared_from_this());
}
return std::shared_ptr<ProjectClip>();
......@@ -283,7 +283,7 @@ void ProjectClip::reloadProducer(bool refreshOnly)
// set a special flag to request thumbnail only
xml.setAttribute(QStringLiteral("refreshOnly"), QStringLiteral("1"));
}
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->reloadProducer(m_id, xml);
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->reloadProducer(m_binId, xml);
}
QDomElement ProjectClip::toXml(QDomDocument &document, bool includeMeta)
......@@ -341,7 +341,7 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
m_duration = getStringDuration();
m_clipStatus = StatusReady;
if (!hasProxy()) {
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->refreshPanel(m_id);
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->refreshPanel(m_binId);
}
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->onItemUpdated(std::static_pointer_cast<ProjectClip>(shared_from_this()));
// Make sure we have a hash for this clip
......@@ -353,7 +353,7 @@ bool ProjectClip::setProducer(std::shared_ptr<Mlt::Producer> producer, bool repl
void ProjectClip::createAudioThumbs()
{
if (KdenliveSettings::audiothumbnails() && (m_clipType == AV || m_clipType == Audio || m_clipType == Playlist)) {
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->requestAudioThumbs(m_id, duration().ms());
if (auto ptr = m_model.lock()) emit std::static_pointer_cast<ProjectItemModel>(ptr)->requestAudioThumbs(m_binId, duration().ms());
emit updateJobStatus(AbstractClipJob::THUMBJOB, JobWaiting, 0);
}
}
......@@ -513,8 +513,8 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
if (value.isEmpty() || value == QLatin1String("-")) {
// reset proxy
if (auto ptr = m_model.lock()) {
if (std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->hasPendingJob(m_id, AbstractClipJob::PROXYJOB)) {
std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->discardJobs(m_id, AbstractClipJob::PROXYJOB);
if (std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->hasPendingJob(m_binId, AbstractClipJob::PROXYJOB)) {
std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->discardJobs(m_binId, AbstractClipJob::PROXYJOB);
} else {
reloadProducer();
}
......@@ -522,7 +522,7 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
} else {
// A proxy was requested, make sure to keep original url
setProducerProperty(QStringLiteral("kdenlive:originalurl"), url());
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->startJob(m_id, AbstractClipJob::PROXYJOB);
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->startJob(m_binId, AbstractClipJob::PROXYJOB);
}
} else if (properties.contains(QStringLiteral("resource")) || properties.contains(QStringLiteral("templatetext")) ||
properties.contains(QStringLiteral("autorotate"))) {
......@@ -560,10 +560,10 @@ void ProjectClip::setProperties(const QMap<QString, QString> &properties, bool r
if (reload) {
// producer has changed, refresh monitor and thumbnail
reloadProducer(refreshOnly);
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->refreshClip(m_id);
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->refreshClip(m_binId);
}
if (!passProperties.isEmpty()) {
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->updateTimelineProducers(m_id, passProperties);
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->updateTimelineProducers(m_binId, passProperties);
}
}
......@@ -650,7 +650,7 @@ bool ProjectClip::rename(const QString &name, int column)
break;
}
if (edited) {
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->slotEditClipCommand(m_id, oldProperites, newProperites);
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->slotEditClipCommand(m_binId, oldProperites, newProperites);
}
return edited;
}
......@@ -693,7 +693,7 @@ void ProjectClip::addMarkers(QList<CommentedTime> &markers)
}
}
// refresh markers in clip monitor
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->refreshClipMarkers(m_id);
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->refreshClipMarkers(m_binId);
// refresh markers in timeline clips
emit refreshClipDisplay();
}
......@@ -1275,3 +1275,22 @@ void ProjectClip::deregisterTimelineClip(int clipId)
Q_ASSERT(m_registeredClips.count(clipId) > 0);
m_registeredClips.erase(clipId);
}
bool ProjectClip::selfSoftDelete(Fun &undo, Fun &redo)
{
for(const auto& clip : m_registeredClips) {
if (auto timeline = clip.second.lock()) {
timeline->requestClipDeletion(clip.first, undo, redo);
} else {
qDebug() << "Error while deleting clip: timeline unavailable";
Q_ASSERT(false);
return false;
}
}
return AbstractProjectItem::selfSoftDelete(undo, redo);
}
bool ProjectClip::isIncludedInTimeline()
{
return m_registeredClips.size() > 0;
}
......@@ -95,6 +95,8 @@ public:
/** @brief Returns the clip type as defined in definitions.h */
ClipType clipType() const;
bool selfSoftDelete(Fun &undo, Fun &redo) override;
/** @brief Check if clip has a parent folder with id id */
bool hasParent(const QString &id) const;
ClipPropertiesController *buildProperties(QWidget *parent);
......@@ -200,6 +202,11 @@ public:
/** @brief Returns a marker data at given pos */
CommentedTime getMarker(const GenTime &pos, bool *ok) const;
/** @brief Returns true if a clip corresponding to this bin is inserted in a timeline.
Note that this function does not account for children, use TreeItem::accumulate if you want to get that information as well.
*/
bool isIncludedInTimeline() override;
protected:
friend class ClipModel;
/** @brief This is a call-back called by a ClipModel when it is created
......
......@@ -96,7 +96,7 @@ QString ProjectFolder::getToolTip() const
std::shared_ptr<ProjectFolder> ProjectFolder::folder(const QString &id)
{
if (m_id == id) {
if (m_binId == id) {
return std::static_pointer_cast<ProjectFolder>(shared_from_this());
}
for (int i = 0; i < childCount(); ++i) {
......@@ -147,6 +147,6 @@ bool ProjectFolder::rename(const QString &name, int column)
return false;
}
// Rename folder
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->renameFolderCommand(m_id, name, m_name);
if (auto ptr = m_model.lock()) std::static_pointer_cast<ProjectItemModel>(ptr)->bin()->renameFolderCommand(m_binId, name, m_name);
return true;
}
......@@ -25,6 +25,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "core.h"
#include "doc/kdenlivedoc.h"
#include "kdenlivesettings.h"
#include "macros.hpp"
#include "projectclip.h"
#include "projectfolder.h"
#include "projectsubclip.h"
......@@ -36,6 +37,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
ProjectItemModel::ProjectItemModel(Bin *bin, QObject *parent)
: AbstractTreeModel(parent)
, m_lock(QReadWriteLock::Recursive)
, m_bin(bin)
{
}
......@@ -70,6 +72,7 @@ int ProjectItemModel::mapToColumn(int column) const
QVariant ProjectItemModel::data(const QModelIndex &index, int role) const
{
READ_LOCK();
if (!index.isValid()) {
return QVariant();
}
......@@ -100,6 +103,7 @@ QVariant ProjectItemModel::data(const QModelIndex &index, int role) const
bool ProjectItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
QWriteLocker locker(&m_lock);
std::shared_ptr<AbstractProjectItem> item = getBinItemByIndex(index);
if (item->rename(value.toString(), index.column())) {
emit dataChanged(index, index, QVector<int>() << role);
......@@ -270,15 +274,24 @@ std::shared_ptr<ProjectClip> ProjectItemModel::getClipByBinID(const QString &bin
if (binId.contains(QLatin1Char('_'))) {
return getClipByBinID(binId.section(QLatin1Char('_'), 0, 0));
}
if (!binId.isEmpty()) {
return std::static_pointer_cast<AbstractProjectItem>(rootItem)->clip(binId);
for (const auto &clip: m_allItems) {
auto c = std::static_pointer_cast<AbstractProjectItem>(clip.second);
if (c->itemType() == AbstractProjectItem::ClipItem && c->clipId() == binId) {
return std::static_pointer_cast<ProjectClip>(c);
}
}
return nullptr;
}
std::shared_ptr<ProjectFolder> ProjectItemModel::getFolderByBinId(const QString &binId)
{
return std::static_pointer_cast<AbstractProjectItem>(rootItem)->folder(binId);
for (const auto &clip: m_allItems) {
auto c = std::static_pointer_cast<AbstractProjectItem>(clip.second);
if (c->itemType() == AbstractProjectItem::FolderItem && c->clipId() == binId) {
return std::static_pointer_cast<ProjectFolder>(c);
}
}
return nullptr;
}
void ProjectItemModel::setBinEffectsEnabled(bool enabled)
......@@ -357,3 +370,72 @@ std::shared_ptr<AbstractProjectItem> ProjectItemModel::getBinItemByIndex(const Q
{
return std::static_pointer_cast<AbstractProjectItem>(getItemById((int)index.internalId()));
}
bool ProjectItemModel::requestBinClipDeletion(const QString &binId, Fun &undo, Fun &redo)
{
QWriteLocker locker(&m_lock);
std::shared_ptr<AbstractProjectItem> clip = getClipByBinID(binId);
if (!clip) {
clip = getFolderByBinId(binId);
}
Q_ASSERT(clip);
if (!clip) return false;
int parentId = -1;
if (auto ptr = clip->parent())
parentId = ptr->getId();
Fun operation = [this, binId]() {
/* Deletion simply deregister clip and remove it from parent.