File indexing completed on 2024-12-22 05:15:19

0001 /*
0002     SPDX-FileCopyrightText: 2007 Kevin Ottens <ervin@kde.org>
0003     SPDX-FileCopyrightText: 2015 Eike Hein <hein@kde.org>
0004 
0005     SPDX-License-Identifier: GPL-2.0-or-later
0006 */
0007 
0008 #include "computermodel.h"
0009 #include "actionlist.h"
0010 #include "simplefavoritesmodel.h"
0011 
0012 #include <QConcatenateTablesProxyModel>
0013 
0014 #include <KAuthorized>
0015 #include <KFilePlacesModel>
0016 #include <KIO/OpenUrlJob>
0017 #include <KLocalizedString>
0018 #include <Solid/Device>
0019 
0020 #include "krunner_interface.h"
0021 
0022 FilteredPlacesModel::FilteredPlacesModel(QObject *parent)
0023     : QSortFilterProxyModel(parent)
0024     , m_placesModel(new KFilePlacesModel(this))
0025 {
0026     setSourceModel(m_placesModel);
0027     sort(0);
0028 }
0029 
0030 FilteredPlacesModel::~FilteredPlacesModel()
0031 {
0032 }
0033 
0034 QUrl FilteredPlacesModel::url(const QModelIndex &index) const
0035 {
0036     return KFilePlacesModel::convertedUrl(m_placesModel->url(mapToSource(index)));
0037 }
0038 
0039 bool FilteredPlacesModel::isDevice(const QModelIndex &index) const
0040 {
0041     return m_placesModel->isDevice(mapToSource(index));
0042 }
0043 
0044 Solid::Device FilteredPlacesModel::deviceForIndex(const QModelIndex &index) const
0045 {
0046     return m_placesModel->deviceForIndex(mapToSource(index));
0047 }
0048 
0049 bool FilteredPlacesModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
0050 {
0051     const QModelIndex index = m_placesModel->index(sourceRow, 0, sourceParent);
0052 
0053     return !m_placesModel->isHidden(index) && !m_placesModel->data(index, KFilePlacesModel::FixedDeviceRole).toBool();
0054 }
0055 
0056 bool FilteredPlacesModel::lessThan(const QModelIndex &left, const QModelIndex &right) const
0057 {
0058     bool lDevice = m_placesModel->isDevice(left);
0059     bool rDevice = m_placesModel->isDevice(right);
0060 
0061     if (lDevice && !rDevice) {
0062         return false;
0063     } else if (!lDevice && rDevice) {
0064         return true;
0065     }
0066 
0067     return (left.row() < right.row());
0068 }
0069 
0070 RunCommandModel::RunCommandModel(QObject *parent)
0071     : AbstractModel(parent)
0072 {
0073 }
0074 
0075 RunCommandModel::~RunCommandModel()
0076 {
0077 }
0078 
0079 QString RunCommandModel::description() const
0080 {
0081     return QString();
0082 }
0083 
0084 QVariant RunCommandModel::data(const QModelIndex &index, int role) const
0085 {
0086     if (!index.isValid()) {
0087         return QVariant();
0088     }
0089 
0090     if (role == Qt::DisplayRole) {
0091         return i18n("Show KRunner");
0092     } else if (role == Qt::DecorationRole) {
0093         return QStringLiteral("plasma-search");
0094     } else if (role == Kicker::DescriptionRole) {
0095         return i18n("Search, calculate, or run a command");
0096     } else if (role == Kicker::GroupRole) {
0097         return i18n("Applications");
0098     }
0099 
0100     return QVariant();
0101 }
0102 
0103 int RunCommandModel::rowCount(const QModelIndex &parent) const
0104 {
0105     return parent.isValid() ? 0 : (KAuthorized::authorize(QStringLiteral("run_command")) ? 1 : 0);
0106 }
0107 
0108 Q_INVOKABLE bool RunCommandModel::trigger(int row, const QString &actionId, const QVariant &argument)
0109 {
0110     Q_UNUSED(actionId)
0111     Q_UNUSED(argument)
0112 
0113     if (row == 0 && KAuthorized::authorize(QStringLiteral("run_command"))) {
0114         org::kde::krunner::App krunner(QStringLiteral("org.kde.krunner"), QStringLiteral("/App"), QDBusConnection::sessionBus());
0115         krunner.display();
0116 
0117         return true;
0118     }
0119 
0120     return false;
0121 }
0122 
0123 ComputerModel::ComputerModel(QObject *parent)
0124     : ForwardingModel(parent)
0125     , m_concatProxy(new QConcatenateTablesProxyModel(this))
0126     , m_runCommandModel(new RunCommandModel(this))
0127     , m_systemAppsModel(new SimpleFavoritesModel(this))
0128     , m_filteredPlacesModel(new FilteredPlacesModel(this))
0129     , m_appNameFormat(AppEntry::NameOnly)
0130     , m_appletInterface(nullptr)
0131 {
0132     connect(m_systemAppsModel, &SimpleFavoritesModel::favoritesChanged, this, &ComputerModel::systemApplicationsChanged);
0133     m_systemAppsModel->setFavorites(QStringList() << QStringLiteral("systemsettings.desktop"));
0134 
0135     m_concatProxy->addSourceModel(m_runCommandModel);
0136     m_concatProxy->addSourceModel(m_systemAppsModel);
0137     m_concatProxy->addSourceModel(m_filteredPlacesModel);
0138 
0139     setSourceModel(m_concatProxy);
0140 }
0141 
0142 ComputerModel::~ComputerModel()
0143 {
0144 }
0145 
0146 QString ComputerModel::description() const
0147 {
0148     return i18n("Computer");
0149 }
0150 
0151 int ComputerModel::appNameFormat() const
0152 {
0153     return m_appNameFormat;
0154 }
0155 
0156 void ComputerModel::setAppNameFormat(int format)
0157 {
0158     if (m_appNameFormat != (AppEntry::NameFormat)format) {
0159         m_appNameFormat = (AppEntry::NameFormat)format;
0160 
0161         m_systemAppsModel->refresh();
0162 
0163         Q_EMIT appNameFormatChanged();
0164     }
0165 }
0166 
0167 QObject *ComputerModel::appletInterface() const
0168 {
0169     return m_appletInterface;
0170 }
0171 
0172 void ComputerModel::setAppletInterface(QObject *appletInterface)
0173 {
0174     if (m_appletInterface != appletInterface) {
0175         m_appletInterface = appletInterface;
0176 
0177         Q_EMIT appletInterfaceChanged();
0178     }
0179 }
0180 
0181 QStringList ComputerModel::systemApplications() const
0182 {
0183     return m_systemAppsModel->favorites();
0184 }
0185 
0186 void ComputerModel::setSystemApplications(const QStringList &apps)
0187 {
0188     m_systemAppsModel->setFavorites(apps);
0189 }
0190 
0191 QVariant ComputerModel::data(const QModelIndex &index, int role) const
0192 {
0193     if (!index.isValid()) {
0194         return QVariant();
0195     }
0196 
0197     const QModelIndex sourceIndex = m_concatProxy->mapToSource(m_concatProxy->index(index.row(), index.column()));
0198 
0199     bool isPlace = (sourceIndex.model() == m_filteredPlacesModel);
0200 
0201     if (isPlace) {
0202         if (role == Kicker::DescriptionRole) {
0203             if (m_filteredPlacesModel->isDevice(sourceIndex)) {
0204                 Solid::Device device = m_filteredPlacesModel->deviceForIndex(sourceIndex);
0205                 Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
0206 
0207                 if (access) {
0208                     return access->filePath();
0209                 } else {
0210                     return QString();
0211                 }
0212             }
0213         } else if (role == Kicker::FavoriteIdRole) {
0214             if (!m_filteredPlacesModel->isDevice(sourceIndex)) {
0215                 return m_filteredPlacesModel->url(sourceIndex);
0216             }
0217         } else if (role == Kicker::UrlRole) {
0218             return m_filteredPlacesModel->url(sourceIndex);
0219         } else if (role == Kicker::GroupRole) {
0220             return sourceIndex.data(KFilePlacesModel::GroupRole).toString();
0221         } else if (role == Qt::DisplayRole || role == Qt::DecorationRole) {
0222             return sourceIndex.data(role);
0223         }
0224     } else if (role == Kicker::GroupRole) {
0225         return i18n("Applications");
0226     } else {
0227         return sourceIndex.data(role);
0228     }
0229 
0230     return QVariant();
0231 }
0232 
0233 bool ComputerModel::trigger(int row, const QString &actionId, const QVariant &argument)
0234 {
0235     const QModelIndex sourceIndex = m_concatProxy->mapToSource(m_concatProxy->index(row, 0));
0236 
0237     if (sourceIndex.model() == m_filteredPlacesModel) {
0238         const QUrl &url = m_filteredPlacesModel->url(sourceIndex);
0239 
0240         if (url.isValid()) {
0241             auto job = new KIO::OpenUrlJob(url);
0242             job->start();
0243 
0244             return true;
0245         }
0246 
0247         Solid::Device device = m_filteredPlacesModel->deviceForIndex(sourceIndex);
0248         Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
0249 
0250         if (access && !access->isAccessible()) {
0251             connect(access, &Solid::StorageAccess::setupDone, this, &ComputerModel::onSetupDone);
0252             access->setup();
0253 
0254             return true;
0255         }
0256     } else {
0257         AbstractModel *model = nullptr;
0258 
0259         if (sourceIndex.model() == m_systemAppsModel) {
0260             model = m_systemAppsModel;
0261         } else {
0262             model = m_runCommandModel;
0263         }
0264 
0265         return model->trigger(sourceIndex.row(), actionId, argument);
0266     }
0267 
0268     return false;
0269 }
0270 
0271 void ComputerModel::onSetupDone(Solid::ErrorType error, QVariant errorData, const QString &udi)
0272 {
0273     Q_UNUSED(errorData);
0274 
0275     if (error != Solid::NoError) {
0276         return;
0277     }
0278 
0279     Solid::Device device(udi);
0280     Solid::StorageAccess *access = device.as<Solid::StorageAccess>();
0281 
0282     Q_ASSERT(access);
0283 
0284     auto job = new KIO::OpenUrlJob(QUrl::fromLocalFile(access->filePath()));
0285     job->start();
0286 }