1 /*
2 SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
3 SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
4
5 SPDX-License-Identifier: GPL-2.0-or-later
6 */
7
8 #include "computermodel.h"
9 #include "actionlist.h"
10 #include "simplefavoritesmodel.h"
11
12 #include <QIcon>
13
14 #include <KAuthorized>
15 #include <KConcatenateRowsProxyModel>
16 #include <KFilePlacesModel>
17 #include <KLocalizedString>
18 #include <KRun>
19 #include <Solid/Device>
20
21 #include "krunner_interface.h"
22
FilteredPlacesModel(QObject * parent)23 FilteredPlacesModel::FilteredPlacesModel(QObject *parent)
24 : QSortFilterProxyModel(parent)
25 , m_placesModel(new KFilePlacesModel(this))
26 {
27 setSourceModel(m_placesModel);
28 sort(0);
29 }
30
~FilteredPlacesModel()31 FilteredPlacesModel::~FilteredPlacesModel()
32 {
33 }
34
url(const QModelIndex & index) const35 QUrl FilteredPlacesModel::url(const QModelIndex &index) const
36 {
37 return KFilePlacesModel::convertedUrl(m_placesModel->url(mapToSource(index)));
38 }
39
isDevice(const QModelIndex & index) const40 bool FilteredPlacesModel::isDevice(const QModelIndex &index) const
41 {
42 return m_placesModel->isDevice(mapToSource(index));
43 }
44
deviceForIndex(const QModelIndex & index) const45 Solid::Device FilteredPlacesModel::deviceForIndex(const QModelIndex &index) const
46 {
47 return m_placesModel->deviceForIndex(mapToSource(index));
48 }
49
filterAcceptsRow(int sourceRow,const QModelIndex & sourceParent) const50 bool FilteredPlacesModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
51 {
52 const QModelIndex index = m_placesModel->index(sourceRow, 0, sourceParent);
53
54 return !m_placesModel->isHidden(index) && !m_placesModel->data(index, KFilePlacesModel::FixedDeviceRole).toBool();
55 }
56
lessThan(const QModelIndex & left,const QModelIndex & right) const57 bool FilteredPlacesModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
58 {
59 bool lDevice = m_placesModel->isDevice(left);
60 bool rDevice = m_placesModel->isDevice(right);
61
62 if (lDevice && !rDevice) {
63 return false;
64 } else if (!lDevice && rDevice) {
65 return true;
66 }
67
68 return (left.row() < right.row());
69 }
70
RunCommandModel(QObject * parent)71 RunCommandModel::RunCommandModel(QObject *parent)
72 : AbstractModel(parent)
73 {
74 }
75
~RunCommandModel()76 RunCommandModel::~RunCommandModel()
77 {
78 }
79
description() const80 QString RunCommandModel::description() const
81 {
82 return QString();
83 }
84
data(const QModelIndex & index,int role) const85 QVariant RunCommandModel::data(const QModelIndex &index, int role) const
86 {
87 if (!index.isValid()) {
88 return QVariant();
89 }
90
91 if (role == Qt::DisplayRole) {
92 return i18n("Show KRunner");
93 } else if (role == Qt::DecorationRole) {
94 return QIcon::fromTheme(QStringLiteral("plasma-search"));
95 } else if (role == Kicker::DescriptionRole) {
96 return i18n("Search, calculate, or run a command");
97 } else if (role == Kicker::GroupRole) {
98 return i18n("Applications");
99 }
100
101 return QVariant();
102 }
103
rowCount(const QModelIndex & parent) const104 int RunCommandModel::rowCount(const QModelIndex &parent) const
105 {
106 return parent.isValid() ? 0 : (KAuthorized::authorize(QStringLiteral("run_command")) ? 1 : 0);
107 }
108
trigger(int row,const QString & actionId,const QVariant & argument)109 Q_INVOKABLE bool RunCommandModel::trigger(int row, const QString &actionId, const QVariant &argument)
110 {
111 Q_UNUSED(actionId)
112 Q_UNUSED(argument)
113
114 if (row == 0 && KAuthorized::authorize(QStringLiteral("run_command"))) {
115 org::kde::krunner::App krunner(QStringLiteral("org.kde.krunner"), QStringLiteral("/App"), QDBusConnection::sessionBus());
116 krunner.display();
117
118 return true;
119 }
120
121 return false;
122 }
123
ComputerModel(QObject * parent)124 ComputerModel::ComputerModel(QObject *parent)
125 : ForwardingModel(parent)
126 , m_concatProxy(new KConcatenateRowsProxyModel(this))
127 , m_runCommandModel(new RunCommandModel(this))
128 , m_systemAppsModel(new SimpleFavoritesModel(this))
129 , m_filteredPlacesModel(new FilteredPlacesModel(this))
130 , m_appNameFormat(AppEntry::NameOnly)
131 , m_appletInterface(nullptr)
132 {
133 connect(m_systemAppsModel, &SimpleFavoritesModel::favoritesChanged, this, &ComputerModel::systemApplicationsChanged);
134 m_systemAppsModel->setFavorites(QStringList() << QStringLiteral("systemsettings.desktop"));
135
136 m_concatProxy->addSourceModel(m_runCommandModel);
137 m_concatProxy->addSourceModel(m_systemAppsModel);
138 m_concatProxy->addSourceModel(m_filteredPlacesModel);
139
140 setSourceModel(m_concatProxy);
141 }
142
~ComputerModel()143 ComputerModel::~ComputerModel()
144 {
145 }
146
description() const147 QString ComputerModel::description() const
148 {
149 return i18n("Computer");
150 }
151
appNameFormat() const152 int ComputerModel::appNameFormat() const
153 {
154 return m_appNameFormat;
155 }
156
setAppNameFormat(int format)157 void ComputerModel::setAppNameFormat(int format)
158 {
159 if (m_appNameFormat != (AppEntry::NameFormat)format) {
160 m_appNameFormat = (AppEntry::NameFormat)format;
161
162 m_systemAppsModel->refresh();
163
164 emit appNameFormatChanged();
165 }
166 }
167
appletInterface() const168 QObject *ComputerModel::appletInterface() const
169 {
170 return m_appletInterface;
171 }
172
setAppletInterface(QObject * appletInterface)173 void ComputerModel::setAppletInterface(QObject *appletInterface)
174 {
175 if (m_appletInterface != appletInterface) {
176 m_appletInterface = appletInterface;
177
178 emit appletInterfaceChanged();
179 }
180 }
181
systemApplications() const182 QStringList ComputerModel::systemApplications() const
183 {
184 return m_systemAppsModel->favorites();
185 }
186
setSystemApplications(const QStringList & apps)187 void ComputerModel::setSystemApplications(const QStringList &apps)
188 {
189 m_systemAppsModel->setFavorites(apps);
190 }
191
data(const QModelIndex & index,int role) const192 QVariant ComputerModel::data(const QModelIndex &index, int role) const
193 {
194 if (!index.isValid()) {
195 return QVariant();
196 }
197
198 const QModelIndex sourceIndex = m_concatProxy->mapToSource(m_concatProxy->index(index.row(), index.column()));
199
200 bool isPlace = (sourceIndex.model() == m_filteredPlacesModel);
201
202 if (isPlace) {
203 if (role == Kicker::DescriptionRole) {
204 if (m_filteredPlacesModel->isDevice(sourceIndex)) {
205 Solid::Device device = m_filteredPlacesModel->deviceForIndex(sourceIndex);
206 Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
207
208 if (access) {
209 return access->filePath();
210 } else {
211 return QString();
212 }
213 }
214 } else if (role == Kicker::FavoriteIdRole) {
215 if (!m_filteredPlacesModel->isDevice(sourceIndex)) {
216 return m_filteredPlacesModel->url(sourceIndex);
217 }
218 } else if (role == Kicker::UrlRole) {
219 return m_filteredPlacesModel->url(sourceIndex);
220 } else if (role == Kicker::GroupRole) {
221 return sourceIndex.data(KFilePlacesModel::GroupRole).toString();
222 } else if (role == Qt::DisplayRole || role == Qt::DecorationRole) {
223 return sourceIndex.data(role);
224 }
225 } else if (role == Kicker::GroupRole) {
226 return i18n("Applications");
227 } else {
228 return sourceIndex.data(role);
229 }
230
231 return QVariant();
232 }
233
trigger(int row,const QString & actionId,const QVariant & argument)234 bool ComputerModel::trigger(int row, const QString &actionId, const QVariant &argument)
235 {
236 const QModelIndex sourceIndex = m_concatProxy->mapToSource(m_concatProxy->index(row, 0));
237
238 if (sourceIndex.model() == m_filteredPlacesModel) {
239 const QUrl &url = m_filteredPlacesModel->url(sourceIndex);
240
241 if (url.isValid()) {
242 new KRun(url, nullptr);
243
244 return true;
245 }
246
247 Solid::Device device = m_filteredPlacesModel->deviceForIndex(sourceIndex);
248 Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
249
250 if (access && !access->isAccessible()) {
251 connect(access, &Solid::StorageAccess::setupDone, this, &ComputerModel::onSetupDone);
252 access->setup();
253
254 return true;
255 }
256 } else {
257 AbstractModel *model = nullptr;
258
259 if (sourceIndex.model() == m_systemAppsModel) {
260 model = m_systemAppsModel;
261 } else {
262 model = m_runCommandModel;
263 }
264
265 return model->trigger(sourceIndex.row(), actionId, argument);
266 }
267
268 return false;
269 }
270
onSetupDone(Solid::ErrorType error,QVariant errorData,const QString & udi)271 void ComputerModel::onSetupDone(Solid::ErrorType error, QVariant errorData, const QString &udi)
272 {
273 Q_UNUSED(errorData);
274
275 if (error != Solid::NoError) {
276 return;
277 }
278
279 Solid::Device device(udi);
280 Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
281
282 Q_ASSERT(access);
283
284 new KRun(QUrl::fromLocalFile(access->filePath()), nullptr);
285 }
286