1/* This file is part of the KDE project
2 Copyright (C) 2006-2007 Matthias Kretz <kretz@kde.org>
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) version 3, or any
8 later version accepted by the membership of KDE e.V. (or its
9 successor approved by the membership of KDE e.V.), Nokia Corporation
10 (or its successors, if any) and the KDE Free Qt Foundation, which shall
11 act as a proxy defined in Section 6 of version 3 of the license.
12
13 This library is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with this library. If not, see <http://www.gnu.org/licenses/>.
20
21*/
22
23#include "objectdescriptionmodel.h"
24#include "objectdescriptionmodel_p.h"
25#include "phonondefs_p.h"
26#include "platform_p.h"
27#include "objectdescription.h"
28#include "phononnamespace_p.h"
29#include "factory_p.h"
30#include <QIcon>
31#include <QPainter>
32#include <QList>
33#include <QMimeData>
34#include <QStringList>
35
36#ifndef QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
37
38// If this wasn't so terrible ...
39// ObjectDescriptionModel is a template class. Moc however cannot handle
40// templates so the solution done here is to *manually* do whatever moc does.
41
42static const uint qt_meta_data_Phonon__ObjectDescriptionModel[] = {
43
44 // content:
45 7, // revision
46 0, // classname
47 0, 0, // classinfo
48 0, 0, // methods
49 0, 0, // properties
50 0, 0, // enums/sets
51 0, 0, // constructors
52 0, // flags
53 0, // signalCount
54
55 0 // eod
56};
57
58#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
59 #define P_STATIC_META_STRINGDATA(name, string, stringlen, stringlenplustwo) \
60 struct qt_meta_stringdata_Phonon__ObjectDescriptionModel_##name##_t { QByteArrayData data[1]; char stringdata[stringlenplustwo]; }; \
61 static const qt_meta_stringdata_Phonon__ObjectDescriptionModel_##name##_t qt_meta_stringdata_Phonon__ObjectDescriptionModel_##name = { \
62 { \
63 Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(stringlen, offsetof(qt_meta_stringdata_Phonon__ObjectDescriptionModel_ ## name ## _t, stringdata) + 0 - 0 * sizeof(QByteArrayData)) \
64 }, \
65 string \
66 };
67#else
68 #define P_STATIC_META_STRINGDATA(name, string, stringlen, stringlenplustwo) \
69 struct qt_meta_stringdata_Phonon__ObjectDescriptionModel_##name##_t { const uint offsetsAndSize[2]; char stringdata[stringlenplustwo]; }; \
70 static const qt_meta_stringdata_Phonon__ObjectDescriptionModel_##name##_t qt_meta_stringdata_Phonon__ObjectDescriptionModel_##name = { \
71 { \
72 uint(offsetof(qt_meta_stringdata_Phonon__ObjectDescriptionModel_ ## name ## _t, stringdata)), stringlen \
73 }, \
74 string \
75 };
76#endif
77
78 P_STATIC_META_STRINGDATA(AudioOutputDeviceType, "Phonon::AudioOutputDeviceModel\0", 30, 32)
79 P_STATIC_META_STRINGDATA(AudioCaptureDeviceType, "Phonon::AudioCaptureDeviceModel\0", 31, 33)
80 P_STATIC_META_STRINGDATA(VideoCaptureDeviceType, "Phonon::VideoCaptureDeviceModel\0", 31, 33)
81 P_STATIC_META_STRINGDATA(EffectType, "Phonon::EffectModel\0", 19, 21)
82 P_STATIC_META_STRINGDATA(AudioChannelType, "Phonon::AudioChannelModel\0", 25, 27)
83 P_STATIC_META_STRINGDATA(SubtitleType, "Phonon::SubtitleModel\0", 21, 23)
84
85 #undef P_STATIC_META_STRINGDATA
86
87#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
88 #define OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(X) { \
89 &QAbstractListModel::staticMetaObject, \
90 qt_meta_stringdata_Phonon__ObjectDescriptionModel_##X.data, \
91 qt_meta_data_Phonon__ObjectDescriptionModel, \
92 nullptr, nullptr, nullptr }
93#else
94 #define OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(X) { \
95 &QAbstractListModel::staticMetaObject, \
96 qt_meta_stringdata_Phonon__ObjectDescriptionModel_##X.offsetsAndSize, \
97 qt_meta_data_Phonon__ObjectDescriptionModel, \
98 nullptr, nullptr, nullptr }
99#endif
100
101namespace Phonon
102{
103
104template<> const QMetaObject ObjectDescriptionModel<AudioOutputDeviceType>::staticMetaObject = {
105 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioOutputDeviceType)
106};
107template<> const QMetaObject ObjectDescriptionModel<AudioCaptureDeviceType>::staticMetaObject = {
108 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioCaptureDeviceType)
109};
110template<> const QMetaObject ObjectDescriptionModel<VideoCaptureDeviceType>::staticMetaObject = {
111 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(VideoCaptureDeviceType)
112};
113template<> const QMetaObject ObjectDescriptionModel<EffectType>::staticMetaObject = {
114 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(EffectType)
115};
116template<> const QMetaObject ObjectDescriptionModel<AudioChannelType>::staticMetaObject = {
117 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioChannelType)
118};
119template<> const QMetaObject ObjectDescriptionModel<SubtitleType>::staticMetaObject = {
120 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(SubtitleType)
121};
122
123template<ObjectDescriptionType type>
124const QMetaObject *ObjectDescriptionModel<type>::metaObject() const
125{
126 return &staticMetaObject;
127}
128
129template<ObjectDescriptionType type>
130void *ObjectDescriptionModel<type>::qt_metacast(const char *_clname)
131{
132 qWarning(msg: "WARNING: Phonon4Qt5 has not been verified to successfully qt_metacast ObjectDescriptionModels.");
133 if (!_clname) {
134 return nullptr;
135 }
136 if (!strcmp(s1: _clname, s2: ObjectDescriptionModel<type>::staticMetaObject.className())) {
137 return static_cast<void *>(const_cast<ObjectDescriptionModel<type> *>(this));
138 }
139 return QAbstractListModel::qt_metacast(_clname);
140}
141
142/*
143template<ObjectDescriptionType type>
144int ObjectDescriptionModel<type>::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
145{
146 return QAbstractListModel::qt_metacall(_c, _id, _a);
147}
148*/
149
150int ObjectDescriptionModelData::rowCount(const QModelIndex &parent) const
151{
152 if (parent.isValid())
153 return 0;
154
155 return d->data.size();
156}
157
158QVariant ObjectDescriptionModelData::data(const QModelIndex &index, int role) const
159{
160 if (!index.isValid() || index.row() >= d->data.size() || index.column() != 0)
161 return QVariant();
162
163 switch(role)
164 {
165 case Qt::EditRole:
166 case Qt::DisplayRole:
167 return d->data.at(i: index.row())->name();
168 break;
169 case Qt::ToolTipRole:
170 return d->data.at(i: index.row())->description();
171 break;
172 case Qt::DecorationRole:
173 {
174 /* Returns an icon if available. Paint a subicon representing the entity (platform
175 * plugin or backend) which discovered this object, if it is specified */
176 QVariant icon = d->data.at(i: index.row())->property(name: "icon");
177 QVariant discovererIcon = d->data.at(i: index.row())->property(name: "discovererIcon");
178 if (icon.isValid()) {
179 if (icon.type() == QVariant::String) {
180 icon = Platform::icon(name: icon.toString());
181 }
182 if (discovererIcon.type() == QVariant::String) {
183 discovererIcon = Platform::icon(name: discovererIcon.toString());
184 }
185 if (icon.type() == QVariant::Icon) {
186 if (discovererIcon.type() == QVariant::Icon) {
187 // Insert the subicon in the top-right corner of the icon
188 QPixmap pixmap = icon.value<QIcon>().pixmap(size: QSize(64, 64));
189 QPixmap subPixmap = discovererIcon.value<QIcon>().pixmap(size: QSize(22, 22));
190 QPainter painter(&pixmap);
191 painter.drawPixmap(x: 42, y: 0, pm: subPixmap);
192 return QIcon(pixmap);
193 } else {
194 return icon;
195 }
196 }
197 }
198 }
199 return QVariant();
200 default:
201 return QVariant();
202}
203}
204
205Qt::ItemFlags ObjectDescriptionModelData::flags(const QModelIndex &index) const
206{
207 if(!index.isValid() || index.row() >= d->data.size() || index.column() != 0) {
208 return Qt::ItemIsDropEnabled;
209 }
210
211 QVariant available = d->data.at(i: index.row())->property(name: "available");
212 if (available.isValid() && available.type() == QVariant::Bool && !available.toBool()) {
213 return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
214 }
215 return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
216}
217
218QList<int> ObjectDescriptionModelData::tupleIndexOrder() const
219{
220 QList<int> ret;
221 for (int i = 0; i < d->data.size(); ++i) {
222 ret.append(t: d->data.at(i)->index());
223 }
224 return ret;
225}
226
227int ObjectDescriptionModelData::tupleIndexAtPositionIndex(int positionIndex) const
228{
229 return d->data.at(i: positionIndex)->index();
230}
231
232QMimeData *ObjectDescriptionModelData::mimeData(ObjectDescriptionType type, const QModelIndexList &indexes) const
233{
234 QMimeData *mimeData = new QMimeData;
235 QByteArray encodedData;
236 QDataStream stream(&encodedData, QIODevice::WriteOnly);
237 QModelIndexList::const_iterator end = indexes.constEnd();
238 QModelIndexList::const_iterator index = indexes.constBegin();
239 for(; index!=end; ++index) {
240 if ((*index).isValid()) {
241 stream << d->data.at(i: (*index).row())->index();
242 }
243 }
244 //pDebug() << Q_FUNC_INFO << "setting mimeData to" << mimeTypes(type).first() << "=>" << encodedData.toHex();
245 mimeData->setData(mimetype: mimeTypes(type).first(), data: encodedData);
246 return mimeData;
247}
248
249void ObjectDescriptionModelData::moveUp(const QModelIndex &index)
250{
251 if (!index.isValid() || index.row() >= d->data.size() || index.row() < 1 || index.column() != 0)
252 return;
253
254 emit d->model->layoutAboutToBeChanged();
255 QModelIndex above = index.sibling(arow: index.row() - 1, acolumn: index.column());
256#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
257 d->data.swapItemsAt(i: index.row(), j: above.row());
258#else
259 d->data.swap(index.row(), above.row());
260#endif
261 QModelIndexList from, to;
262 from << index << above;
263 to << above << index;
264 d->model->changePersistentIndexList(from, to);
265 emit d->model->layoutChanged();
266}
267
268void ObjectDescriptionModelData::moveDown(const QModelIndex &index)
269{
270 if (!index.isValid() || index.row() >= d->data.size() - 1 || index.column() != 0)
271 return;
272
273 emit d->model->layoutAboutToBeChanged();
274 QModelIndex below = index.sibling(arow: index.row() + 1, acolumn: index.column());
275#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
276 d->data.swapItemsAt(i: index.row(), j: below.row());
277#else
278 d->data.swap(index.row(), below.row());
279#endif
280 QModelIndexList from, to;
281 from << index << below;
282 to << below << index;
283 d->model->changePersistentIndexList(from, to);
284 emit d->model->layoutChanged();
285}
286
287ObjectDescriptionModelData::ObjectDescriptionModelData(QAbstractListModel *model)
288 : d(new ObjectDescriptionModelDataPrivate(model))
289{
290}
291
292ObjectDescriptionModelData::~ObjectDescriptionModelData()
293{
294 delete d;
295}
296
297void ObjectDescriptionModelData::setModelData(const QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > &newData)
298{
299 d->model->beginResetModel();
300 d->data = newData;
301 d->model->endResetModel();
302}
303
304QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > ObjectDescriptionModelData::modelData() const
305{
306 return d->data;
307}
308
309QExplicitlySharedDataPointer<ObjectDescriptionData> ObjectDescriptionModelData::modelData(const QModelIndex &index) const
310{
311 if (!index.isValid() || index.row() >= d->data.size() || index.column() != 0) {
312 return QExplicitlySharedDataPointer<ObjectDescriptionData>(new ObjectDescriptionData(nullptr));
313 }
314 return d->data.at(i: index.row());
315}
316
317Qt::DropActions ObjectDescriptionModelData::supportedDropActions() const
318{
319 //pDebug() << Q_FUNC_INFO;
320 return Qt::MoveAction;
321}
322
323bool ObjectDescriptionModelData::dropMimeData(ObjectDescriptionType type, const QMimeData *data, Qt::DropAction action,
324 int row, int column, const QModelIndex &parent)
325{
326 Q_UNUSED(action);
327 Q_UNUSED(column);
328 Q_UNUSED(parent);
329 //pDebug() << Q_FUNC_INFO << data << action << row << column << parent;
330
331 QString format = mimeTypes(type).first();
332 if (!data->hasFormat(mimetype: format)) {
333 return false;
334 }
335
336 if (row == -1) {
337 row = d->data.size();
338 }
339
340 QByteArray encodedData = data->data(mimetype: format);
341 QDataStream stream(&encodedData, QIODevice::ReadOnly);
342 QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > toInsert;
343 while (!stream.atEnd()) {
344 int otherIndex;
345 stream >> otherIndex;
346 ObjectDescriptionData *obj = ObjectDescriptionData::fromIndex(type, index: otherIndex);
347
348 if (obj->isValid()) {
349 toInsert << QExplicitlySharedDataPointer<ObjectDescriptionData>(obj);
350 } else {
351 delete obj;
352 }
353 }
354 d->model->beginInsertRows(parent: QModelIndex(), first: row, last: row + toInsert.size() - 1);
355 for (int i = 0 ; i < toInsert.count(); ++i) {
356 d->data.insert(i: row, t: toInsert.at(i));
357 }
358 d->model->endInsertRows();
359 return true;
360}
361
362
363bool ObjectDescriptionModelData::removeRows(int row, int count, const QModelIndex &parent)
364{
365 //pDebug() << Q_FUNC_INFO << row << count << parent;
366 if (parent.isValid() || row + count > d->data.size()) {
367 return false;
368 }
369 d->model->beginRemoveRows(parent, first: row, last: row + count - 1);
370 for (;count > 0; --count) {
371 d->data.removeAt(i: row);
372 }
373 d->model->endRemoveRows();
374 return true;
375}
376
377/*
378template<ObjectDescriptionType type>
379bool ObjectDescriptionModel<type>::insertRows(int row, int count, const QModelIndex &parent)
380{
381 pDebug() << Q_FUNC_INFO << row << count << parent;
382 if (parent.isValid() || row < 0 || row > d->data.size()) {
383 return false;
384 }
385 beginInsertRows(parent, row, row + count - 1);
386 for (;count > 0; --count) {
387 d->data.insert(row, ObjectDescription<type>());
388 }
389 endInsertRows();
390 return true;
391}
392*/
393
394QStringList ObjectDescriptionModelData::mimeTypes(ObjectDescriptionType type) const
395{
396 return QStringList(QLatin1String("application/x-phonon-objectdescription") + QString::number(static_cast<int>(type)));
397}
398
399#if !defined(Q_CC_MSVC) || _MSC_VER > 1300 || defined(Q_CC_INTEL) || defined(Q_CC_MINGW)
400#define INSTANTIATE_META_FUNCTIONS(type) \
401template const QMetaObject *ObjectDescriptionModel<type>::metaObject() const; \
402template void *ObjectDescriptionModel<type>::qt_metacast(const char *)
403
404INSTANTIATE_META_FUNCTIONS(AudioOutputDeviceType);
405INSTANTIATE_META_FUNCTIONS(AudioCaptureDeviceType);
406INSTANTIATE_META_FUNCTIONS(VideoCaptureDeviceType);
407INSTANTIATE_META_FUNCTIONS(EffectType);
408INSTANTIATE_META_FUNCTIONS(AudioChannelType);
409INSTANTIATE_META_FUNCTIONS(SubtitleType);
410#endif
411/*INSTANTIATE_META_FUNCTIONS(VideoOutputDeviceType);
412INSTANTIATE_META_FUNCTIONS(AudioCodecType);
413INSTANTIATE_META_FUNCTIONS(VideoCodecType);
414INSTANTIATE_META_FUNCTIONS(ContainerFormatType);
415INSTANTIATE_META_FUNCTIONS(VisualizationType);
416*/
417} // namespace Phonon
418
419#endif //QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
420

source code of phonon/phonon/objectdescriptionmodel.cpp