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 <QtCore/QList>
28#include "objectdescription.h"
29#include "phononnamespace_p.h"
30#include <QtCore/QMimeData>
31#include <QtCore/QStringList>
32#include <QIcon>
33#include <QPainter>
34#include "factory_p.h"
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
42#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) // Qt 5
43static const uint qt_meta_data_Phonon__ObjectDescriptionModel[] = {
44
45 // content:
46 7, // revision
47 0, // classname
48 0, 0, // classinfo
49 0, 0, // methods
50 0, 0, // properties
51 0, 0, // enums/sets
52 0, 0, // constructors
53 0, // flags
54 0, // signalCount
55
56 0 // eod
57};
58#else // Qt 4
59static const uint qt_meta_data_Phonon__ObjectDescriptionModel[] = {
60
61 // content:
62 1, // revision
63 0, // classname
64 0, 0, // classinfo
65 0, 0, // methods
66 0, 0, // properties
67 0, 0, // enums/sets
68
69 0 // eod
70};
71#endif
72
73#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) // Qt 5
74 #define P_STATIC_META_STRINGDATA(name, string, stringlen, stringlenplustwo) \
75 struct qt_meta_stringdata_Phonon__ObjectDescriptionModel_##name##_t { QByteArrayData data[1]; char stringdata[stringlenplustwo]; }; \
76 static const qt_meta_stringdata_Phonon__ObjectDescriptionModel_##name##_t qt_meta_stringdata_Phonon__ObjectDescriptionModel_##name = { \
77 { \
78 Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(stringlen, offsetof(qt_meta_stringdata_Phonon__ObjectDescriptionModel_ ## name ## _t, stringdata) + 0 - 0 * sizeof(QByteArrayData)) \
79 }, \
80 string \
81 };
82
83 P_STATIC_META_STRINGDATA(AudioOutputDeviceType, "Phonon::AudioOutputDeviceModel\0", 30, 32)
84 P_STATIC_META_STRINGDATA(AudioCaptureDeviceType, "Phonon::AudioCaptureDeviceModel\0", 31, 33)
85 P_STATIC_META_STRINGDATA(VideoCaptureDeviceType, "Phonon::VideoCaptureDeviceModel\0", 31, 33)
86 P_STATIC_META_STRINGDATA(EffectType, "Phonon::EffectModel\0", 19, 21)
87 P_STATIC_META_STRINGDATA(AudioChannelType, "Phonon::AudioChannelModel\0", 25, 27)
88 P_STATIC_META_STRINGDATA(SubtitleType, "Phonon::SubtitleModel\0", 21, 23)
89
90 #undef P_STATIC_META_STRINGDATA
91#else // Qt 4
92 static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioOutputDeviceType[] = { "Phonon::AudioOutputDevice\0" };
93 static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioCaptureDeviceType[] = { "Phonon::AudioCaptureDevice\0" };
94 static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_VideoCaptureDeviceType[] = { "Phonon::VideoCaptureDevice\0" };
95 static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_EffectType[] = { "Phonon::EffectDescription\0" };
96 static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_AudioChannelType[] = { "Phonon::AudioChannelDescription\0" };
97 static const char qt_meta_stringdata_Phonon__ObjectDescriptionModel_SubtitleType[] = { "Phonon::SubtitleDescription\0" };
98#endif
99
100#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) // Qt 5
101 #define OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(X) { \
102 &QAbstractListModel::staticMetaObject, \
103 qt_meta_stringdata_Phonon__ObjectDescriptionModel_##X.data, \
104 qt_meta_data_Phonon__ObjectDescriptionModel, \
105 0, 0, 0 }
106#else // Qt 4
107 #define OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(X) { \
108 &QAbstractListModel::staticMetaObject, \
109 qt_meta_stringdata_Phonon__ObjectDescriptionModel_ ## X, \
110 qt_meta_data_Phonon__ObjectDescriptionModel, \
111 0 }
112#endif
113
114namespace Phonon
115{
116
117template<> const QMetaObject ObjectDescriptionModel<AudioOutputDeviceType>::staticMetaObject = {
118 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioOutputDeviceType)
119};
120template<> const QMetaObject ObjectDescriptionModel<AudioCaptureDeviceType>::staticMetaObject = {
121 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioCaptureDeviceType)
122};
123template<> const QMetaObject ObjectDescriptionModel<VideoCaptureDeviceType>::staticMetaObject = {
124 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(VideoCaptureDeviceType)
125};
126template<> const QMetaObject ObjectDescriptionModel<EffectType>::staticMetaObject = {
127 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(EffectType)
128};
129template<> const QMetaObject ObjectDescriptionModel<AudioChannelType>::staticMetaObject = {
130 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioChannelType)
131};
132template<> const QMetaObject ObjectDescriptionModel<SubtitleType>::staticMetaObject = {
133 OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(SubtitleType)
134};
135
136template<ObjectDescriptionType type>
137const QMetaObject *ObjectDescriptionModel<type>::metaObject() const
138{
139 return &staticMetaObject;
140}
141
142template<ObjectDescriptionType type>
143void *ObjectDescriptionModel<type>::qt_metacast(const char *_clname)
144{
145#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) // Qt 5
146 qWarning("WARNING: Phonon4Qt5 has not been verified to successfully qt_metacast ObjectDescriptionModels.");
147#endif
148 if (!_clname) {
149 return 0;
150 }
151 if (!strcmp(_clname, ObjectDescriptionModel<type>::staticMetaObject.className())) {
152 return static_cast<void *>(const_cast<ObjectDescriptionModel<type> *>(this));
153 }
154 return QAbstractListModel::qt_metacast(_clname);
155}
156
157/*
158template<ObjectDescriptionType type>
159int ObjectDescriptionModel<type>::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
160{
161 return QAbstractListModel::qt_metacall(_c, _id, _a);
162}
163*/
164
165int ObjectDescriptionModelData::rowCount(const QModelIndex &parent) const
166{
167 if (parent.isValid())
168 return 0;
169
170 return d->data.size();
171}
172
173QVariant ObjectDescriptionModelData::data(const QModelIndex &index, int role) const
174{
175 if (!index.isValid() || index.row() >= d->data.size() || index.column() != 0)
176 return QVariant();
177
178 switch(role)
179 {
180 case Qt::EditRole:
181 case Qt::DisplayRole:
182 return d->data.at(index.row())->name();
183 break;
184 case Qt::ToolTipRole:
185 return d->data.at(index.row())->description();
186 break;
187 case Qt::DecorationRole:
188 {
189 /* Returns an icon if available. Paint a subicon representing the entity (platform
190 * plugin or backend) which discovered this object, if it is specified */
191 QVariant icon = d->data.at(index.row())->property("icon");
192 QVariant discovererIcon = d->data.at(index.row())->property("discovererIcon");
193 if (icon.isValid()) {
194 if (icon.type() == QVariant::String) {
195 icon = Platform::icon(icon.toString());
196 }
197 if (discovererIcon.type() == QVariant::String) {
198 discovererIcon = Platform::icon(discovererIcon.toString());
199 }
200 if (icon.type() == QVariant::Icon) {
201 if (discovererIcon.type() == QVariant::Icon) {
202 // Insert the subicon in the top-right corner of the icon
203 QPixmap pixmap = icon.value<QIcon>().pixmap(QSize(64, 64));
204 QPixmap subPixmap = discovererIcon.value<QIcon>().pixmap(QSize(22, 22));
205 QPainter painter(&pixmap);
206 painter.drawPixmap(42, 0, subPixmap);
207 return QIcon(pixmap);
208 } else {
209 return icon;
210 }
211 }
212 }
213 }
214 return QVariant();
215 default:
216 return QVariant();
217}
218}
219
220Qt::ItemFlags ObjectDescriptionModelData::flags(const QModelIndex &index) const
221{
222 if(!index.isValid() || index.row() >= d->data.size() || index.column() != 0) {
223 return Qt::ItemIsDropEnabled;
224 }
225
226 QVariant available = d->data.at(index.row())->property("available");
227 if (available.isValid() && available.type() == QVariant::Bool && !available.toBool()) {
228 return Qt::ItemIsSelectable | Qt::ItemIsDragEnabled;
229 }
230 return Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
231}
232
233QList<int> ObjectDescriptionModelData::tupleIndexOrder() const
234{
235 QList<int> ret;
236 for (int i = 0; i < d->data.size(); ++i) {
237 ret.append(d->data.at(i)->index());
238 }
239 return ret;
240}
241
242int ObjectDescriptionModelData::tupleIndexAtPositionIndex(int positionIndex) const
243{
244 return d->data.at(positionIndex)->index();
245}
246
247QMimeData *ObjectDescriptionModelData::mimeData(ObjectDescriptionType type, const QModelIndexList &indexes) const
248{
249 QMimeData *mimeData = new QMimeData;
250 QByteArray encodedData;
251 QDataStream stream(&encodedData, QIODevice::WriteOnly);
252 QModelIndexList::const_iterator end = indexes.constEnd();
253 QModelIndexList::const_iterator index = indexes.constBegin();
254 for(; index!=end; ++index) {
255 if ((*index).isValid()) {
256 stream << d->data.at((*index).row())->index();
257 }
258 }
259 //pDebug() << Q_FUNC_INFO << "setting mimeData to" << mimeTypes(type).first() << "=>" << encodedData.toHex();
260 mimeData->setData(mimeTypes(type).first(), encodedData);
261 return mimeData;
262}
263
264void ObjectDescriptionModelData::moveUp(const QModelIndex &index)
265{
266 if (!index.isValid() || index.row() >= d->data.size() || index.row() < 1 || index.column() != 0)
267 return;
268
269 emit d->model->layoutAboutToBeChanged();
270 QModelIndex above = index.sibling(index.row() - 1, index.column());
271 d->data.swap(index.row(), above.row());
272 QModelIndexList from, to;
273 from << index << above;
274 to << above << index;
275 d->model->changePersistentIndexList(from, to);
276 emit d->model->layoutChanged();
277}
278
279void ObjectDescriptionModelData::moveDown(const QModelIndex &index)
280{
281 if (!index.isValid() || index.row() >= d->data.size() - 1 || index.column() != 0)
282 return;
283
284 emit d->model->layoutAboutToBeChanged();
285 QModelIndex below = index.sibling(index.row() + 1, index.column());
286 d->data.swap(index.row(), below.row());
287 QModelIndexList from, to;
288 from << index << below;
289 to << below << index;
290 d->model->changePersistentIndexList(from, to);
291 emit d->model->layoutChanged();
292}
293
294ObjectDescriptionModelData::ObjectDescriptionModelData(QAbstractListModel *model)
295 : d(new ObjectDescriptionModelDataPrivate(model))
296{
297}
298
299ObjectDescriptionModelData::~ObjectDescriptionModelData()
300{
301 delete d;
302}
303
304void ObjectDescriptionModelData::setModelData(const QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > &newData)
305{
306 d->model->beginResetModel();
307 d->data = newData;
308 d->model->endResetModel();
309}
310
311QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > ObjectDescriptionModelData::modelData() const
312{
313 return d->data;
314}
315
316QExplicitlySharedDataPointer<ObjectDescriptionData> ObjectDescriptionModelData::modelData(const QModelIndex &index) const
317{
318 if (!index.isValid() || index.row() >= d->data.size() || index.column() != 0) {
319 return QExplicitlySharedDataPointer<ObjectDescriptionData>(new ObjectDescriptionData(0));
320 }
321 return d->data.at(index.row());
322}
323
324Qt::DropActions ObjectDescriptionModelData::supportedDropActions() const
325{
326 //pDebug() << Q_FUNC_INFO;
327 return Qt::MoveAction;
328}
329
330bool ObjectDescriptionModelData::dropMimeData(ObjectDescriptionType type, const QMimeData *data, Qt::DropAction action,
331 int row, int column, const QModelIndex &parent)
332{
333 Q_UNUSED(action);
334 Q_UNUSED(column);
335 Q_UNUSED(parent);
336 //pDebug() << Q_FUNC_INFO << data << action << row << column << parent;
337
338 QString format = mimeTypes(type).first();
339 if (!data->hasFormat(format)) {
340 return false;
341 }
342
343 if (row == -1) {
344 row = d->data.size();
345 }
346
347 QByteArray encodedData = data->data(format);
348 QDataStream stream(&encodedData, QIODevice::ReadOnly);
349 QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > toInsert;
350 while (!stream.atEnd()) {
351 int otherIndex;
352 stream >> otherIndex;
353 ObjectDescriptionData *obj = ObjectDescriptionData::fromIndex(type, otherIndex);
354
355 if (obj->isValid()) {
356 toInsert << QExplicitlySharedDataPointer<ObjectDescriptionData>(obj);
357 } else {
358 delete obj;
359 }
360 }
361 d->model->beginInsertRows(QModelIndex(), row, row + toInsert.size() - 1);
362 for (int i = 0 ; i < toInsert.count(); ++i) {
363 d->data.insert(row, toInsert.at(i));
364 }
365 d->model->endInsertRows();
366 return true;
367}
368
369
370bool ObjectDescriptionModelData::removeRows(int row, int count, const QModelIndex &parent)
371{
372 //pDebug() << Q_FUNC_INFO << row << count << parent;
373 if (parent.isValid() || row + count > d->data.size()) {
374 return false;
375 }
376 d->model->beginRemoveRows(parent, row, row + count - 1);
377 for (;count > 0; --count) {
378 d->data.removeAt(row);
379 }
380 d->model->endRemoveRows();
381 return true;
382}
383
384/*
385template<ObjectDescriptionType type>
386bool ObjectDescriptionModel<type>::insertRows(int row, int count, const QModelIndex &parent)
387{
388 pDebug() << Q_FUNC_INFO << row << count << parent;
389 if (parent.isValid() || row < 0 || row > d->data.size()) {
390 return false;
391 }
392 beginInsertRows(parent, row, row + count - 1);
393 for (;count > 0; --count) {
394 d->data.insert(row, ObjectDescription<type>());
395 }
396 endInsertRows();
397 return true;
398}
399*/
400
401QStringList ObjectDescriptionModelData::mimeTypes(ObjectDescriptionType type) const
402{
403 return QStringList(QLatin1String("application/x-phonon-objectdescription") + QString::number(static_cast<int>(type)));
404}
405
406#if !defined(Q_CC_MSVC) || _MSC_VER > 1300 || defined(Q_CC_INTEL) || defined(Q_CC_MINGW)
407#define INSTANTIATE_META_FUNCTIONS(type) \
408template const QMetaObject *ObjectDescriptionModel<type>::metaObject() const; \
409template void *ObjectDescriptionModel<type>::qt_metacast(const char *)
410
411INSTANTIATE_META_FUNCTIONS(AudioOutputDeviceType);
412INSTANTIATE_META_FUNCTIONS(AudioCaptureDeviceType);
413INSTANTIATE_META_FUNCTIONS(VideoCaptureDeviceType);
414INSTANTIATE_META_FUNCTIONS(EffectType);
415INSTANTIATE_META_FUNCTIONS(AudioChannelType);
416INSTANTIATE_META_FUNCTIONS(SubtitleType);
417#endif
418/*INSTANTIATE_META_FUNCTIONS(VideoOutputDeviceType);
419INSTANTIATE_META_FUNCTIONS(AudioCodecType);
420INSTANTIATE_META_FUNCTIONS(VideoCodecType);
421INSTANTIATE_META_FUNCTIONS(ContainerFormatType);
422INSTANTIATE_META_FUNCTIONS(VisualizationType);
423*/
424} // namespace Phonon
425
426#endif //QT_NO_PHONON_OBJECTDESCRIPTIONMODEL
427