1 /*
2     SPDX-FileCopyrightText: 2020 Harald Sitter <sitter@kde.org>
3     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
4 */
5 
6 #include "smbmountmodel.h"
7 
8 #include <QDebug>
9 #include <QIcon>
10 #include <QMetaEnum>
11 #include <Solid/DeviceInterface>
12 #include <Solid/DeviceNotifier>
13 #include <Solid/NetworkShare>
14 #include <Solid/StorageAccess>
15 
SmbMountModel(QObject * parent)16 SmbMountModel::SmbMountModel(QObject *parent)
17     : QAbstractListModel(parent)
18 {
19     connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceAdded, this, &SmbMountModel::addDevice);
20     connect(Solid::DeviceNotifier::instance(), &Solid::DeviceNotifier::deviceRemoved, this, &SmbMountModel::removeDevice);
21     metaObject()->invokeMethod(this, &SmbMountModel::reloadData);
22 }
23 
24 SmbMountModel::~SmbMountModel() = default;
25 
rowCount(const QModelIndex & parent) const26 int SmbMountModel::rowCount(const QModelIndex &parent) const
27 {
28     Q_UNUSED(parent)
29     return m_devices.size();
30 }
31 
data(const QModelIndex & index,int intRole) const32 QVariant SmbMountModel::data(const QModelIndex &index, int intRole) const
33 {
34     if (!index.isValid()) {
35         return {};
36     }
37 
38     Q_ASSERT(index.row() < m_devices.count());
39 
40     static QMetaEnum roleEnum = QMetaEnum::fromType<Role>();
41     if (roleEnum.valueToKey(intRole) == nullptr) {
42         return {};
43     }
44     const auto role = static_cast<Role>(intRole);
45 
46     const Solid::Device &device = m_devices.at(index.row());
47     switch (role) {
48     case Role::Share:
49         return device.as<Solid::NetworkShare>()->url();
50     case Role::Path:
51         return device.as<Solid::StorageAccess>()->filePath();
52     case Role::Accessible:
53         return device.as<Solid::StorageAccess>()->isAccessible();
54     }
55 
56     return {};
57 }
58 
addDevice(const QString & udi)59 void SmbMountModel::addDevice(const QString &udi)
60 {
61     auto it = deviceForUdi(udi);
62     if (it != m_devices.constEnd()) {
63         return; // already in the list
64     }
65 
66     Solid::Device device(udi);
67     if (!device.is<Solid::NetworkShare>()) {
68         return;
69     }
70 
71     beginInsertRows(QModelIndex(), m_devices.count(), m_devices.count());
72     m_devices.append(device);
73     endInsertRows();
74 }
75 
removeDevice(const QString & udi)76 void SmbMountModel::removeDevice(const QString &udi)
77 {
78     auto it = deviceForUdi(udi);
79     if (it == m_devices.constEnd()) {
80         return; // untracked udi
81     }
82 
83     const int index = static_cast<int>(std::distance(m_devices.constBegin(), it));
84     beginRemoveRows(QModelIndex(), index, index);
85     m_devices.removeAt(index);
86     endRemoveRows();
87 }
88 
reloadData()89 void SmbMountModel::reloadData()
90 {
91     beginResetModel();
92     m_devices.clear();
93     const auto devices = Solid::Device::listFromType(Solid::DeviceInterface::NetworkShare);
94     for (auto it = devices.begin(); it != devices.end(); ++it) {
95         if (!it->is<Solid::NetworkShare>()) {
96             // Workaround in case listFromType still gives incorrect types.
97             // https://bugs.kde.org/show_bug.cgi?id=419220
98             continue;
99         }
100         switch (it->as<Solid::NetworkShare>()->type()) {
101         case Solid::NetworkShare::Cifs:
102             m_devices.append(*it);
103             continue;
104         case Solid::NetworkShare::Nfs:
105         case Solid::NetworkShare::Unknown:
106             continue;
107         }
108     }
109     endResetModel();
110 }
111 
hasChildren(const QModelIndex & parent) const112 bool SmbMountModel::hasChildren(const QModelIndex &parent) const
113 {
114     return !parent.isValid() ? false : (rowCount(parent) > 0);
115 }
116 
roleNames() const117 QHash<int, QByteArray> SmbMountModel::roleNames() const
118 {
119     static QHash<int, QByteArray> roles;
120     if (!roles.isEmpty()) {
121         return roles;
122     }
123 
124     const QMetaEnum roleEnum = QMetaEnum::fromType<Role>();
125     for (int i = 0; i < roleEnum.keyCount(); ++i) {
126         const int value = roleEnum.value(i);
127         Q_ASSERT(value != -1);
128         roles[static_cast<int>(value)] = QByteArray("ROLE_") + roleEnum.valueToKey(value);
129     }
130     return roles;
131 }
132