KDELibs4Support

kdevicelistmodel.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2006 Michael Larouche <[email protected]>
3  2007 Kevin Ottens <[email protected]>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License version 2 as published by the Free Software Foundation.
8 
9  This library is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this library; see the file COPYING.LIB. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  Boston, MA 02110-1301, USA.
18 
19 */
20 #include "kdevicelistmodel.h"
21 #include "kdevicelistitem_p.h"
22 
23 #include <solid/devicenotifier.h>
24 #include <solid/device.h>
25 #include <solid/deviceinterface.h>
26 
27 #include <QTimer>
28 #include <QIcon>
29 
30 #include <klocalizedstring.h>
31 
32 class Q_DECL_HIDDEN KDeviceListModel::Private
33 {
34 public:
35  Private(KDeviceListModel *self) : q(self), rootItem(new KDeviceListItem()) {}
36  ~Private()
37  {
38  delete rootItem;
39  }
40 
42 
43  KDeviceListItem *rootItem;
45  Solid::Predicate predicate;
46 
47  void initialize(const Solid::Predicate &p);
48  QModelIndex indexForItem(KDeviceListItem *item) const;
49  void addDevice(const Solid::Device &device);
50  void removeBranch(const QString &udi);
51 
52  // Private slots
53  void _k_initDeviceList();
54  void _k_deviceAdded(const QString &udi);
55  void _k_deviceRemoved(const QString &udi);
56 };
57 
58 KDeviceListModel::KDeviceListModel(QObject *parent)
59  : QAbstractItemModel(parent), d(new Private(this))
60 {
61  d->deviceItems[QString()] = d->rootItem;
62  d->initialize(Solid::Predicate());
63 }
64 
65 KDeviceListModel::KDeviceListModel(const QString &predicate, QObject *parent)
66  : QAbstractItemModel(parent), d(new Private(this))
67 {
68  d->initialize(Solid::Predicate::fromString(predicate));
69 }
70 
71 KDeviceListModel::KDeviceListModel(const Solid::Predicate &predicate, QObject *parent)
72  : QAbstractItemModel(parent), d(new Private(this))
73 {
74  d->initialize(predicate);
75 }
76 
77 KDeviceListModel::~KDeviceListModel()
78 {
79  delete d;
80 }
81 
82 void KDeviceListModel::Private::initialize(const Solid::Predicate &p)
83 {
84  predicate = p;
85 
86  // Delay load of hardware list when the event loop start
87  QTimer::singleShot(0, q, SLOT(_k_initDeviceList()));
88 }
89 
91 {
92  if (!index.isValid()) {
93  return QVariant();
94  }
95 
96  KDeviceListItem *deviceItem = static_cast<KDeviceListItem *>(index.internalPointer());
97  Solid::Device device = deviceItem->device();
98 
99  QVariant returnData;
100  if (role == Qt::DisplayRole) {
101  returnData = device.product();
102  }
103  // Only display icons in the first column
104  else if (role == Qt::DecorationRole && index.column() == 0) {
105  returnData = QIcon::fromTheme(device.icon());
106  }
107 
108  return returnData;
109 }
110 
111 QVariant KDeviceListModel::headerData(int section, Qt::Orientation orientation, int role) const
112 {
113  Q_UNUSED(section)
114 
115  if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
116  return i18n("Device name");
117  }
118 
119  return QVariant();
120 }
121 
122 QModelIndex KDeviceListModel::index(int row, int column, const QModelIndex &parent) const
123 {
124  if (row < 0 || column != 0) {
125  return QModelIndex();
126  }
127 
128  KDeviceListItem *parentItem;
129  if (parent.isValid()) {
130  parentItem = static_cast<KDeviceListItem *>(parent.internalPointer());
131  } else {
132  parentItem = d->rootItem;
133  }
134 
135  KDeviceListItem *childItem = parentItem->child(row);
136 
137  if (childItem) {
138  return createIndex(row, column, childItem);
139  } else {
140  return QModelIndex();
141  }
142 }
143 
144 QModelIndex KDeviceListModel::rootIndex() const
145 {
146  return d->indexForItem(d->rootItem);
147 }
148 
150 {
151  if (!child.isValid()) {
152  return QModelIndex();
153  }
154 
155  KDeviceListItem *childItem = static_cast<KDeviceListItem *>(child.internalPointer());
156  KDeviceListItem *parentItem = childItem->parent();
157 
158  if (!parentItem) {
159  return QModelIndex();
160  } else {
161  return d->indexForItem(parentItem);
162  }
163 }
164 
165 int KDeviceListModel::rowCount(const QModelIndex &parent) const
166 {
167  if (!parent.isValid()) {
168  return d->rootItem->childCount();
169  }
170 
171  KDeviceListItem *item = static_cast<KDeviceListItem *>(parent.internalPointer());
172 
173  return item->childCount();
174 }
175 
177 {
178  Q_UNUSED(parent);
179  // We only know 1 information for a particualiar device.
180  return 1;
181 }
182 
183 Solid::Device KDeviceListModel::deviceForIndex(const QModelIndex &index) const
184 {
185  KDeviceListItem *deviceItem = static_cast<KDeviceListItem *>(index.internalPointer());
186  return deviceItem->device();
187 }
188 
189 void KDeviceListModel::Private::_k_initDeviceList()
190 {
191  Solid::DeviceNotifier *notifier = Solid::DeviceNotifier::instance();
192 
193  connect(notifier, SIGNAL(deviceAdded(QString)),
194  q, SLOT(_k_deviceAdded(QString)));
195  connect(notifier, SIGNAL(deviceRemoved(QString)),
196  q, SLOT(_k_deviceRemoved(QString)));
197 
198  // Use allDevices() from the manager if the predicate is not valid
199  // otherwise the returned list is empty
200  const QList<Solid::Device> &deviceList = predicate.isValid() ?
203 
204  foreach (const Solid::Device &device, deviceList) {
205  addDevice(device);
206  }
207 
208  emit q->modelInitialized();
209 }
210 
211 void KDeviceListModel::Private::addDevice(const Solid::Device &device)
212 {
213  // Don't insert invalid devices
214  if (!device.isValid()) {
215  return;
216  }
217 
218  // Don't insert devices that doesn't match the predicate set
219  // (except for the root)
220  if (!device.parentUdi().isEmpty()
221  && predicate.isValid() && !predicate.matches(device)) {
222  return;
223  }
224 
225  KDeviceListItem *item;
226  if (deviceItems.contains(device.udi())) { // It was already inserted as a parent
227  item = deviceItems[device.udi()];
228  } else {
229  item = new KDeviceListItem();
230  deviceItems[device.udi()] = item;
231  }
232  item->setDevice(device);
233 
234  KDeviceListItem *parent = rootItem;
235 
236  if (!deviceItems.contains(device.parentUdi())) { // The parent was not present, try to insert it in the model
237  addDevice(Solid::Device(device.parentUdi()));
238  }
239 
240  if (deviceItems.contains(device.parentUdi())) { // Update the parent if the device is now present
241  parent = deviceItems[device.parentUdi()];
242  }
243 
244  if (item->parent() != parent) { // If it's already our parent no need to signal the new row
245  q->beginInsertRows(indexForItem(parent), parent->childCount(), parent->childCount());
246  item->setParent(parent);
247  q->endInsertRows();
248  }
249 }
250 
251 void KDeviceListModel::Private::removeBranch(const QString &udi)
252 {
253  if (!deviceItems.contains(udi)) {
254  return;
255  }
256 
257  KDeviceListItem *item = deviceItems[udi];
258  KDeviceListItem *parent = item->parent();
259 
260  QList<KDeviceListItem *> children = item->children();
261 
262  foreach (KDeviceListItem *child, children) {
263  removeBranch(child->device().udi());
264  }
265 
266  q->beginRemoveRows(indexForItem(parent),
267  item->row(), item->row());
268 
269  item->setParent(nullptr);
270  deviceItems.remove(udi);
271  delete item;
272 
273  q->endRemoveRows();
274 }
275 
276 void KDeviceListModel::Private::_k_deviceAdded(const QString &udi)
277 {
278  Solid::Device device(udi);
279  addDevice(device);
280 }
281 
282 void KDeviceListModel::Private::_k_deviceRemoved(const QString &udi)
283 {
284  removeBranch(udi);
285 }
286 
287 QModelIndex KDeviceListModel::Private::indexForItem(KDeviceListItem *item) const
288 {
289  if (item == rootItem) {
290  return QModelIndex();
291  } else {
292  return q->createIndex(item->row(), 0, item);
293  }
294 }
295 
296 #include "moc_kdevicelistmodel.cpp"
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const override
Get the header data for a given section, orientation and role.
const QObjectList & children() const const
KCRASH_EXPORT void initialize()
bool matches(const Device &device) const
bool isValid() const const
static QList< Device > listFromQuery(const Predicate &predicate, const QString &parentUdi=QString())
DisplayRole
bool isEmpty() const const
static Predicate fromString(const QString &predicate)
void * internalPointer() const const
bool isValid() const
QString udi() const
int rowCount(const QModelIndex &parent=QModelIndex()) const override
Get the number of rows for a model index.
QModelIndex createIndex(int row, int column, void *ptr) const const
bool isValid() const
QString icon() const
QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const override
Get the children model index for the given row and column.
QString i18n(const char *text, const TYPE &arg...)
Device list model in Qt&#39;s Interview framework.
static QList< Device > allDevices()
int columnCount(const QModelIndex &parent=QModelIndex()) const override
Get the number of columns for a model index.
int column() const const
QIcon fromTheme(const QString &name)
Orientation
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
QVariant data(const QModelIndex &index, int role) const override
Get a visible data based on Qt role for the given index.
QString product() const
QString parentUdi() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Sat Jul 4 2020 22:58:57 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.