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 |
43 | static 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 |
59 | static 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 | |
114 | namespace Phonon |
115 | { |
116 | |
117 | template<> const QMetaObject ObjectDescriptionModel<AudioOutputDeviceType>::staticMetaObject = { |
118 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioOutputDeviceType) |
119 | }; |
120 | template<> const QMetaObject ObjectDescriptionModel<AudioCaptureDeviceType>::staticMetaObject = { |
121 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioCaptureDeviceType) |
122 | }; |
123 | template<> const QMetaObject ObjectDescriptionModel<VideoCaptureDeviceType>::staticMetaObject = { |
124 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(VideoCaptureDeviceType) |
125 | }; |
126 | template<> const QMetaObject ObjectDescriptionModel<EffectType>::staticMetaObject = { |
127 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(EffectType) |
128 | }; |
129 | template<> const QMetaObject ObjectDescriptionModel<AudioChannelType>::staticMetaObject = { |
130 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioChannelType) |
131 | }; |
132 | template<> const QMetaObject ObjectDescriptionModel<SubtitleType>::staticMetaObject = { |
133 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(SubtitleType) |
134 | }; |
135 | |
136 | template<ObjectDescriptionType type> |
137 | const QMetaObject *ObjectDescriptionModel<type>::metaObject() const |
138 | { |
139 | return &staticMetaObject; |
140 | } |
141 | |
142 | template<ObjectDescriptionType type> |
143 | void *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 | /* |
158 | template<ObjectDescriptionType type> |
159 | int ObjectDescriptionModel<type>::qt_metacall(QMetaObject::Call _c, int _id, void **_a) |
160 | { |
161 | return QAbstractListModel::qt_metacall(_c, _id, _a); |
162 | } |
163 | */ |
164 | |
165 | int ObjectDescriptionModelData::rowCount(const QModelIndex &parent) const |
166 | { |
167 | if (parent.isValid()) |
168 | return 0; |
169 | |
170 | return d->data.size(); |
171 | } |
172 | |
173 | QVariant 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 | |
220 | Qt::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 | |
233 | QList<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 | |
242 | int ObjectDescriptionModelData::tupleIndexAtPositionIndex(int positionIndex) const |
243 | { |
244 | return d->data.at(positionIndex)->index(); |
245 | } |
246 | |
247 | QMimeData *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 | |
264 | void 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 | |
279 | void 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 | |
294 | ObjectDescriptionModelData::ObjectDescriptionModelData(QAbstractListModel *model) |
295 | : d(new ObjectDescriptionModelDataPrivate(model)) |
296 | { |
297 | } |
298 | |
299 | ObjectDescriptionModelData::~ObjectDescriptionModelData() |
300 | { |
301 | delete d; |
302 | } |
303 | |
304 | void ObjectDescriptionModelData::setModelData(const QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > &newData) |
305 | { |
306 | d->model->beginResetModel(); |
307 | d->data = newData; |
308 | d->model->endResetModel(); |
309 | } |
310 | |
311 | QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > ObjectDescriptionModelData::modelData() const |
312 | { |
313 | return d->data; |
314 | } |
315 | |
316 | QExplicitlySharedDataPointer<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 | |
324 | Qt::DropActions ObjectDescriptionModelData::supportedDropActions() const |
325 | { |
326 | //pDebug() << Q_FUNC_INFO; |
327 | return Qt::MoveAction; |
328 | } |
329 | |
330 | bool 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 | |
370 | bool 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 | /* |
385 | template<ObjectDescriptionType type> |
386 | bool 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 | |
401 | QStringList 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) \ |
408 | template const QMetaObject *ObjectDescriptionModel<type>::metaObject() const; \ |
409 | template void *ObjectDescriptionModel<type>::qt_metacast(const char *) |
410 | |
411 | INSTANTIATE_META_FUNCTIONS(AudioOutputDeviceType); |
412 | INSTANTIATE_META_FUNCTIONS(AudioCaptureDeviceType); |
413 | INSTANTIATE_META_FUNCTIONS(VideoCaptureDeviceType); |
414 | INSTANTIATE_META_FUNCTIONS(EffectType); |
415 | INSTANTIATE_META_FUNCTIONS(AudioChannelType); |
416 | INSTANTIATE_META_FUNCTIONS(SubtitleType); |
417 | #endif |
418 | /*INSTANTIATE_META_FUNCTIONS(VideoOutputDeviceType); |
419 | INSTANTIATE_META_FUNCTIONS(AudioCodecType); |
420 | INSTANTIATE_META_FUNCTIONS(VideoCodecType); |
421 | INSTANTIATE_META_FUNCTIONS(ContainerFormatType); |
422 | INSTANTIATE_META_FUNCTIONS(VisualizationType); |
423 | */ |
424 | } // namespace Phonon |
425 | |
426 | #endif //QT_NO_PHONON_OBJECTDESCRIPTIONMODEL |
427 | |