projectitemmodel.cpp 10.9 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
Copyright (C) 2012  Till Theato <root@ttill.de>
Copyright (C) 2014  Jean-Baptiste Mardelle <jb@kdenlive.org>
This file is part of Kdenlive. See www.kdenlive.org.

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
published by the Free Software Foundation; either version 2 of
the License or (at your option) version 3 or any later version
accepted by the membership of KDE e.V. (or its successor approved
by the membership of KDE e.V.), which shall act as a proxy 
defined in Section 14 of version 3 of the license.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "projectitemmodel.h"
#include "abstractprojectitem.h"
#include "projectclip.h"
26
#include "projectsubclip.h"
27 28 29 30 31 32 33 34
#include "projectfolder.h"
#include "bin.h"

#include <qvarlengtharray.h>
#include <KLocalizedString>
#include <QIcon>
#include <QMimeData>
#include <QDebug>
35
#include <QStringListModel>
36 37 38 39 40 41 42 43 44 45 46 47 48


ProjectItemModel::ProjectItemModel(Bin *bin) :
    QAbstractItemModel(bin)
  , m_bin(bin)
{
    connect(m_bin, SIGNAL(itemUpdated(AbstractProjectItem*)), this, SLOT(onItemUpdated(AbstractProjectItem*)));
}

ProjectItemModel::~ProjectItemModel()
{
}

49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65
int ProjectItemModel::mapToColumn(int column) const
{
    switch (column) {
      case 0:
          return AbstractProjectItem::DataName;
          break;
      case 1:
          return AbstractProjectItem::DataDate;
          break;
      case 2:
          return AbstractProjectItem::DataDescription;
          break;
      default:
          return AbstractProjectItem::DataName;
    }
}

66 67 68 69 70
QVariant ProjectItemModel::data(const QModelIndex& index, int role) const
{
    if (!index.isValid()) {
        return QVariant();
    }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
71
    if (role == Qt::DisplayRole || role == Qt::EditRole) {
72
        AbstractProjectItem *item = static_cast<AbstractProjectItem *>(index.internalPointer());
73
        return item->data(static_cast<AbstractProjectItem::DataType>(mapToColumn(index.column())));
74
    }
75 76 77 78
    if (role == Qt::DecorationRole) {
        if (index.column() != 0) {
            return QVariant();
        }
79 80
        // Data has to be returned as icon to allow the view to scale it
        AbstractProjectItem *item = static_cast<AbstractProjectItem *>(index.internalPointer());
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
81
        QIcon icon = item->data(AbstractProjectItem::DataThumbnail).value<QIcon>();
82 83
        return icon;
    }
84
    else {
85 86 87 88 89
        AbstractProjectItem *item = static_cast<AbstractProjectItem *>(index.internalPointer());
        return item->data((AbstractProjectItem::DataType) role);
    }
}

Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
90 91 92
bool ProjectItemModel::setData(const QModelIndex & index, const QVariant & value, int role)
{
    AbstractProjectItem *item = static_cast<AbstractProjectItem *>(index.internalPointer());
93
    if (item->rename(value.toString(), index.column())) {
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
94 95 96 97 98 99 100
        emit dataChanged(index, index, QVector<int> () << role);
        return true;
    }
    // Item name was not changed
    return false;
}

101 102
Qt::ItemFlags ProjectItemModel::flags(const QModelIndex& index) const
{
103
    /*return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable;*/
104
    if (!index.isValid()) {
105
        return Qt::ItemIsDropEnabled;
106
    }
107
    AbstractProjectItem *item = static_cast<AbstractProjectItem *>(index.internalPointer());
108 109 110 111 112 113
    AbstractProjectItem::PROJECTITEMTYPE type = item->itemType();
    switch (type) {
      case AbstractProjectItem::FolderItem:
          return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable;
          break;
      case AbstractProjectItem::ClipItem:
114 115
          if (!item->statusReady())
              return Qt::ItemIsSelectable;
116
          return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | Qt::ItemIsEditable;
117 118 119 120
          break;
      case AbstractProjectItem::SubClipItem:
          return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled;
          break;
121 122 123
      case AbstractProjectItem::FolderUpItem:
          return Qt::ItemIsEnabled;
          break;
124 125 126
      default:
          return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable;
    }
127 128
}

