File indexing completed on 2024-05-12 05:35:38
0001 /* 0002 SPDX-FileCopyrightText: 2022 Méven Car <meven@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "applicationmodel.h" 0008 0009 #include <KApplicationTrader> 0010 #include <KLocalizedString> 0011 #include <KService> 0012 0013 #include <optional> 0014 0015 #include "componentchooser.h" 0016 0017 ApplicationModel::ApplicationModel(QObject *parent) 0018 : QAbstractItemModel(parent) 0019 { 0020 } 0021 0022 void ApplicationModel::addApplication(const QString &name, const QString &iconName, const QString &storageId, bool isSelected, const QString &execLine) 0023 { 0024 QVariantMap application; 0025 application[QStringLiteral("name")] = name; 0026 application[QStringLiteral("icon")] = iconName; 0027 application[QStringLiteral("storageId")] = storageId; 0028 application[QStringLiteral("isSelected")] = isSelected; 0029 application[QStringLiteral("execLine")] = execLine; 0030 m_applications += application; 0031 } 0032 0033 void ApplicationModel::load(const QString &mimeType, 0034 const QString &applicationCategory, 0035 const QString &defaultApplication, 0036 const KService::Ptr preferredService) 0037 { 0038 beginResetModel(); 0039 0040 m_applications.clear(); 0041 0042 if (preferredService) { 0043 addApplication(preferredService->name(), preferredService->icon(), preferredService->storageId(), true, preferredService->exec()); 0044 if (preferredService->storageId() == defaultApplication) { 0045 m_defaultIndex = 0; 0046 } 0047 } 0048 0049 KApplicationTrader::query([preferredService, applicationCategory, mimeType, defaultApplication, this](const KService::Ptr &service) { 0050 if (service->exec().isEmpty() || (!applicationCategory.isEmpty() && !service->categories().contains(applicationCategory)) 0051 || (!mimeType.isEmpty() && !ComponentChooser::serviceSupportsMimeType(service, mimeType)) 0052 || (preferredService && preferredService->storageId() == service->storageId())) { 0053 return false; 0054 } 0055 0056 const auto icon = service->icon().isEmpty() ? QStringLiteral("application-x-shellscript") : service->icon(); 0057 bool isDefault = service->storageId() == defaultApplication; 0058 0059 addApplication(service->name(), icon, service->storageId(), false, service->exec()); 0060 0061 if (isDefault) { 0062 m_defaultIndex = m_applications.length() - 1; 0063 } 0064 return false; 0065 }); 0066 0067 addApplication(i18n("Other…"), QStringLiteral("application-x-shellscript"), QString(), false, QString()); 0068 0069 endResetModel(); 0070 } 0071 0072 int ApplicationModel::currentIndex() const 0073 { 0074 int index = 0; 0075 for (const auto &application : std::as_const(m_applications)) { 0076 if (application["isSelected"].toBool()) { 0077 return index; 0078 } 0079 ++index; 0080 } 0081 0082 if (m_defaultIndex != -1) { 0083 return m_defaultIndex; 0084 } 0085 0086 return 0; 0087 } 0088 0089 std::optional<int> ApplicationModel::defaultIndex() const 0090 { 0091 if (m_defaultIndex == -1) 0092 return {}; 0093 else { 0094 return m_defaultIndex; 0095 } 0096 } 0097 0098 int ApplicationModel::addApplicationBeforeLast(const KServicePtr service) 0099 { 0100 // the application will grow by 1, we want to add the new application at the before 0101 // last position taking into account the future new size of m_applications 0102 int newRowIndex = rowCount() - 1; 0103 beginInsertRows(QModelIndex(), newRowIndex, newRowIndex); 0104 0105 addApplication(service->name(), service->icon(), service->storageId(), false, service->exec()); 0106 // addApplication adds at the end of of the list 0107 // swaps the last and before last applications 0108 m_applications.swapItemsAt(rowCount() - 2, rowCount() - 1); 0109 0110 endInsertRows(); 0111 0112 return newRowIndex; 0113 } 0114 0115 QVariant ApplicationModel::headerData(int section, Qt::Orientation orientation, int role) const 0116 { 0117 Q_UNUSED(section) 0118 Q_UNUSED(orientation) 0119 Q_UNUSED(role) 0120 0121 return QVariant(); 0122 } 0123 0124 QModelIndex ApplicationModel::index(int row, int column, const QModelIndex &parent) const 0125 { 0126 Q_UNUSED(parent) 0127 0128 if (row >= 0 && row < m_applications.length()) { 0129 return createIndex(row, column); 0130 } 0131 return QModelIndex(); 0132 } 0133 0134 QModelIndex ApplicationModel::parent(const QModelIndex &index) const 0135 { 0136 Q_UNUSED(index) 0137 return QModelIndex(); 0138 } 0139 0140 int ApplicationModel::rowCount(const QModelIndex &parent) const 0141 { 0142 Q_UNUSED(parent) 0143 return m_applications.length(); 0144 } 0145 0146 int ApplicationModel::columnCount(const QModelIndex &parent) const 0147 { 0148 if (!parent.isValid()) 0149 return 0; 0150 0151 return 1; 0152 } 0153 0154 QVariant ApplicationModel::data(const QModelIndex &index, int role) const 0155 { 0156 if (!isValid(index)) 0157 return QVariant(); 0158 0159 int row = index.row(); 0160 const auto map = m_applications.at(row); 0161 switch (role) { 0162 case Qt::DisplayRole: 0163 return map["name"]; 0164 case Icon: 0165 return map["icon"]; 0166 case StorageId: 0167 return map["storageId"]; 0168 case Selected: 0169 return map["isSelected"]; 0170 case ExecLine: 0171 return map["execLine"]; 0172 } 0173 0174 return QVariant(); 0175 } 0176 0177 QVariant ApplicationModel::data(const int &row, int role) const 0178 { 0179 return data(index(row, 0), role); 0180 } 0181 0182 bool ApplicationModel::isValid(const QModelIndex &index) const 0183 { 0184 return index.column() == 0 && index.row() >= 0 && index.row() < m_applications.length(); 0185 } 0186 0187 bool ApplicationModel::setData(const QModelIndex &index, const QVariant &value, int role) 0188 { 0189 if (role != Selected) { 0190 return false; 0191 } 0192 if (!isValid(index)) { 0193 return false; 0194 } 0195 if (!value.canConvert(QMetaType(QMetaType::Type::Bool)) && !value.toBool()) { 0196 return false; 0197 } 0198 0199 for (auto &application : m_applications) { 0200 application["isSelected"] = false; 0201 } 0202 0203 const auto row = index.row(); 0204 0205 // auto map = m_applications[row].toMap(); 0206 m_applications[row]["isSelected"] = true; 0207 // m_applications[row] = map; 0208 0209 Q_EMIT dataChanged(index, index, {role}); 0210 0211 return true; 0212 } 0213 0214 QModelIndex ApplicationModel::findByStorageId(const QString &storageId) const 0215 { 0216 int i = 0; 0217 for (const auto &application : std::as_const(m_applications)) { 0218 if (application["storageId"] == storageId) { 0219 return index(i, 0); 0220 } 0221 ++i; 0222 } 0223 return QModelIndex(); 0224 } 0225 0226 QHash<int, QByteArray> ApplicationModel::roleNames() const 0227 { 0228 return { 0229 {Qt::DisplayRole, "name"}, 0230 {Icon, "icon"}, 0231 {StorageId, "storageId"}, 0232 {Selected, "isSelected"}, 0233 {ExecLine, "execLine"}, 0234 }; 0235 }