Select Git revision
actionextenderdefault.h
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
codecmodel.cpp 23.99 KiB
/****************************************************************************
* Copyright (C) 2012-2018 Savoir-faire Linux *
* Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Lesser General Public *
* License as published by the Free Software Foundation; either *
* version 2.1 of the License, or (at your option) any later version. *
* *
* This library 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 *
* Lesser 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 "codecmodel.h"
//Qt
#include <QtCore/QDebug>
#include <QtCore/QCoreApplication>
#include <QtCore/QSortFilterProxyModel>
#include <QtCore/QItemSelectionModel>
#include <QMimeData>
//DRing
#include <account_const.h>
//Ring
#include "account.h"
#include "dbus/configurationmanager.h"
#include "mime.h"
#include "callmodel.h"
#include <private/matrixutils.h>
typedef void (CodecModelPrivate::*CodecModelFct)();
class CodecModelPrivate final : public QObject
{
Q_OBJECT
public:
CodecModelPrivate(CodecModel* parent);
///@struct CodecData store audio/video codec information
struct CodecData {
int id ;
QString name ;
QString bitrate ;
QString min_bitrate;
QString max_bitrate;
QString samplerate ;
QString type ;
QString quality ;
QString min_quality;
QString max_quality;
QString auto_quality_enabled;
};
//Attributes
QList<CodecData*> m_lCodecs ;
QMap<int,bool> m_lEnabledCodecs ;
Account* m_pAccount ;
QSortFilterProxyModel* m_pAudioProxy ;
QSortFilterProxyModel* m_pVideoProxy ;
QStringList m_lMimes ;
QItemSelectionModel* m_pSelectionModel;
CodecModel::EditState m_EditState ;
static Matrix2D<CodecModel::EditState, CodecModel::EditAction,CodecModelFct> m_mStateMachine;
//Callbacks
QModelIndex add ( );
void remove ( const QModelIndex& idx );
void clear ( );
void reload ( );
void save ( );
void nothing ( );
void modify ( );
//Helpers
bool findCodec(int id);
QModelIndex getIndexofCodecByID(int id);
inline void performAction(const CodecModel::EditAction action);
private:
CodecModel* q_ptr;
};
#define CMP &CodecModelPrivate
Matrix2D<CodecModel::EditState, CodecModel::EditAction,CodecModelFct> CodecModelPrivate::m_mStateMachine ={{
/* SAVE MODIFY RELOAD CLEAR */
/* LOADING */ {{ CMP::nothing, CMP::nothing, CMP::reload , CMP::nothing }},
/* READY */ {{ CMP::nothing, CMP::modify , CMP::reload , CMP::clear }},
/* MODIFIED */ {{ CMP::save , CMP::nothing, CMP::reload , CMP::clear }},
/* OUTDATED */ {{ CMP::save , CMP::nothing, CMP::reload , CMP::clear }},
/* RELOADING */ {{ CMP::nothing, CMP::nothing, CMP::nothing, CMP::nothing }},
}};
#undef CMP
CodecModelPrivate::CodecModelPrivate(CodecModel* parent) : q_ptr(parent),
m_pAudioProxy(nullptr),m_pVideoProxy(nullptr),m_pSelectionModel(nullptr)
{
}
///Constructor
CodecModel::CodecModel(Account* account) :
QAbstractListModel(account?(QObject*)account:(QObject*)QCoreApplication::instance()), d_ptr(new CodecModelPrivate(this))
{
Q_ASSERT(account);
d_ptr->m_EditState = CodecModel::EditState::LOADING;
d_ptr->m_pAccount = account;
// New accounts don't have ID yet, avoid a warning
if (account && !account->isNew())
setObjectName("CodecModel: "+(account?account->id():"Unknown"));
d_ptr->m_lMimes << RingMimes::AUDIO_CODEC << RingMimes::VIDEO_CODEC;
this << EditAction::RELOAD;
d_ptr->m_EditState = CodecModel::EditState::READY;
}
CodecModel::~CodecModel()
{
while (d_ptr->m_lCodecs.size()) {
CodecModelPrivate::CodecData* c = d_ptr->m_lCodecs[0];
d_ptr->m_lCodecs.removeAt(0);
delete c;
}
}
QHash<int,QByteArray> CodecModel::roleNames() const
{
static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames();
static bool initRoles = false;
if (!initRoles) {
initRoles = true;
roles.insert(CodecModel::Role::ID ,QByteArray("id"));
roles.insert(CodecModel::Role::NAME ,QByteArray("name"));
roles.insert(CodecModel::Role::BITRATE ,QByteArray("bitrate"));
roles.insert(CodecModel::Role::MIN_BITRATE,QByteArray("min_bitrate"));
roles.insert(CodecModel::Role::MAX_BITRATE,QByteArray("max_bitrate"));
roles.insert(CodecModel::Role::SAMPLERATE ,QByteArray("samplerate"));
roles.insert(CodecModel::Role::TYPE ,QByteArray("type"));
roles.insert(CodecModel::Role::QUALITY ,QByteArray("quality"));
roles.insert(CodecModel::Role::MIN_QUALITY,QByteArray("min_quality"));
roles.insert(CodecModel::Role::MAX_QUALITY,QByteArray("max_quality"));
roles.insert(CodecModel::Role::AUTO_QUALITY_ENABLED,QByteArray("autoQualityEnabled"));
}
return roles;
}
QItemSelectionModel* CodecModel::selectionModel() const
{
if (!d_ptr->m_pSelectionModel)
d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<CodecModel*>(this));
return d_ptr->m_pSelectionModel;
}
///Model data
QVariant CodecModel::data(const QModelIndex& idx, int role) const
{
if (idx.column() != 0)
return QVariant();
switch (role) {
case Qt::DisplayRole:
return QVariant(d_ptr->m_lCodecs[idx.row()]->name);
case Qt::CheckStateRole:
return QVariant(d_ptr->m_lEnabledCodecs[d_ptr->m_lCodecs[idx.row()]->id] ? Qt::Checked : Qt::Unchecked);
case CodecModel::Role::NAME:
return d_ptr->m_lCodecs[idx.row()]->name;
case CodecModel::Role::BITRATE:
return d_ptr->m_lCodecs[idx.row()]->bitrate;
case CodecModel::Role::MIN_BITRATE:
return d_ptr->m_lCodecs[idx.row()]->min_bitrate;
case CodecModel::Role::MAX_BITRATE:
return d_ptr->m_lCodecs[idx.row()]->max_bitrate;
case CodecModel::Role::SAMPLERATE:
return d_ptr->m_lCodecs[idx.row()]->samplerate;
case CodecModel::Role::ID:
return d_ptr->m_lCodecs[idx.row()]->id;
case CodecModel::Role::TYPE:
return d_ptr->m_lCodecs[idx.row()]->type;
case CodecModel::Role::QUALITY:
return d_ptr->m_lCodecs[idx.row()]->quality;
case CodecModel::Role::MIN_QUALITY:
return d_ptr->m_lCodecs[idx.row()]->min_quality;
case CodecModel::Role::MAX_QUALITY:
return d_ptr->m_lCodecs[idx.row()]->max_quality;
case CodecModel::Role::AUTO_QUALITY_ENABLED:
return d_ptr->m_lCodecs[idx.row()]->auto_quality_enabled;
default:
return QVariant();
}
return QVariant();
}
///Number of audio codecs
int CodecModel::rowCount(const QModelIndex& par) const
{
return par.isValid() ? 0 : d_ptr->m_lCodecs.size();
}
///Model flags
Qt::ItemFlags CodecModel::flags(const QModelIndex& idx) const
{
if (idx.column() == 0)
return QAbstractItemModel::flags(idx) | Qt::ItemIsUserCheckable
| Qt::ItemIsEnabled
| Qt::ItemIsSelectable
| Qt::ItemIsDragEnabled
| Qt::ItemIsDropEnabled;
return QAbstractItemModel::flags(idx);
}
///Set audio codec data
bool CodecModel::setData( const QModelIndex& idx, const QVariant &value, int role)
{
if (idx.column() != 0)
return false;
switch (role) {
case CodecModel::NAME :
d_ptr->m_lCodecs[idx.row()]->name = value.toString();
break;
case CodecModel::BITRATE :
d_ptr->m_lCodecs[idx.row()]->bitrate = value.toString();
break;
case CodecModel::MIN_BITRATE :
d_ptr->m_lCodecs[idx.row()]->min_bitrate = value.toString();
break;
case CodecModel::MAX_BITRATE :
d_ptr->m_lCodecs[idx.row()]->max_bitrate = value.toString();
break;
case Qt::CheckStateRole :
d_ptr->m_lEnabledCodecs[d_ptr->m_lCodecs[idx.row()]->id] = value.toBool();
break;
case CodecModel::SAMPLERATE :
d_ptr->m_lCodecs[idx.row()]->samplerate = value.toString();
break;
case CodecModel::ID :
d_ptr->m_lCodecs[idx.row()]->id = value.toInt();
break;
case CodecModel::TYPE :
d_ptr->m_lCodecs[idx.row()]->type = value.toString();
break;
case CodecModel::QUALITY :
d_ptr->m_lCodecs[idx.row()]->quality = value.toString();
break;
case CodecModel::MIN_QUALITY :
d_ptr->m_lCodecs[idx.row()]->min_quality = value.toString();
break;
case CodecModel::MAX_QUALITY :
d_ptr->m_lCodecs[idx.row()]->max_quality = value.toString();
break;
case CodecModel::AUTO_QUALITY_ENABLED :
d_ptr->m_lCodecs[idx.row()]->auto_quality_enabled = value.toString();
break;
default:
return false;
}
//if we did not return yet, then we modified the codec
emit dataChanged(idx, idx);
this << EditAction::MODIFY;
return true;
}
///Add a new audio codec
QModelIndex CodecModelPrivate::add()
{
q_ptr->beginInsertRows(QModelIndex(), m_lCodecs.size()-1, m_lCodecs.size()-1);
m_lCodecs << new CodecModelPrivate::CodecData;
q_ptr->endInsertRows();
emit q_ptr->dataChanged(q_ptr->index(m_lCodecs.size()-1,0), q_ptr->index(m_lCodecs.size()-1,0));
q_ptr << CodecModel::EditAction::MODIFY;
return q_ptr->index(m_lCodecs.size()-1,0);
}
///Remove audio codec at 'idx'
void CodecModelPrivate::remove(const QModelIndex& idx)
{
if (idx.isValid()) {
q_ptr->beginRemoveRows(QModelIndex(), idx.row(), idx.row());
CodecModelPrivate::CodecData* d = m_lCodecs[idx.row()];
m_lCodecs.removeAt(idx.row());
delete d;
q_ptr->endRemoveRows();
emit q_ptr->dataChanged(idx, q_ptr->index(m_lCodecs.size()-1,0));
q_ptr << CodecModel::EditAction::MODIFY;
}
else {
qDebug() << "Failed to remove an invalid audio codec";
}
}
///Remove everything
void CodecModelPrivate::clear()
{
while(m_lCodecs.size()) {
CodecModelPrivate::CodecData* d = m_lCodecs[0];
m_lCodecs.removeAt(0);
delete d;
}
m_lCodecs.clear();
m_lEnabledCodecs.clear();
m_EditState = CodecModel::EditState::READY;
}
///Reload the codeclist
void CodecModelPrivate::reload()
{
m_EditState = CodecModel::EditState::RELOADING;
ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance();
QVector<uint> codecIdList = configurationManager.getCodecList();
QVector<uint> activeCodecList = m_pAccount->isNew() ? codecIdList :
configurationManager.getActiveCodecList(m_pAccount->id());
QStringList tmpNameList;
//TODO: the following method cannot update the order of the codecs if it
// changes in the daemon after it has been initially loaded in the client
// load the active codecs first to get the correct order
foreach (const int aCodec, activeCodecList) {
const QMap<QString,QString> codec = configurationManager.getCodecDetails(
m_pAccount->isNew()? QString() : m_pAccount->id(), aCodec
);
if (!findCodec(aCodec)) {
const QModelIndex& idx = add();
q_ptr->setData(idx,QString::number(aCodec), CodecModel::Role::ID);
}
// update the codec
const auto& idx = getIndexofCodecByID(aCodec);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::NAME ] ,CodecModel::Role::NAME );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::SAMPLE_RATE ] ,CodecModel::Role::SAMPLERATE );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::BITRATE ] ,CodecModel::Role::BITRATE );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::MIN_BITRATE ] ,CodecModel::Role::MIN_BITRATE);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::MAX_BITRATE ] ,CodecModel::Role::MAX_BITRATE);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::TYPE ] ,CodecModel::Role::TYPE );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::QUALITY ] ,CodecModel::Role::QUALITY );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::MIN_QUALITY ] ,CodecModel::Role::MIN_QUALITY);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::MAX_QUALITY ] ,CodecModel::Role::MAX_QUALITY);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::AUTO_QUALITY_ENABLED] ,CodecModel::Role::AUTO_QUALITY_ENABLED);
q_ptr->setData(idx, Qt::Checked ,Qt::CheckStateRole);
// remove from list of all codecs, since we have already updated it
if (codecIdList.indexOf(aCodec)!=-1)
codecIdList.remove(codecIdList.indexOf(aCodec));
}
// now add add/update remaining (inactive) codecs
foreach (const int aCodec, codecIdList) {
const QMap<QString,QString> codec = configurationManager.getCodecDetails(
m_pAccount->isNew()? QString() : m_pAccount->id(), aCodec
);
if (!findCodec(aCodec)) {
const QModelIndex& idx = add();
q_ptr->setData(idx,QString::number(aCodec), CodecModel::Role::ID);
}
// update the codec
const auto& idx = getIndexofCodecByID(aCodec);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::NAME ] ,CodecModel::Role::NAME );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::SAMPLE_RATE ] ,CodecModel::Role::SAMPLERATE );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::BITRATE ] ,CodecModel::Role::BITRATE );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::MIN_BITRATE ] ,CodecModel::Role::MIN_BITRATE);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::MAX_BITRATE ] ,CodecModel::Role::MAX_BITRATE);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::TYPE ] ,CodecModel::Role::TYPE );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::QUALITY ] ,CodecModel::Role::QUALITY );
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::MIN_QUALITY ] ,CodecModel::Role::MIN_QUALITY);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::MAX_QUALITY ] ,CodecModel::Role::MAX_QUALITY);
q_ptr->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::AUTO_QUALITY_ENABLED] ,CodecModel::Role::AUTO_QUALITY_ENABLED);
q_ptr->setData(idx, Qt::Unchecked ,Qt::CheckStateRole);
}
m_EditState = CodecModel::EditState::READY;
}
///Save details
void CodecModelPrivate::save()
{
//TODO there is a race condition, the account has to be saved first
//Update active codec list
VectorUInt _codecList;
for (int i = 0; i < q_ptr->rowCount();i++) {
const QModelIndex& idx = q_ptr->index(i,0);
if (q_ptr->data(idx,Qt::CheckStateRole) == Qt::Checked) {
_codecList << q_ptr->data(idx,CodecModel::Role::ID).toInt();
}
}
ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance();
configurationManager.setActiveCodecList(m_pAccount->id(), _codecList);
//Update codec details
for (int i=0; i < q_ptr->rowCount();i++) {
const QModelIndex& idx = q_ptr->index(i,0);
MapStringString codecDetails;
codecDetails[ DRing::Account::ConfProperties::CodecInfo::NAME ] = q_ptr->data(idx,CodecModel::Role::NAME).toString();
codecDetails[ DRing::Account::ConfProperties::CodecInfo::SAMPLE_RATE ] = q_ptr->data(idx,CodecModel::Role::SAMPLERATE).toString();
codecDetails[ DRing::Account::ConfProperties::CodecInfo::BITRATE ] = q_ptr->data(idx,CodecModel::Role::BITRATE).toString();
codecDetails[ DRing::Account::ConfProperties::CodecInfo::MIN_BITRATE ] = q_ptr->data(idx,CodecModel::Role::MIN_BITRATE).toString();
codecDetails[ DRing::Account::ConfProperties::CodecInfo::MAX_BITRATE ] = q_ptr->data(idx,CodecModel::Role::MAX_BITRATE).toString();
codecDetails[ DRing::Account::ConfProperties::CodecInfo::TYPE ] = q_ptr->data(idx,CodecModel::Role::TYPE).toString();
codecDetails[ DRing::Account::ConfProperties::CodecInfo::QUALITY ] = q_ptr->data(idx,CodecModel::Role::QUALITY).toString();
codecDetails[ DRing::Account::ConfProperties::CodecInfo::MIN_QUALITY ] = q_ptr->data(idx,CodecModel::Role::MIN_QUALITY).toString();
codecDetails[ DRing::Account::ConfProperties::CodecInfo::MAX_QUALITY ] = q_ptr->data(idx,CodecModel::Role::MAX_QUALITY).toString();
codecDetails[ DRing::Account::ConfProperties::CodecInfo::AUTO_QUALITY_ENABLED] = q_ptr->data(idx,CodecModel::Role::AUTO_QUALITY_ENABLED).toString();
qDebug() << "setting codec details for " << q_ptr->data(idx,CodecModel::Role::NAME).toString();
configurationManager.setCodecDetails(m_pAccount->id(), q_ptr->data(idx,CodecModel::Role::ID).toUInt(), codecDetails);
}
m_EditState = CodecModel::EditState::READY;
}
void CodecModelPrivate::nothing()
{
//nothing
}
void CodecModelPrivate::modify()
{
m_EditState = CodecModel::EditState::MODIFIED;
m_pAccount << Account::EditAction::MODIFY;
}
void CodecModelPrivate::performAction(const CodecModel::EditAction action)
{
(this->*(m_mStateMachine[m_EditState][action]))();//FIXME don't use integer cast
}
CodecModel* CodecModel::operator<<(CodecModel::EditAction& action)
{
performAction(action);
return this;
}
CodecModel* operator<<(CodecModel* a, CodecModel::EditAction action)
{
return (!a)?nullptr : (*a) << action;
}
///Change the current edition state
bool CodecModel::performAction(const CodecModel::EditAction action)
{
CodecModel::EditState curState = d_ptr->m_EditState;
d_ptr->performAction(action);
return curState != d_ptr->m_EditState;
}
///Move a codec up in the priority list (using the selectionModel)
bool CodecModel::moveUp()
{
if (d_ptr->m_pSelectionModel) {
const QModelIndex& idx = d_ptr->m_pSelectionModel->currentIndex();
if (dropMimeData(mimeData({idx}), Qt::MoveAction, idx.row()-1, idx.column(),idx.parent())) {
d_ptr->m_pSelectionModel->setCurrentIndex(index(idx.row()-1,idx.column()), QItemSelectionModel::ClearAndSelect);
return true;
}
}
return false;
}
///Move a codec down in the priority list (using the selectionModel)
bool CodecModel::moveDown()
{
if (d_ptr->m_pSelectionModel) {
const QModelIndex& idx = d_ptr->m_pSelectionModel->currentIndex();
if (dropMimeData(mimeData({idx}), Qt::MoveAction, idx.row()+1, idx.column(),idx.parent())) {
d_ptr->m_pSelectionModel->setCurrentIndex(index(idx.row()+1,idx.column()), QItemSelectionModel::ClearAndSelect);
return true;
}
}
return false;
}
///Check is a codec is already in the list
bool CodecModelPrivate::findCodec(int id)
{
foreach(const CodecData* data, m_lCodecs) {
if (data->id == id)
return true;
}
return false;
}
///Return valid payload types
int CodecModel::acceptedPayloadTypes() const
{
return CallModel::DropPayloadType::AUDIO_CODEC | CallModel::DropPayloadType::VIDEO_CODEC;
}
QSortFilterProxyModel* CodecModel::videoCodecs() const
{
if (!d_ptr->m_pVideoProxy) {
d_ptr->m_pVideoProxy = new QSortFilterProxyModel(const_cast<CodecModel*>(this));
d_ptr->m_pVideoProxy->setSourceModel(const_cast<CodecModel*>(this));
d_ptr->m_pVideoProxy->setFilterRole(CodecModel::Role::TYPE);
d_ptr->m_pVideoProxy->setFilterFixedString("VIDEO");
}
return d_ptr->m_pVideoProxy;
}
QSortFilterProxyModel* CodecModel::audioCodecs() const
{
if (!d_ptr->m_pAudioProxy) {
d_ptr->m_pAudioProxy = new QSortFilterProxyModel(const_cast<CodecModel*>(this));
d_ptr->m_pAudioProxy->setSourceModel(const_cast<CodecModel*>(this));
d_ptr->m_pAudioProxy->setFilterRole(CodecModel::Role::TYPE);
d_ptr->m_pAudioProxy->setFilterFixedString("AUDIO");
}
return d_ptr->m_pAudioProxy;
}
// ======== DnD Api =========
QModelIndex CodecModelPrivate::getIndexofCodecByID(int id)
{
for (int i=0; i < q_ptr->rowCount();i++) {
const QModelIndex& idx = q_ptr->index(i,0);
if (q_ptr->data(idx, CodecModel::Role::ID) == id)
return idx;
}
return QModelIndex();
}
QStringList CodecModel::mimeTypes() const
{
return d_ptr->m_lMimes;
}
bool CodecModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent)
{
Q_UNUSED(action)
if(parent.isValid() || column > 0) {
qDebug() << "column invalid";
return false;
}
if (data->hasFormat(RingMimes::AUDIO_CODEC) || data->hasFormat(RingMimes::VIDEO_CODEC)) {
int destinationRow = -1;
if(row < 0) {
//drop on top
destinationRow = d_ptr->m_lCodecs.size() - 1;
}
else if(row >= d_ptr->m_lCodecs.size()) {
destinationRow = 0;
}
else if(data->hasFormat(RingMimes::VIDEO_CODEC) && row >= rowCount()) {
destinationRow = 0;
}
else {
destinationRow = row;
}
const int codecId = data->data(data->hasFormat(RingMimes::AUDIO_CODEC)
? RingMimes::AUDIO_CODEC
: RingMimes::VIDEO_CODEC).toInt();
const QModelIndex codecIdx = d_ptr->getIndexofCodecByID(codecId);
#ifdef Q_OS_WIN
/* To understand why qtDestinationRow is needed
http://doc.qt.io/qt-5/qabstractitemmodel.html#beginMoveRows */
auto qtDestinationRow = destinationRow > codecIdx.row() ? destinationRow+1 : destinationRow;
beginMoveRows(parent, codecIdx.row(), codecIdx.row(), parent, qtDestinationRow);
d_ptr->m_lCodecs.move(codecIdx.row(), destinationRow);
endMoveRows();
#else
beginRemoveRows(QModelIndex(), codecIdx.row(), codecIdx.row());
CodecModelPrivate::CodecData* codecInfo = d_ptr->m_lCodecs[codecIdx.row()];
d_ptr->m_lCodecs.removeAt(codecIdx.row());
endRemoveRows();
beginInsertRows(QModelIndex(), destinationRow, destinationRow);
d_ptr->m_lCodecs.insert(destinationRow,codecInfo);
endInsertRows();
#endif
this << EditAction::MODIFY;
return true;
}
return false;
}
QMimeData* CodecModel::mimeData(const QModelIndexList& indexes) const
{
QMimeData* mMimeData = new QMimeData();
for (const QModelIndex& index : indexes) {
if (index.isValid()) {
qDebug() << "setting mime data for row: " << index.row();
const QByteArray mime = (index.data(CodecModel::Role::TYPE).toString() == "AUDIO")
? RingMimes::AUDIO_CODEC
: RingMimes::VIDEO_CODEC;
mMimeData->setData(mime, index.data(CodecModel::Role::ID).toByteArray());
}
}
return mMimeData;
}
Qt::DropActions CodecModel::supportedDragActions() const
{
return Qt::MoveAction | Qt::TargetMoveAction;
}
Qt::DropActions CodecModel::supportedDropActions() const
{
return Qt::MoveAction | Qt::TargetMoveAction;
}
#include <codecmodel.moc>