129
// cppcheck-suppress unusedFunction
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
bool ProjectItemModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{
    Q_UNUSED(row)
    Q_UNUSED(column)
    if (action == Qt::IgnoreAction)
        return true;

    if (data->hasUrls()) {
        emit itemDropped(data->urls(), parent);
        return true;
    }

    if (data->hasFormat(QStringLiteral("kdenlive/producerslist"))) {
       // Dropping an Bin item
        QStringList ids = QString(data->data(QStringLiteral("kdenlive/producerslist"))).split(';');
        emit itemDropped(ids, parent);
        return true;
    }

    if (data->hasFormat(QStringLiteral("kdenlive/effectslist"))) {
        // Dropping effect on a Bin item
        const QString effect = QString::fromUtf8(data->data(QStringLiteral("kdenlive/effectslist")));
        emit effectDropped(effect, parent);
        return true;
    }

    if (data->hasFormat(QStringLiteral("kdenlive/clip"))) {
        QStringList list = QString(data->data(QStringLiteral("kdenlive/clip"))).split(';');
        emit addClipCut(list.at(0), list.at(1).toInt(), list.at(2).toInt());
    }

    return false;
}

164 165 166 167
QVariant ProjectItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
        QVariant columnName;
168 169
        switch (section) {
        case 0:
170 171
            columnName = i18n("Name");
            break;
172
        case 1:
173 174
            columnName = i18n("Date");
            break;
175 176 177
        case 2:
            columnName = i18n("Description");
            break;
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222
        default:
            columnName = i18n("Unknown");
            break;
        }
        return columnName;
    }
    return QAbstractItemModel::headerData(section, orientation, role);
}

QModelIndex ProjectItemModel::index(int row, int column, const QModelIndex& parent) const
{
    if (!hasIndex(row, column, parent)) {
        return QModelIndex();
    }

    AbstractProjectItem *parentItem;

    if (parent.isValid()) {
        parentItem = static_cast<AbstractProjectItem*>(parent.internalPointer());
    } else {
        parentItem = m_bin->rootFolder();
    }

    AbstractProjectItem *childItem = parentItem->at(row);
    return createIndex(row, column, childItem);
}

QModelIndex ProjectItemModel::parent(const QModelIndex& index) const
{
    if (!index.isValid()) {
        return QModelIndex();
    }

    AbstractProjectItem * parentItem = static_cast<AbstractProjectItem*>(index.internalPointer())->parent();

    if (!parentItem || parentItem == m_bin->rootFolder()) {
        return QModelIndex();
    }

    return createIndex(parentItem->index(), 0, parentItem);
}

int ProjectItemModel::rowCount(const QModelIndex& parent) const
{
    // ?
223
    /*if (parent.column() > 0) {
224
        return 0;
225
    }*/
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245

    AbstractProjectItem *parentItem;
    if (parent.isValid()) {
        parentItem = static_cast<AbstractProjectItem*>(parent.internalPointer());
    } else {
        parentItem = m_bin->rootFolder();
    }

    return parentItem->count();
}

int ProjectItemModel::columnCount(const QModelIndex& parent) const
{
    if (parent.isValid()) {
        return static_cast<AbstractProjectItem*>(parent.internalPointer())->supportedDataCount();
    } else {
        return m_bin->rootFolder()->supportedDataCount();
    }
}

246
// cppcheck-suppress unusedFunction
247 248 249 250 251
Qt::DropActions ProjectItemModel::supportedDropActions() const
{
    return Qt::CopyAction | Qt::MoveAction;
}

