Commit ad0126e0 authored by Nicolas Carion's avatar Nicolas Carion

Fix folder creation

parent 13cd5b12
......@@ -170,8 +170,9 @@ void AbstractTreeModel::registerItem(const std::shared_ptr<TreeItem> &item)
m_allItems[id] = item;
}
void AbstractTreeModel::deregisterItem(int id)
void AbstractTreeModel::deregisterItem(int id, TreeItem *item)
{
Q_UNUSED(item);
Q_ASSERT(m_allItems.count(id) > 0);
m_allItems.erase(id);
}
......@@ -182,5 +183,5 @@ std::shared_ptr<TreeItem> AbstractTreeModel::getItemById(int id) const
return rootItem;
}
Q_ASSERT(m_allItems.count(id) > 0);
return m_allItems.at(id);
return m_allItems.at(id).lock();
}
......@@ -91,7 +91,7 @@ protected:
virtual void registerItem(const std::shared_ptr<TreeItem> &item);
/* @brief Deregister an item. This is a call-back meant to be called from TreeItem */
virtual void deregisterItem(int id);
virtual void deregisterItem(int id, TreeItem *item);
/* @brief Returns the next valid id to give to a new element */
static int getNextId();
......@@ -99,7 +99,7 @@ protected:
protected:
std::shared_ptr<TreeItem> rootItem;
std::unordered_map<int, std::shared_ptr<TreeItem>> m_allItems;
std::unordered_map<int, std::weak_ptr<TreeItem>> m_allItems;
static int currentTreeId;
};
......
......@@ -58,7 +58,7 @@ void TreeItem::baseFinishConstruct(const std::shared_ptr<TreeItem> &self)
TreeItem::~TreeItem()
{
if (auto ptr = m_model.lock()) {
ptr->deregisterItem(m_id);
ptr->deregisterItem(m_id, this);
} else {
qDebug() << "ERROR: Something went wrong when deleting TreeItem. Model is not available anymore";
}
......
......@@ -70,7 +70,7 @@ public:
/* @brief Change the parent of the current item. Structures are modified accordingly
*/
void changeParent(std::shared_ptr<TreeItem> newParent);
virtual void changeParent(std::shared_ptr<TreeItem> newParent);
/* @brief Retrieves a child of the current item
@param row is the index of the child to retrieve
......
......@@ -237,7 +237,7 @@ bool AbstractProjectItem::selfSoftDelete(Fun &undo, Fun &redo)
}
Fun operation = [this]() {
if (auto ptr = m_model.lock()) {
ptr->deregisterItem(m_id);
ptr->deregisterItem(m_id, this);
} else {
qDebug() << "ERROR: Something went wrong when deleting TreeItem. Model is not available anymore";
return false;
......@@ -261,3 +261,17 @@ bool AbstractProjectItem::selfSoftDelete(Fun &undo, Fun &redo)
}
return false;
}
QString AbstractProjectItem::lastParentId() const
{
return m_lastParentId;
}
void AbstractProjectItem::changeParent(std::shared_ptr<TreeItem> newParent)
{
m_lastParentId.clear();
if (newParent) {
m_lastParentId = std::static_pointer_cast<AbstractProjectItem>(newParent)->clipId();
}
TreeItem::changeParent(newParent);
}
......@@ -173,6 +173,14 @@ public:
virtual QString getToolTip() const = 0;
virtual bool rename(const QString &name, int column) = 0;
/* @brief Return the bin id of the last parent that this element got, even if this
parent has already been destroyed.
Return the empty string if the element was parentless */
QString lastParentId() const;
/* @brief This is an overload of TreeItem::changeParent that tracks the id of the id of the parent */
void changeParent(std::shared_ptr<TreeItem> newParent) override;
/* Returns a ptr to the enclosing dir, and nullptr if none is found.
@param strict if set to false, the enclosing dir of a dir is itself, otherwise we try to find a "true" parent
*/
......@@ -202,6 +210,8 @@ protected:
QString m_jobMessage;
PROJECTITEMTYPE m_itemType;
QString m_lastParentId;
/** @brief Returns a rounded border pixmap from the @param source pixmap. */
QPixmap roundedPixmap(const QPixmap &source);
......
......@@ -1385,17 +1385,23 @@ QString Bin::slotAddFolder(const QString &folderName)
std::shared_ptr<AbstractProjectItem> currentItem = m_itemModel->getBinItemByIndex(m_proxyModel->mapToSource(ix));
parentFolder = std::static_pointer_cast<ProjectFolder>(currentItem->getEnclosingFolder());
}
QString newId = QString::number(getFreeFolderId());
AddBinFolderCommand *command = new AddBinFolderCommand(this, newId, folderName.isEmpty() ? i18n("Folder") : folderName, parentFolder->clipId());
m_doc->commandStack()->push(command);
qDebug() << "pranteforder id"<<parentFolder->clipId();
QString newId;
Fun undo = []() { return true; };
Fun redo = []() { return true; };
m_itemModel->requestAddFolder(newId, folderName.isEmpty() ? i18n("Folder") : folderName, parentFolder->clipId(), undo, redo);
pCore->pushUndo(undo, redo, i18n("Create bin folder"));
// Edit folder name
if (!folderName.isEmpty()) {
// We already have a name, no need to edit
return newId;
}
ix = getIndexForId(newId, true);
auto folder = m_itemModel->getFolderByBinId(newId);
ix = m_itemModel->getIndexFromItem(folder);
qDebug() << "selecting"<<ix;
if (ix.isValid()) {
qDebug() << "ix valid";
m_proxyModel->selectionModel()->clearSelection();
int row = ix.row();
const QModelIndex id = m_itemModel->index(row, 0, ix.parent());
......
......@@ -42,6 +42,8 @@ ProjectItemModel::ProjectItemModel(Bin *bin, QObject *parent)
, m_lock(QReadWriteLock::Recursive)
, m_binPlaylist(new Mlt::Playlist(pCore->getCurrentProfile()->profile()))
, m_bin(bin)
, m_clipCounter(1)
, m_folderCounter(1)
{
}
......@@ -278,7 +280,7 @@ std::shared_ptr<ProjectClip> ProjectItemModel::getClipByBinID(const QString &bin
return getClipByBinID(binId.section(QLatin1Char('_'), 0, 0));
}
for (const auto &clip : m_allItems) {
auto c = std::static_pointer_cast<AbstractProjectItem>(clip.second);
auto c = std::static_pointer_cast<AbstractProjectItem>(clip.second.lock());
if (c->itemType() == AbstractProjectItem::ClipItem && c->clipId() == binId) {
return std::static_pointer_cast<ProjectClip>(c);
}
......@@ -289,7 +291,7 @@ std::shared_ptr<ProjectClip> ProjectItemModel::getClipByBinID(const QString &bin
std::shared_ptr<ProjectFolder> ProjectItemModel::getFolderByBinId(const QString &binId)
{
for (const auto &clip : m_allItems) {
auto c = std::static_pointer_cast<AbstractProjectItem>(clip.second);
auto c = std::static_pointer_cast<AbstractProjectItem>(clip.second.lock());
if (c->itemType() == AbstractProjectItem::FolderItem && c->clipId() == binId) {
return std::static_pointer_cast<ProjectFolder>(c);
}
......@@ -324,7 +326,16 @@ QStringList ProjectItemModel::getEnclosingFolderInfo(const QModelIndex &index) c
void ProjectItemModel::clean()
{
rootItem = ProjectFolder::construct(std::static_pointer_cast<ProjectItemModel>(shared_from_this()));
std::vector<std::shared_ptr<TreeItem> > toDelete;
for (int i = 0; i < rootItem->childCount(); ++i) {
toDelete.push_back(rootItem->child(i));
}
for (const auto& child : toDelete) {
rootItem->removeChild(child);
}
Q_ASSERT(rootItem->childCount() == 0);
m_clipCounter = 1;
m_folderCounter = 1;
}
std::shared_ptr<ProjectFolder> ProjectItemModel::getRootFolder() const
......@@ -388,7 +399,7 @@ bool ProjectItemModel::requestBinClipDeletion(std::shared_ptr<AbstractProjectIte
is captured by the reverse operation.
Actual deletions occurs when the undo object is destroyed.
*/
auto currentClip = std::static_pointer_cast<AbstractProjectItem>(m_allItems[id]);
auto currentClip = std::static_pointer_cast<AbstractProjectItem>(m_allItems[id].lock());
Q_ASSERT(currentClip);
if (!currentClip) return false;
auto parent = currentClip->parent();
......@@ -424,16 +435,15 @@ bool ProjectItemModel::requestBinClipDeletion(std::shared_ptr<AbstractProjectIte
void ProjectItemModel::registerItem(const std::shared_ptr<TreeItem> &item)
{
auto clip = std::static_pointer_cast<AbstractProjectItem>(item);
qDebug() << "registering" <<clip->clipId();
manageBinClipInsertion(clip);
AbstractTreeModel::registerItem(item);
}
void ProjectItemModel::deregisterItem(int id)
void ProjectItemModel::deregisterItem(int id, TreeItem *item)
{
auto clip = std::static_pointer_cast<AbstractProjectItem>(m_allItems[id]);
if (auto parent = clip->parent()) {
manageBinClipDeletion(clip, parent);
}
AbstractTreeModel::deregisterItem(id);
auto clip = static_cast<AbstractProjectItem*>(item);
manageBinClipDeletion(clip);
AbstractTreeModel::deregisterItem(id, item);
}
void ProjectItemModel::notifyRowAppended(const std::shared_ptr<TreeItem> &row)
......@@ -463,18 +473,19 @@ void ProjectItemModel::notifyRowAboutToDelete(std::shared_ptr<TreeItem> item, in
{
auto rowItem = item->child(row);
auto binElem = std::static_pointer_cast<AbstractProjectItem>(rowItem);
auto oldParent = std::static_pointer_cast<AbstractProjectItem>(item);
manageBinClipDeletion(binElem, oldParent);
manageBinClipDeletion(binElem.get());
AbstractTreeModel::notifyRowAboutToDelete(item, row);
}
void ProjectItemModel::manageBinClipDeletion(std::shared_ptr<AbstractProjectItem> binElem, std::shared_ptr<AbstractProjectItem> oldParent)
void ProjectItemModel::manageBinClipDeletion(AbstractProjectItem *binElem)
{
switch(binElem->itemType()) {
case AbstractProjectItem::FolderItem: {
//When a folder is removed, we clear the path info
QString propertyName = "kdenlive:folder." + oldParent->clipId() + QLatin1Char('.') + binElem->clipId();
m_binPlaylist->set(propertyName.toUtf8().constData(), (char *)nullptr);
if (!binElem->lastParentId().isEmpty()) {
QString propertyName = "kdenlive:folder." + binElem->lastParentId() + QLatin1Char('.') + binElem->clipId();
m_binPlaylist->set(propertyName.toUtf8().constData(), (char *)nullptr);
}
break;
}
default:
......@@ -482,40 +493,65 @@ void ProjectItemModel::manageBinClipDeletion(std::shared_ptr<AbstractProjectItem
}
}
// bool ProjectItemModel::requestAddFolder(const QString &name, const QString &parentId, Fun &undo, Fun &redo)
// {
// QWriteLocker locker(&m_lock);
// std::shared_ptr<ProjectFolder> parentFolder = getFolderByBinId(parentId);
// if (!parentFolder) {
// qCDebug(KDENLIVE_LOG) << " / / ERROR IN PARENT FOLDER";
// return false;
// }
// std::shared_ptr<ProjectFolder> new_folder = ProjectFolder::construct(id, name, m_itemModel, parentFolder);
// int folderId = new_folder->getId();
// Fun operation = [this, new_folder, parentId]() {
// /* Insertion is simply setting the parent of the folder.*/
// std::shared_ptr<ProjectFolder> parentFolder = getFolderByBinId(parentId);
// if (!parentFolder) {
// return false;
// }
// new_folder->changeParent(parentFolder);
// return true;
// };
// Fun reverse = [this, folderId]() {
// /* To undo insertion, we deregister the clip */
// std::shared_ptr<AbstractProjectItem> folder = getClipByBinID(folderId);
// if (!folder) {
// return false;
// }
// auto parent = currentClip->parent();
// parent->removeChild(currentClip);
// return true;
// };
// bool res = operation();
// if (res) {
// LOCK_IN_LAMBDA(operation);
// LOCK_IN_LAMBDA(reverse);
// UPDATE_UNDO_REDO(operation, reverse, undo, redo);
// }
// return res;
// }
int ProjectItemModel::getFreeFolderId()
{
return m_folderCounter++;
}
int ProjectItemModel::getFreeClipId()
{
return m_clipCounter++;
}
bool ProjectItemModel::requestAddFolder(QString &id, const QString &name, const QString &parentId, Fun &undo, Fun &redo)
{
QWriteLocker locker(&m_lock);
qDebug() << "request Add. parent="<<parentId;
std::shared_ptr<ProjectFolder> parentFolder = getFolderByBinId(parentId);
if (!parentFolder) {
qCDebug(KDENLIVE_LOG) << " / / ERROR IN PARENT FOLDER";
return false;
}
if (id.isEmpty()) {
id = QString::number(getFreeFolderId());
}
std::shared_ptr<ProjectFolder> new_folder = ProjectFolder::construct(id, name, std::static_pointer_cast<ProjectItemModel>(shared_from_this()), parentFolder);
qDebug() << "newfolder created:"<<new_folder->clipId()<<(void*)new_folder.get();
parentFolder->appendChild(new_folder);
int folderId = new_folder->getId();
qDebug() << "creating op. parent="<<parentId<<(void*)parentFolder.get();
Fun operation = [this, new_folder, parentId]() {
/* Insertion is simply setting the parent of the folder.*/
qDebug() << "executing op. parent="<<parentId;
std::shared_ptr<ProjectFolder> parent = getFolderByBinId(parentId);
if (!parent) {
return false;
}
qDebug() << "executing op2. parent="<<parent->clipId()<<(void*)parent.get();
new_folder->changeParent(parent);
return true;
};
Fun reverse = [this, folderId]() {
/* To undo insertion, we deregister the clip */
auto folder = std::static_pointer_cast<AbstractProjectItem>(m_allItems[folderId].lock());
if (!folder) {
return false;
}
auto parent = folder->parent();
parent->removeChild(folder);
return true;
};
qDebug()<<"Folder list";
for (const auto &clip : m_allItems) {
auto c = std::static_pointer_cast<AbstractProjectItem>(clip.second.lock());
if (c->itemType() == AbstractProjectItem::FolderItem) {
qDebug() <<"folder"<<c->clipId()<<(void*)c.get();
}
}
bool res = operation();
if (res) {
LOCK_IN_LAMBDA(operation);
LOCK_IN_LAMBDA(reverse);
UPDATE_UNDO_REDO(operation, reverse, undo, redo);
}
return res;
}
......@@ -109,6 +109,13 @@ public:
*/
bool requestBinClipDeletion(std::shared_ptr<AbstractProjectItem> clip, Fun &undo, Fun &redo);
/* @brief Request creation of a bin folder
@param id Id of the requested bin. If this is empty, it will be used as a return parameter to give the automatic bin id used.
@param name Name of the folder
@param parentId Bin id of the parent folder
@param undo,redo: lambdas that are updated to accumulate operation.
*/
bool requestAddFolder(QString &id, const QString &name, const QString &parentId, Fun &undo, Fun &redo);
/* @brief Manage insertion in the tree hierarchy.
Note that the element has normally already been registered through registerItem,
this function is called when its parent is defined.
......@@ -124,19 +131,25 @@ public:
/* @brief Register the existence of a new element
*/
void registerItem(const std::shared_ptr<TreeItem> &item) override;
void deregisterItem(int id) override;
void deregisterItem(int id, TreeItem *item) override;
protected:
/* @brief This function updates the underlying binPlaylist object to reflect deletion of a bin item
@param binElem is the bin item deleted
@param oldParent is its parent
@param binElem is the bin item deleted. Note that exceptionnally, this function takes a raw pointer instead of a smart one.
This is because the function will be called in the middle of the element's destructor, so no smart pointer is available at that time.
*/
void manageBinClipDeletion(std::shared_ptr<AbstractProjectItem> binElem, std::shared_ptr<AbstractProjectItem> oldParent);
void manageBinClipDeletion(AbstractProjectItem *binElem);
/* @brief This function updates the underlying binPlaylist object to reflect insertion of a bin item
@param binElem is the bin item inserted
*/
void manageBinClipInsertion(const std::shared_ptr<AbstractProjectItem> &binElem);
/* @brief Retrieves the next id available for attribution to a folder */
int getFreeFolderId();
/* @brief Retrieves the next id available for attribution to a clip */
int getFreeClipId();
public slots:
/** @brief An item in the list was modified, notify */
void onItemUpdated(std::shared_ptr<AbstractProjectItem> item);
......@@ -152,6 +165,8 @@ private:
Bin *m_bin;
int m_clipCounter;
int m_folderCounter;
signals:
void updateThumbProgress(long ms);
void abortAudioThumb(const QString &id, long duration);
......
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