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 | |
42 | static 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 | |
101 | namespace Phonon |
102 | { |
103 | |
104 | template<> const QMetaObject ObjectDescriptionModel<AudioOutputDeviceType>::staticMetaObject = { |
105 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioOutputDeviceType) |
106 | }; |
107 | template<> const QMetaObject ObjectDescriptionModel<AudioCaptureDeviceType>::staticMetaObject = { |
108 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioCaptureDeviceType) |
109 | }; |
110 | template<> const QMetaObject ObjectDescriptionModel<VideoCaptureDeviceType>::staticMetaObject = { |
111 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(VideoCaptureDeviceType) |
112 | }; |
113 | template<> const QMetaObject ObjectDescriptionModel<EffectType>::staticMetaObject = { |
114 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(EffectType) |
115 | }; |
116 | template<> const QMetaObject ObjectDescriptionModel<AudioChannelType>::staticMetaObject = { |
117 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(AudioChannelType) |
118 | }; |
119 | template<> const QMetaObject ObjectDescriptionModel<SubtitleType>::staticMetaObject = { |
120 | OBJECT_DESCRIPTION_MODEL_STATIC_META_OBJECT(SubtitleType) |
121 | }; |
122 | |
123 | template<ObjectDescriptionType type> |
124 | const QMetaObject *ObjectDescriptionModel<type>::metaObject() const |
125 | { |
126 | return &staticMetaObject; |
127 | } |
128 | |
129 | template<ObjectDescriptionType type> |
130 | void *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 | /* |
143 | template<ObjectDescriptionType type> |
144 | int ObjectDescriptionModel<type>::qt_metacall(QMetaObject::Call _c, int _id, void **_a) |
145 | { |
146 | return QAbstractListModel::qt_metacall(_c, _id, _a); |
147 | } |
148 | */ |
149 | |
150 | int ObjectDescriptionModelData::rowCount(const QModelIndex &parent) const |
151 | { |
152 | if (parent.isValid()) |
153 | return 0; |
154 | |
155 | return d->data.size(); |
156 | } |
157 | |
158 | QVariant 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 | |
205 | Qt::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 | |
218 | QList<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 | |
227 | int ObjectDescriptionModelData::tupleIndexAtPositionIndex(int positionIndex) const |
228 | { |
229 | return d->data.at(i: positionIndex)->index(); |
230 | } |
231 | |
232 | QMimeData *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 | |
249 | void 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 | |
268 | void 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 | |
287 | ObjectDescriptionModelData::ObjectDescriptionModelData(QAbstractListModel *model) |
288 | : d(new ObjectDescriptionModelDataPrivate(model)) |
289 | { |
290 | } |
291 | |
292 | ObjectDescriptionModelData::~ObjectDescriptionModelData() |
293 | { |
294 | delete d; |
295 | } |
296 | |
297 | void ObjectDescriptionModelData::setModelData(const QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > &newData) |
298 | { |
299 | d->model->beginResetModel(); |
300 | d->data = newData; |
301 | d->model->endResetModel(); |
302 | } |
303 | |
304 | QList<QExplicitlySharedDataPointer<ObjectDescriptionData> > ObjectDescriptionModelData::modelData() const |
305 | { |
306 | return d->data; |
307 | } |
308 | |
309 | QExplicitlySharedDataPointer<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 | |
317 | Qt::DropActions ObjectDescriptionModelData::supportedDropActions() const |
318 | { |
319 | //pDebug() << Q_FUNC_INFO; |
320 | return Qt::MoveAction; |
321 | } |
322 | |
323 | bool 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 | |
363 | bool 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 | /* |
378 | template<ObjectDescriptionType type> |
379 | bool 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 | |
394 | QStringList 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) \ |
401 | template const QMetaObject *ObjectDescriptionModel<type>::metaObject() const; \ |
402 | template void *ObjectDescriptionModel<type>::qt_metacast(const char *) |
403 | |
404 | INSTANTIATE_META_FUNCTIONS(AudioOutputDeviceType); |
405 | INSTANTIATE_META_FUNCTIONS(AudioCaptureDeviceType); |
406 | INSTANTIATE_META_FUNCTIONS(VideoCaptureDeviceType); |
407 | INSTANTIATE_META_FUNCTIONS(EffectType); |
408 | INSTANTIATE_META_FUNCTIONS(AudioChannelType); |
409 | INSTANTIATE_META_FUNCTIONS(SubtitleType); |
410 | #endif |
411 | /*INSTANTIATE_META_FUNCTIONS(VideoOutputDeviceType); |
412 | INSTANTIATE_META_FUNCTIONS(AudioCodecType); |
413 | INSTANTIATE_META_FUNCTIONS(VideoCodecType); |
414 | INSTANTIATE_META_FUNCTIONS(ContainerFormatType); |
415 | INSTANTIATE_META_FUNCTIONS(VisualizationType); |
416 | */ |
417 | } // namespace Phonon |
418 | |
419 | #endif //QT_NO_PHONON_OBJECTDESCRIPTIONMODEL |
420 | |