252 253 254
QStringList ProjectItemModel::mimeTypes() const
{
    QStringList types;
255
    types << QStringLiteral("kdenlive/producerslist") << QStringLiteral("text/uri-list") << QStringLiteral("kdenlive/clip") << QStringLiteral("kdenlive/effectslist");
256 257 258 259 260
    return types;
}

QMimeData* ProjectItemModel::mimeData(const QModelIndexList& indices) const
{
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
261 262
    // Mime data is a list of id's separated by ';'.
    // Clip ids are represented like:  2 (where 2 is the clip's id)
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
263
    // Clip zone ids are represented like:  2/10/200 (where 2 is the clip's id, 10 and 200 are in and out points)
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
264
    // Folder ids are represented like:  #2 (where 2 is the folder's id)
265
    QMimeData *mimeData = new QMimeData();
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
266 267 268
    QStringList list;
    for (int i = 0; i < indices.count(); i++) {
        QModelIndex ix = indices.at(i);
Vincent Pinon's avatar
Vincent Pinon committed
269
        if (!ix.isValid() || ix.column() != 0) continue;
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
270
        AbstractProjectItem *item = static_cast<AbstractProjectItem*>(ix.internalPointer());
271 272 273 274 275
        AbstractProjectItem::PROJECTITEMTYPE type = item->itemType();
        if (type == AbstractProjectItem::ClipItem) {
            list << item->clipId();
        } else if (type == AbstractProjectItem::SubClipItem) {
            QPoint p = item->zone();
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
276
            list << item->clipId() + "/" + QString::number(p.x()) + "/" + QString::number(p.y());
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
277 278 279
        }
        else if (type == AbstractProjectItem::FolderItem) {
            list << "#" + item->clipId();
280 281
        }
    }
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
282 283
    if (!list.isEmpty()) {
        QByteArray data;
284 285
        data.append(list.join(QStringLiteral(";")).toUtf8());
        mimeData->setData(QStringLiteral("kdenlive/producerslist"),  data);
Jean-Baptiste Mardelle's avatar
Jean-Baptiste Mardelle committed
286 287
    }
    return mimeData;
288 289 290 291 292 293
}


void ProjectItemModel::onAboutToAddItem(AbstractProjectItem* item)
{
    AbstractProjectItem *parentItem = item->parent();
294
    if (parentItem == Q_NULLPTR) return;
295 296 297
    QModelIndex parentIndex;
    if (parentItem != m_bin->rootFolder()) {
        parentIndex = createIndex(parentItem->index(), 0, parentItem);
298
    }
299 300 301 302 303 304 305 306 307 308 309 310
    beginInsertRows(parentIndex, parentItem->count(), parentItem->count());
}

void ProjectItemModel::onItemAdded(AbstractProjectItem* item)
{
    Q_UNUSED(item)
    endInsertRows();
}

void ProjectItemModel::onAboutToRemoveItem(AbstractProjectItem* item)
{
    AbstractProjectItem *parentItem = item->parent();
311
    if (parentItem == Q_NULLPTR) return;
312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328
    QModelIndex parentIndex;
    if (parentItem != m_bin->rootFolder()) {
        parentIndex = createIndex(parentItem->index(), 0, parentItem);
    }

    beginRemoveRows(parentIndex, item->index(), item->index());
}

void ProjectItemModel::onItemRemoved(AbstractProjectItem* item)
{
    Q_UNUSED(item)
    endRemoveRows();
}


void ProjectItemModel::onItemUpdated(AbstractProjectItem* item)
{
329
    if (!item || item->clipStatus() == AbstractProjectItem::StatusDeleting) return;
330
    AbstractProjectItem *parentItem = item->parent();
331
    if (parentItem == Q_NULLPTR) return;
332 333 334 335 336 337
    QModelIndex parentIndex;
    if (parentItem != m_bin->rootFolder()) {
        parentIndex = createIndex(parentItem->index(), 0, parentItem);
    }
    emit dataChanged(parentIndex, parentIndex);
}