| 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 | |