File indexing completed on 2025-01-19 12:45:15
0001 /* This file is part of the KDE project 0002 Copyright (C) 2006 Michael Larouche <michael.larouche@kdemail.net> 0003 2007 Kevin Ottens <ervin@kde.org> 0004 0005 This library is free software; you can redistribute it and/or 0006 modify it under the terms of the GNU Library General Public 0007 License version 2 as published by the Free Software Foundation. 0008 0009 This library is distributed in the hope that it will be useful, 0010 but WITHOUT ANY WARRANTY; without even the implied warranty of 0011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0012 Library General Public License for more details. 0013 0014 You should have received a copy of the GNU Library General Public License 0015 along with this library; see the file COPYING.LIB. If not, write to 0016 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 0017 Boston, MA 02110-1301, USA. 0018 0019 */ 0020 #include "kdevicelistmodel.h" 0021 #include "kdevicelistitem_p.h" 0022 0023 #include <solid/devicenotifier.h> 0024 #include <solid/deviceinterface.h> 0025 0026 #include <QTimer> 0027 #include <QIcon> 0028 0029 #include <klocalizedstring.h> 0030 0031 class Q_DECL_HIDDEN KDeviceListModel::Private 0032 { 0033 public: 0034 Private(KDeviceListModel *self) : q(self), rootItem(new KDeviceListItem()) {} 0035 ~Private() 0036 { 0037 delete rootItem; 0038 } 0039 0040 KDeviceListModel *q; 0041 0042 KDeviceListItem *rootItem; 0043 QMap<QString, KDeviceListItem *> deviceItems; 0044 Solid::Predicate predicate; 0045 0046 void initialize(const Solid::Predicate &p); 0047 QModelIndex indexForItem(KDeviceListItem *item) const; 0048 void addDevice(const Solid::Device &device); 0049 void removeBranch(const QString &udi); 0050 0051 // Private slots 0052 void _k_initDeviceList(); 0053 void _k_deviceAdded(const QString &udi); 0054 void _k_deviceRemoved(const QString &udi); 0055 }; 0056 0057 KDeviceListModel::KDeviceListModel(QObject *parent) 0058 : QAbstractItemModel(parent), d(new Private(this)) 0059 { 0060 d->deviceItems[QString()] = d->rootItem; 0061 d->initialize(Solid::Predicate()); 0062 } 0063 0064 KDeviceListModel::KDeviceListModel(const QString &predicate, QObject *parent) 0065 : QAbstractItemModel(parent), d(new Private(this)) 0066 { 0067 d->initialize(Solid::Predicate::fromString(predicate)); 0068 } 0069 0070 KDeviceListModel::KDeviceListModel(const Solid::Predicate &predicate, QObject *parent) 0071 : QAbstractItemModel(parent), d(new Private(this)) 0072 { 0073 d->initialize(predicate); 0074 } 0075 0076 KDeviceListModel::~KDeviceListModel() 0077 { 0078 delete d; 0079 } 0080 0081 void KDeviceListModel::Private::initialize(const Solid::Predicate &p) 0082 { 0083 predicate = p; 0084 0085 // Delay load of hardware list when the event loop start 0086 QTimer::singleShot(0, q, SLOT(_k_initDeviceList())); 0087 } 0088 0089 QVariant KDeviceListModel::data(const QModelIndex &index, int role) const 0090 { 0091 if (!index.isValid()) { 0092 return QVariant(); 0093 } 0094 0095 KDeviceListItem *deviceItem = static_cast<KDeviceListItem *>(index.internalPointer()); 0096 Solid::Device device = deviceItem->device(); 0097 0098 QVariant returnData; 0099 if (role == Qt::DisplayRole) { 0100 returnData = device.product(); 0101 } 0102 // Only display icons in the first column 0103 else if (role == Qt::DecorationRole && index.column() == 0) { 0104 returnData = QIcon::fromTheme(device.icon()); 0105 } 0106 0107 return returnData; 0108 } 0109 0110 QVariant KDeviceListModel::headerData(int section, Qt::Orientation orientation, int role) const 0111 { 0112 Q_UNUSED(section) 0113 0114 if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { 0115 return i18n("Device name"); 0116 } 0117 0118 return QVariant(); 0119 } 0120 0121 QModelIndex KDeviceListModel::index(int row, int column, const QModelIndex &parent) const 0122 { 0123 if (row < 0 || column != 0) { 0124 return QModelIndex(); 0125 } 0126 0127 KDeviceListItem *parentItem; 0128 if (parent.isValid()) { 0129 parentItem = static_cast<KDeviceListItem *>(parent.internalPointer()); 0130 } else { 0131 parentItem = d->rootItem; 0132 } 0133 0134 KDeviceListItem *childItem = parentItem->child(row); 0135 0136 if (childItem) { 0137 return createIndex(row, column, childItem); 0138 } else { 0139 return QModelIndex(); 0140 } 0141 } 0142 0143 QModelIndex KDeviceListModel::rootIndex() const 0144 { 0145 return d->indexForItem(d->rootItem); 0146 } 0147 0148 QModelIndex KDeviceListModel::parent(const QModelIndex &child) const 0149 { 0150 if (!child.isValid()) { 0151 return QModelIndex(); 0152 } 0153 0154 KDeviceListItem *childItem = static_cast<KDeviceListItem *>(child.internalPointer()); 0155 KDeviceListItem *parentItem = childItem->parent(); 0156 0157 if (!parentItem) { 0158 return QModelIndex(); 0159 } else { 0160 return d->indexForItem(parentItem); 0161 } 0162 } 0163 0164 int KDeviceListModel::rowCount(const QModelIndex &parent) const 0165 { 0166 if (!parent.isValid()) { 0167 return d->rootItem->childCount(); 0168 } 0169 0170 KDeviceListItem *item = static_cast<KDeviceListItem *>(parent.internalPointer()); 0171 0172 return item->childCount(); 0173 } 0174 0175 int KDeviceListModel::columnCount(const QModelIndex &parent) const 0176 { 0177 Q_UNUSED(parent); 0178 // We only know 1 information for a particualiar device. 0179 return 1; 0180 } 0181 0182 Solid::Device KDeviceListModel::deviceForIndex(const QModelIndex &index) const 0183 { 0184 KDeviceListItem *deviceItem = static_cast<KDeviceListItem *>(index.internalPointer()); 0185 return deviceItem->device(); 0186 } 0187 0188 void KDeviceListModel::Private::_k_initDeviceList() 0189 { 0190 Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance(); 0191 0192 connect(notifier, SIGNAL(deviceAdded(QString)), 0193 q, SLOT(_k_deviceAdded(QString))); 0194 connect(notifier, SIGNAL(deviceRemoved(QString)), 0195 q, SLOT(_k_deviceRemoved(QString))); 0196 0197 // Use allDevices() from the manager if the predicate is not valid 0198 // otherwise the returned list is empty 0199 const QList<Solid::Device> &deviceList = predicate.isValid() ? 0200 Solid::Device::listFromQuery(predicate) 0201 : Solid::Device::allDevices(); 0202 0203 foreach (const Solid::Device &device, deviceList) { 0204 addDevice(device); 0205 } 0206 0207 emit q->modelInitialized(); 0208 } 0209 0210 void KDeviceListModel::Private::addDevice(const Solid::Device &device) 0211 { 0212 // Don't insert invalid devices 0213 if (!device.isValid()) { 0214 return; 0215 } 0216 0217 // Don't insert devices that doesn't match the predicate set 0218 // (except for the root) 0219 if (!device.parentUdi().isEmpty() 0220 && predicate.isValid() && !predicate.matches(device)) { 0221 return; 0222 } 0223 0224 KDeviceListItem *item; 0225 if (deviceItems.contains(device.udi())) { // It was already inserted as a parent 0226 item = deviceItems[device.udi()]; 0227 } else { 0228 item = new KDeviceListItem(); 0229 deviceItems[device.udi()] = item; 0230 } 0231 item->setDevice(device); 0232 0233 KDeviceListItem *parent = rootItem; 0234 0235 if (!deviceItems.contains(device.parentUdi())) { // The parent was not present, try to insert it in the model 0236 addDevice(Solid::Device(device.parentUdi())); 0237 } 0238 0239 if (deviceItems.contains(device.parentUdi())) { // Update the parent if the device is now present 0240 parent = deviceItems[device.parentUdi()]; 0241 } 0242 0243 if (item->parent() != parent) { // If it's already our parent no need to signal the new row 0244 q->beginInsertRows(indexForItem(parent), parent->childCount(), parent->childCount()); 0245 item->setParent(parent); 0246 q->endInsertRows(); 0247 } 0248 } 0249 0250 void KDeviceListModel::Private::removeBranch(const QString &udi) 0251 { 0252 if (!deviceItems.contains(udi)) { 0253 return; 0254 } 0255 0256 KDeviceListItem *item = deviceItems[udi]; 0257 KDeviceListItem *parent = item->parent(); 0258 0259 QList<KDeviceListItem *> children = item->children(); 0260 0261 foreach (KDeviceListItem *child, children) { 0262 removeBranch(child->device().udi()); 0263 } 0264 0265 q->beginRemoveRows(indexForItem(parent), 0266 item->row(), item->row()); 0267 0268 item->setParent(nullptr); 0269 deviceItems.remove(udi); 0270 delete item; 0271 0272 q->endRemoveRows(); 0273 } 0274 0275 void KDeviceListModel::Private::_k_deviceAdded(const QString &udi) 0276 { 0277 Solid::Device device(udi); 0278 addDevice(device); 0279 } 0280 0281 void KDeviceListModel::Private::_k_deviceRemoved(const QString &udi) 0282 { 0283 removeBranch(udi); 0284 } 0285 0286 QModelIndex KDeviceListModel::Private::indexForItem(KDeviceListItem *item) const 0287 { 0288 if (item == rootItem) { 0289 return QModelIndex(); 0290 } else { 0291 return q->createIndex(item->row(), 0, item); 0292 } 0293 } 0294 0295 #include "moc_kdevicelistmodel.cpp"