Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

Commit 128d2982 authored by Nicolas Carion's avatar Nicolas Carion

Start reorganizing Bin. May break things.

Most salient changes:
- Effect logic is being mostly deprecated. It now uses the effectstackmodel
- Direct access to profiles are being removed. They should be accessed through pCore
- Producers are wrapped in shared_ptr
- The coupling with the Monitor is being reduced. Ideally, there should only be a
signal telling which Producer to display.
- The bin hierarchy is melted into the abstractTreeModel framework. Fusion is done but
there are still duplicate logic
- ProjectClip now inherits ClipController
parent 3297ef4a
......@@ -26,7 +26,7 @@
AbstractTreeModel::AbstractTreeModel(QObject *parent)
: QAbstractItemModel(parent)
{
rootItem = new TreeItem(QList<QVariant>());
rootItem = new TreeItem(QList<QVariant>(), this);
}
AbstractTreeModel::~AbstractTreeModel()
......@@ -126,3 +126,32 @@ int AbstractTreeModel::rowCount(const QModelIndex &parent) const
return parentItem->childCount();
}
QModelIndex AbstractTreeModel::getIndexFromItem(TreeItem *item) const
{
if (item == rootItem) {
return QModelIndex();
}
return index(item->row(), 0, getIndexFromItem(item->parentItem()));
}
void AbstractTreeModel::notifyRowAboutToAppend(TreeItem *item)
{
auto index = getIndexFromItem(item);
beginInsertRows(index, item->childCount(), item->childCount());
}
void AbstractTreeModel::notifyRowAppended()
{
endInsertRows();
}
void AbstractTreeModel::notifyRowAboutToDelete(TreeItem *item, int row)
{
auto index = getIndexFromItem(item);
beginRemoveRows(index, row, row);
}
void AbstractTreeModel::notifyRowDeleted()
{
endRemoveRows();
}
......@@ -35,6 +35,29 @@ public:
explicit AbstractTreeModel(QObject *parent = nullptr);
virtual ~AbstractTreeModel();
/* @brief Given an item from the hierarchy, construct the corresponding ModelIndex */
QModelIndex getIndexFromItem(TreeItem *item) const;
/* @brief Send the appropriate notification related to a row that we are appending
@param item is the parent item to which row is appended
*/
void notifyRowAboutToAppend(TreeItem *item);
/* @brief Send the appropriate notification related to a row that we have appended
*/
void notifyRowAppended();
/* @brief Send the appropriate notification related to a row that we are deleting
@param item is the parent of the row being deleted
@param row is the index of the row being deleted
*/
void notifyRowAboutToDelete(TreeItem *item, int row);
/* @brief Send the appropriate notification related to a row that we have appended
@param item is the item to which row are appended
*/
void notifyRowDeleted();
QVariant data(const QModelIndex &index, int role) const override;
//This is reimplemented to prevent selection of the categories
Qt::ItemFlags flags(const QModelIndex &index) const override;
......
......@@ -20,12 +20,14 @@
***************************************************************************/
#include "treeitem.hpp"
#include "abstracttreemodel.hpp"
TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent)
TreeItem::TreeItem(const QList<QVariant> &data, AbstractTreeModel* model, TreeItem *parent)
{
m_parentItem = parent;
m_itemData = data;
m_depth = 0;
m_model = model;
}
TreeItem::~TreeItem()
......@@ -35,19 +37,44 @@ TreeItem::~TreeItem()
TreeItem* TreeItem::appendChild(const QList<QVariant> &data)
{
TreeItem *child = new TreeItem(data, this);
m_model->notifyRowAboutToAppend(this);
TreeItem *child = new TreeItem(data, m_model, this);
child->m_depth = m_depth + 1;
m_childItems.append(child);
m_model->notifyRowAppended();
return child;
}
void TreeItem::appendChild(TreeItem *child)
{
m_model->notifyRowAboutToAppend(this);
child->m_depth = m_depth + 1;
child->m_parentItem = this;
m_childItems.append(child);
m_model->notifyRowAppended();
}
TreeItem *TreeItem::child(int row)
void TreeItem::removeChild(TreeItem *child)
{
m_model->notifyRowAboutToDelete(this, child->row());
bool success = m_childItems.removeAll(child);
Q_ASSERT(success);
child->m_depth = 0;
child->m_parentItem = nullptr;
m_model->notifyRowDeleted();
}
void TreeItem::changeParent(TreeItem *newParent)
{
if (m_parentItem) {
m_parentItem->removeChild(this);
}
if (newParent) {
newParent->appendChild(this);
}
}
TreeItem *TreeItem::child(int row) const
{
return m_childItems.value(row);
}
......@@ -77,7 +104,7 @@ int TreeItem::row() const
if (m_parentItem)
return m_parentItem->m_childItems.indexOf(const_cast<TreeItem*>(this));
return 0;
return -1;
}
int TreeItem::depth() const
......
......@@ -29,15 +29,17 @@
/* @brief This class is a generic class to represent items of a tree-like model
*/
class AbstractTreeModel;
class TreeItem
{
public:
/* @brief Construct a TreeItem
@param data List of data elements (columns) of the created item
@param model Pointer to the model to which this elem belongs to
@param parentItem address of the parent if the child is not orphan
*/
explicit TreeItem(const QList<QVariant> &data, TreeItem *parentItem = nullptr);
~TreeItem();
explicit TreeItem(const QList<QVariant> &data, AbstractTreeModel* model, TreeItem *parentItem = nullptr);
virtual ~TreeItem();
/* @brief Creates a child of the current item
@param data: List of data elements (columns) to init the child with.
......@@ -49,10 +51,19 @@ public:
*/
void appendChild(TreeItem *child);
/* @brief Remove given child from children list. The parent of the child is updated
accordingly
*/
void removeChild(TreeItem *child);
/* @brief Change the parent of the current item. Structures are modified accordingly
*/
void changeParent(TreeItem *newParent);
/* @brief Retrieves a child of the current item
@param row is the index of the child to retrieve
*/
TreeItem *child(int row);
TreeItem *child(int row) const;
/* @brief Return the number of children */
int childCount() const;
......@@ -66,6 +77,7 @@ public:
QVariant data(int column) const;
/* @brief Return the index of current item amongst father's children
Returns -1 on error (eg: no parent set)
*/
int row() const;
......@@ -76,10 +88,12 @@ public:
/* @brief Return the depth of the current item*/
int depth() const;
private:
protected:
QList<TreeItem*> m_childItems;
QList<QVariant> m_itemData;
TreeItem *m_parentItem;
AbstractTreeModel *m_model;
int m_depth;
};
......
......@@ -21,15 +21,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "abstractprojectitem.h"
#include "projectitemmodel.h"
#include "bin.h"
#include <QDomElement>
#include <QVariant>
#include <QPainter>
AbstractProjectItem::AbstractProjectItem(PROJECTITEMTYPE type, const QString &id, AbstractProjectItem *parent) :
AbstractProjectItem::AbstractProjectItem(PROJECTITEMTYPE type, const QString &id, ProjectItemModel* model, AbstractProjectItem *parent) :
QObject()
, m_parent(parent)
, TreeItem(QList<QVariant>(), static_cast<AbstractTreeModel*>(model), (TreeItem*)parent)
, m_id(id)
, m_usage(0)
, m_clipStatus(StatusReady)
......@@ -40,9 +41,9 @@ AbstractProjectItem::AbstractProjectItem(PROJECTITEMTYPE type, const QString &id
{
}
AbstractProjectItem::AbstractProjectItem(PROJECTITEMTYPE type, const QDomElement &description, AbstractProjectItem *parent) :
AbstractProjectItem::AbstractProjectItem(PROJECTITEMTYPE type, const QDomElement &description,ProjectItemModel* model, AbstractProjectItem *parent) :
QObject()
, m_parent(parent)
, TreeItem(QList<QVariant>(), static_cast<AbstractTreeModel*>(model), (TreeItem*)parent)
, m_id(description.attribute(QStringLiteral("id")))
, m_usage(0)
, m_clipStatus(StatusReady)
......@@ -55,30 +56,25 @@ AbstractProjectItem::AbstractProjectItem(PROJECTITEMTYPE type, const QDomElement
AbstractProjectItem::~AbstractProjectItem()
{
while (!isEmpty()) {
AbstractProjectItem *child = takeFirst();
removeChild(child);
delete child;
}
}
bool AbstractProjectItem::operator==(const AbstractProjectItem *projectItem) const
{
// FIXME: only works for folders
bool equal = static_cast<const QList *const>(this) == static_cast<const QList *const>(projectItem);
equal &= m_parent == projectItem->parent();
bool equal = this->m_childItems == projectItem->m_childItems;
equal &= m_parentItem == projectItem->m_parentItem;
return equal;
}
AbstractProjectItem *AbstractProjectItem::parent() const
{
return m_parent;
return static_cast<AbstractProjectItem*>(m_parentItem);
}
void AbstractProjectItem::setRefCount(uint count)
{
m_usage = count;
bin()->emitItemUpdated(this);
static_cast<ProjectItemModel*>(m_model)->bin()->emitItemUpdated(this);
}
uint AbstractProjectItem::refCount() const
......@@ -89,13 +85,13 @@ uint AbstractProjectItem::refCount() const
void AbstractProjectItem::addRef()
{
m_usage++;
bin()->emitItemUpdated(this);
static_cast<ProjectItemModel*>(m_model)->bin()->emitItemUpdated(this);
}
void AbstractProjectItem::removeRef()
{
m_usage--;
bin()->emitItemUpdated(this);
static_cast<ProjectItemModel*>(m_model)->bin()->emitItemUpdated(this);
}
const QString &AbstractProjectItem::clipId() const
......@@ -103,29 +99,6 @@ const QString &AbstractProjectItem::clipId() const
return m_id;
}
void AbstractProjectItem::setParent(AbstractProjectItem *parent)
{
if (m_parent != parent) {
if (m_parent) {
m_parent->removeChild(this);
}
m_parent = parent;
QObject::setParent(m_parent);
}
if (m_parent && !m_parent->contains(this)) {
m_parent->addChild(this);
}
}
Bin *AbstractProjectItem::bin()
{
if (m_parent) {
return m_parent->bin();
}
return nullptr;
}
QPixmap AbstractProjectItem::roundedPixmap(const QPixmap &source)
{
QPixmap pix(source.width(), source.height());
......@@ -140,31 +113,7 @@ QPixmap AbstractProjectItem::roundedPixmap(const QPixmap &source)
return pix;
}
void AbstractProjectItem::addChild(AbstractProjectItem *child)
{
if (child && !contains(child)) {
bin()->emitAboutToAddItem(child);
append(child);
bin()->emitItemAdded(child);
}
}
void AbstractProjectItem::removeChild(AbstractProjectItem *child)
{
if (child && contains(child)) {
bin()->emitAboutToRemoveItem(child);
removeAll(child);
bin()->emitItemRemoved(child);
}
}
int AbstractProjectItem::index() const
{
if (m_parent) {
return m_parent->indexOf(const_cast<AbstractProjectItem *>(this));
}
return 0;
}
AbstractProjectItem::PROJECTITEMTYPE AbstractProjectItem::itemType() const
{
......@@ -265,3 +214,14 @@ AbstractProjectItem::CLIPSTATUS AbstractProjectItem::clipStatus() const
return m_clipStatus;
}
AbstractProjectItem *AbstractProjectItem::getEnclosingFolder(bool strict) const
{
if (!strict && itemType() == AbstractProjectItem::FolderItem) {
return const_cast<AbstractProjectItem*>(this);
}
if (m_parentItem) {
return static_cast<AbstractProjectItem*>(m_parentItem)->getEnclosingFolder(false);
}
return nullptr;
}
......@@ -23,10 +23,10 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#ifndef ABSTRACTPROJECTITEM_H
#define ABSTRACTPROJECTITEM_H
#include "abstractmodel/treeitem.hpp"
#include "project/jobs/abstractclipjob.h"
#include <QObject>
#include <QPixmap>
#include <QDateTime>
class ProjectClip;
......@@ -34,6 +34,7 @@ class ProjectFolder;
class Bin;
class QDomElement;
class QDomDocument;
class ProjectItemModel;
/**
* @class AbstractProjectItem
......@@ -42,7 +43,7 @@ class QDomDocument;
* Project items are stored in a tree like structure ...
*/
class AbstractProjectItem : public QObject, public QList<AbstractProjectItem *>
class AbstractProjectItem : public QObject, public TreeItem
{
Q_OBJECT
......@@ -59,15 +60,16 @@ public:
* @brief Constructor.
* @param parent parent this item should be added to
*/
AbstractProjectItem(PROJECTITEMTYPE type, const QString &id, AbstractProjectItem *parent = nullptr);
AbstractProjectItem(PROJECTITEMTYPE type, const QString &id, ProjectItemModel *model, AbstractProjectItem *parent = nullptr);
/**
* @brief Creates a project item upon project load.
* @param description element for this item.
* @param model pointer to the model this item is added to.
* @param parent parent this item should be added to
*
* We try to read the attributes "name" and "description"
*/
AbstractProjectItem(PROJECTITEMTYPE type, const QDomElement &description, AbstractProjectItem *parent = nullptr);
AbstractProjectItem(PROJECTITEMTYPE type, const QDomElement &description, ProjectItemModel *model, AbstractProjectItem *parent = nullptr);
virtual ~AbstractProjectItem();
bool operator==(const AbstractProjectItem *projectItem) const;
......@@ -93,10 +95,8 @@ public:
*/
virtual void removeChild(AbstractProjectItem *child);
/** @brief Returns a pointer to the bin model this item is child of (through its parent item). */
virtual Bin *bin();
/** @brief Returns the index this item has in its parent's child list. */
//TODO : this is redudant with TreeItem::row()
int index() const;
/** @brief Returns the type of this item (folder, clip, subclip, etc). */
......@@ -196,12 +196,16 @@ public:
virtual QString getToolTip() const = 0;
virtual bool rename(const QString &name, int column) = 0;
/* 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
*/
AbstractProjectItem *getEnclosingFolder(bool strict = false) const;
signals:
void childAdded(AbstractProjectItem *child);
void aboutToRemoveChild(AbstractProjectItem *child);
protected:
AbstractProjectItem *m_parent;
QString m_name;
QString m_description;
QIcon m_thumbnail;
......
This diff is collapsed.
......@@ -26,6 +26,8 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "abstractprojectitem.h"
#include "timecode.h"
#include "effects/effectstack/model/effectstackmodel.hpp"
#include <KMessageWidget>
#include <QWidget>
......@@ -183,9 +185,6 @@ public:
/** @brief Sets the document for the bin and initialize some stuff */
void setDocument(KdenliveDoc *project);
/** @brief Returns the root folder, which is the parent for all items in the view */
ProjectFolder *rootFolder();
/** @brief Create a clip item from its xml description */
void createClip(const QDomElement &xml);
......@@ -226,11 +225,6 @@ public:
/** @brief Current producer has changed, refresh monitor and timeline*/
void refreshClip(const QString &id);
/** @brief Some stuff used to notify the Item Model */
void emitAboutToAddItem(AbstractProjectItem *item);
void emitItemAdded(AbstractProjectItem *item);
void emitAboutToRemoveItem(AbstractProjectItem *item);
void emitItemRemoved(AbstractProjectItem *item);
void setupMenu(QMenu *addMenu, QAction *defaultAction, const QHash<QString, QAction *> &actions);
/** @brief The source file was modified, we will reload it soon, disable item in the meantime */
......@@ -295,16 +289,8 @@ public:
void deleteClipMarker(const QString &comment, const QString &id, const GenTime &position);
/** @brief Delete all markers from @param id clip. */
void deleteAllClipMarkers(const QString &id);
/** @brief Remove an effect from a bin clip. */
void removeEffect(const QString &id, const QDomElement &effect);
void moveEffect(const QString &id, const QList<int> &oldPos, const QList<int> &newPos);
/** @brief Add an effect to a bin clip. */
void addEffect(const QString &id, QDomElement &effect);
/** @brief Update a bin clip effect. */
void updateEffect(const QString &id, QDomElement &effect, int ix, bool refreshStackWidget);
void changeEffectState(const QString &id, const QList<int> &indexes, bool disable, bool refreshStack);
/** @brief Edit an effect settings to a bin clip. */
void editMasterEffect(ClipController *ctl);
void editMasterEffect(AbstractProjectItem *clip);
/** @brief An effect setting was changed, update stack if displayed. */
void updateMasterEffect(ClipController *ctl);
/** @brief Display a message about an operation in status bar. */
......@@ -371,8 +357,6 @@ private slots:
void slotItemDropped(const QStringList &ids, const QModelIndex &parent);
void slotItemDropped(const QList<QUrl> &urls, const QModelIndex &parent);
void slotEffectDropped(const QString &effect, const QModelIndex &parent);
void slotUpdateEffect(QString id, QDomElement oldEffect, QDomElement newEffect, int ix, bool refreshStack = false);
void slotChangeEffectState(QString id, const QList<int> &indexes, bool disable);
void slotItemEdited(const QModelIndex &, const QModelIndex &, const QVector<int> &);
void slotAddUrl(const QString &url, int folderId, const QMap<QString, QString> &data = QMap<QString, QString>());
void slotAddUrl(const QString &url, const QMap<QString, QString> &data = QMap<QString, QString>());
......@@ -444,8 +428,6 @@ public slots:
void slotSaveClipMarkers(const QString &id);
void slotDuplicateClip();
void slotLocateClip();
void slotDeleteEffect(const QString &id, QDomElement effect);
void slotMoveEffect(const QString &id, const QList<int> &currentPos, int newPos);
/** @brief Request audio thumbnail for clip with id */
void slotCreateAudioThumb(const QString &id);
/** @brief Abort audio thumbnail for clip with id */
......@@ -456,8 +438,8 @@ public slots:
/** @brief Pass some important properties to timeline track producers. */
void updateTimelineProducers(const QString &id, const QMap<QString, QString> &passProperties);
/** @brief Add effect to active Bin clip (used when double clicking an effect in list). */
void slotEffectDropped(QString id, QDomElement);
/** @brief Request current frame from project monitor.
void slotEffectDropped(QString id, const QString& effectID);
/** @brief Request current frame from project monitor.
* @param clipId is the id of a clip we want to hide from screenshot
* @param request true to start capture process, false to end it. It is necessary to emit a false after image is received
**/
......@@ -482,7 +464,6 @@ protected:
private:
ProjectItemModel *m_itemModel;
QAbstractItemView *m_itemView;
ProjectFolder *m_rootFolder;
/** @brief An "Up" item that is inserted in bin when using icon view so that user can navigate up */
ProjectFolderUp *m_folderUp;
BinItemDelegate *m_binTreeViewDelegate;
......@@ -565,9 +546,11 @@ signals:
/** @brief Trigger timecode format refresh where needed. */
void refreshTimeCode();
/** @brief Request display of effect stack for a Bin clip. */
void masterClipSelected(ClipController *, Monitor *);
/** @brief Request updating of the effect stack if currently displayed. */
void masterClipUpdated(ClipController *, Monitor *);
void requestShowEffectStack(std::shared_ptr<EffectStackModel>);
/** @brief Request that the current effect stack is hidden */
void requestHideEffectStack();
/** @brief Request that the given clip is displayed in the clip monitor */
void requestClipShow(ProjectClip*);
void displayBinMessage(const QString &, KMessageWidget::MessageType);
void displayMessage(const QString &, int, MessageType);
void requesteInvalidRemoval(const QString &, const QString &, const QString &);
......
......@@ -116,117 +116,6 @@ void RenameBinFolderCommand::redo()
m_bin->renameFolder(m_clipId, m_newName);
}
AddBinEffectCommand::AddBinEffectCommand(Bin *bin, const QString &clipId, QDomElement &effect, QUndoCommand *parent) :
QUndoCommand(parent),
m_bin(bin),
m_clipId(clipId),
m_effect(effect)
{
setText(i18n("Add Bin Effect"));
}
// virtual
void AddBinEffectCommand::undo()
{
m_bin->removeEffect(m_clipId, m_effect);
}
// virtual
void AddBinEffectCommand::redo()
{
m_bin->addEffect(m_clipId, m_effect);
}
RemoveBinEffectCommand::RemoveBinEffectCommand(Bin *bin, const QString &clipId, QDomElement &effect, QUndoCommand *parent) :
QUndoCommand(parent),
m_bin(bin),
m_clipId(clipId),
m_effect(effect)
{
setText(i18n("Remove Bin Effect"));
}
// virtual
void RemoveBinEffectCommand::undo()
{
m_bin->addEffect(m_clipId, m_effect);
}
// virtual
void RemoveBinEffectCommand::redo()
{
m_bin->removeEffect(m_clipId, m_effect);
}
UpdateBinEffectCommand::UpdateBinEffectCommand(Bin *bin, const QString &clipId, QDomElement &oldEffect, QDomElement &newEffect, int ix, bool refreshStack, QUndoCommand *parent) :
QUndoCommand(parent),
m_bin(bin),
m_clipId(clipId),
m_oldEffect(oldEffect),
m_newEffect(newEffect),
m_ix(ix),
m_refreshStack(refreshStack)
{
setText(i18n("Edit Bin Effect"));
}
// virtual
void UpdateBinEffectCommand::undo()
{
m_bin->updateEffect(m_clipId, m_oldEffect, m_ix, m_refreshStack);
}
// virtual
void UpdateBinEffectCommand::redo()
{
m_bin->updateEffect(m_clipId, m_newEffect, m_ix, m_refreshStack);
m_refreshStack = true;
}
ChangeMasterEffectStateCommand::ChangeMasterEffectStateCommand(Bin *bin, const QString &clipId, const QList<int> &effectIndexes, bool disable, QUndoCommand *parent) :
QUndoCommand(parent),
m_bin(bin),
m_clipId(clipId),
m_effectIndexes(effectIndexes),
m_disable(disable),
m_refreshEffectStack(false)
{
if (disable) {
setText(i18np("Disable effect", "Disable effects", effectIndexes.count()));
} else {
setText(i18np("Enable effect", "Enable effects", effectIndexes.count()));
}
}
// virtual
void ChangeMasterEffectStateCommand::undo()
{
m_bin->changeEffectState(m_clipId, m_effectIndexes, !m_disable, m_refreshEffectStack);
}
// virtual
void ChangeMasterEffectStateCommand::redo()
{
m_bin->changeEffectState(m_clipId, m_effectIndexes, m_disable, m_refreshEffectStack);
m_refreshEffectStack = true;
}
MoveBinEffectCommand::MoveBinEffectCommand(Bin *bin, const QString &clipId, const QList<int> &oldPos, int newPos, QUndoCommand *parent) :
QUndoCommand(parent),
m_bin(bin),
m_clipId(clipId),
m_oldindex(oldPos)
{
m_newindex.reserve(m_oldindex.count());
for (int i = 0; i < m_oldindex.count(); ++i) {
m_newindex << newPos + i;
}
setText(i18n("Move Bin Effect"));
}
// virtual
void MoveBinEffectCommand::undo()
{
m_bin->moveEffect(m_clipId, m_newindex, m_oldindex);
}
// virtual
void MoveBinEffectCommand::redo()
{
m_bin->moveEffect(m_clipId, m_oldindex, m_newindex);
}
RenameBinSubClipCommand::RenameBinSubClipCommand(Bin *bin, const QString &clipId, const QString &newName, const QString &oldName, int in, int out, QUndoCommand *parent) :
QUndoCommand(parent),
......
......@@ -79,71 +79,6 @@ private:
QString m_newName;
};
class AddBinEffectCommand : public QUndoCommand
{
public:
explicit AddBinEffectCommand(Bin *bin, const QString &clipId, QDomElement &effect, QUndoCommand *parent = nullptr);