Warning, file /plasma/plasma-mobile/containments/homescreens/halcyon/pinnedmodel.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 // SPDX-FileCopyrightText: 2022 Devin Lin <devin@kde.org> 0002 // SPDX-License-Identifier: GPL-2.0-or-later 0003 0004 #include "pinnedmodel.h" 0005 0006 #include <QJsonArray> 0007 #include <QJsonDocument> 0008 0009 #include <KLocalizedString> 0010 0011 PinnedModel::PinnedModel(QObject *parent, Plasma::Applet *applet) 0012 : QAbstractListModel{parent} 0013 , m_applet{applet} 0014 { 0015 } 0016 0017 PinnedModel::~PinnedModel() = default; 0018 0019 int PinnedModel::rowCount(const QModelIndex &parent) const 0020 { 0021 return m_applications.count(); 0022 } 0023 0024 QVariant PinnedModel::data(const QModelIndex &index, int role) const 0025 { 0026 if (!index.isValid()) { 0027 return QVariant(); 0028 } 0029 0030 switch (role) { 0031 case IsFolderRole: 0032 return m_folders.at(index.row()) != nullptr; 0033 case ApplicationRole: 0034 return QVariant::fromValue(m_applications.at(index.row())); 0035 case FolderRole: 0036 return QVariant::fromValue(m_folders.at(index.row())); 0037 } 0038 0039 return QVariant(); 0040 } 0041 0042 QHash<int, QByteArray> PinnedModel::roleNames() const 0043 { 0044 return {{IsFolderRole, "isFolder"}, {ApplicationRole, "application"}, {FolderRole, "folder"}}; 0045 } 0046 0047 void PinnedModel::addApp(const QString &storageId, int row) 0048 { 0049 if (row < 0 || row > m_applications.size()) { 0050 return; 0051 } 0052 0053 if (KService::Ptr service = KService::serviceByStorageId(storageId)) { 0054 Application *app = new Application(this, service); 0055 0056 beginInsertRows(QModelIndex(), row, row); 0057 m_applications.insert(row, app); 0058 m_folders.insert(row, nullptr); // maintain indicies 0059 endInsertRows(); 0060 0061 save(); 0062 } 0063 } 0064 0065 void PinnedModel::addFolder(QString name, int row) 0066 { 0067 if (row < 0 || row > m_applications.size()) { 0068 return; 0069 } 0070 0071 ApplicationFolder *folder = new ApplicationFolder(this, name); 0072 connect(folder, &ApplicationFolder::saveRequested, this, &PinnedModel::save); 0073 connect(folder, &ApplicationFolder::moveAppOutRequested, this, &PinnedModel::addAppFromFolder); 0074 0075 beginInsertRows(QModelIndex(), row, row); 0076 m_applications.insert(row, nullptr); 0077 m_folders.insert(row, folder); 0078 endInsertRows(); 0079 0080 save(); 0081 } 0082 0083 void PinnedModel::removeEntry(int row) 0084 { 0085 if (row < 0 || row >= m_applications.size()) { 0086 return; 0087 } 0088 0089 beginRemoveRows(QModelIndex(), row, row); 0090 if (m_folders[row]) { 0091 m_folders[row]->deleteLater(); 0092 } 0093 if (m_applications[row]) { 0094 m_applications[row]->deleteLater(); 0095 } 0096 m_applications.removeAt(row); 0097 m_folders.removeAt(row); 0098 endRemoveRows(); 0099 0100 save(); 0101 } 0102 0103 void PinnedModel::moveEntry(int fromRow, int toRow) 0104 { 0105 if (fromRow < 0 || toRow < 0 || fromRow >= m_applications.length() || toRow >= m_applications.length() || fromRow == toRow) { 0106 return; 0107 } 0108 if (toRow > fromRow) { 0109 ++toRow; 0110 } 0111 0112 beginMoveRows(QModelIndex(), fromRow, fromRow, QModelIndex(), toRow); 0113 if (toRow > fromRow) { 0114 Application *app = m_applications.at(fromRow); 0115 m_applications.insert(toRow, app); 0116 m_applications.takeAt(fromRow); 0117 0118 ApplicationFolder *folder = m_folders.at(fromRow); 0119 m_folders.insert(toRow, folder); 0120 m_folders.takeAt(fromRow); 0121 0122 } else { 0123 Application *app = m_applications.takeAt(fromRow); 0124 m_applications.insert(toRow, app); 0125 0126 ApplicationFolder *folder = m_folders.takeAt(fromRow); 0127 m_folders.insert(toRow, folder); 0128 } 0129 endMoveRows(); 0130 0131 save(); 0132 0133 // HACK: didn't seem to persist 0134 m_applet->config().sync(); 0135 } 0136 0137 void PinnedModel::createFolderFromApps(int sourceAppRow, int draggedAppRow) 0138 { 0139 if (sourceAppRow < 0 || sourceAppRow >= m_applications.size() || draggedAppRow < 0 || draggedAppRow >= m_applications.size()) { 0140 return; 0141 } 0142 0143 if (sourceAppRow == draggedAppRow || !m_applications[sourceAppRow] || !m_applications[draggedAppRow]) { 0144 return; 0145 } 0146 0147 // replace source app with folder containing both apps 0148 ApplicationFolder *folder = new ApplicationFolder(this, i18nc("Default application folder name.", "Folder")); 0149 connect(folder, &ApplicationFolder::saveRequested, this, &PinnedModel::save); 0150 connect(folder, &ApplicationFolder::moveAppOutRequested, this, &PinnedModel::addAppFromFolder); 0151 0152 folder->addApp(m_applications[sourceAppRow]->storageId(), 0); 0153 folder->addApp(m_applications[draggedAppRow]->storageId(), 0); 0154 0155 m_applications[sourceAppRow]->deleteLater(); 0156 m_applications[sourceAppRow] = nullptr; 0157 m_folders[sourceAppRow] = folder; 0158 0159 Q_EMIT dataChanged(index(sourceAppRow, 0), index(sourceAppRow, 0), {IsFolderRole, ApplicationRole, FolderRole}); 0160 save(); 0161 0162 // remove dragged app after 0163 removeEntry(draggedAppRow); 0164 } 0165 0166 void PinnedModel::addAppToFolder(int appRow, int folderRow) 0167 { 0168 if (appRow < 0 || appRow >= m_applications.size() || folderRow < 0 || folderRow >= m_applications.size()) { 0169 return; 0170 } 0171 0172 if (!m_applications[appRow] || !m_folders[folderRow]) { 0173 return; 0174 } 0175 0176 ApplicationFolder *folder = m_folders[folderRow]; 0177 Application *app = m_applications[appRow]; 0178 folder->addApp(app->storageId(), folder->applications() ? folder->applications()->rowCount() : 0); 0179 0180 removeEntry(appRow); 0181 } 0182 0183 void PinnedModel::load() 0184 { 0185 if (!m_applet) { 0186 return; 0187 } 0188 0189 QJsonDocument doc = QJsonDocument::fromJson(m_applet->config().readEntry("Pinned", "{}").toUtf8()); 0190 0191 beginResetModel(); 0192 0193 for (QJsonValueRef r : doc.array()) { 0194 QJsonObject obj = r.toObject(); 0195 0196 if (obj[QStringLiteral("type")].toString() == "application") { 0197 // read application 0198 Application *app = Application::fromJson(obj, this); 0199 if (app) { 0200 m_applications.append(app); 0201 m_folders.append(nullptr); 0202 } 0203 0204 } else if (obj[QStringLiteral("type")].toString() == "folder") { 0205 // read folder 0206 ApplicationFolder *folder = ApplicationFolder::fromJson(obj, this); 0207 connect(folder, &ApplicationFolder::saveRequested, this, &PinnedModel::save); 0208 connect(folder, &ApplicationFolder::moveAppOutRequested, this, &PinnedModel::addAppFromFolder); 0209 0210 if (folder) { 0211 m_applications.append(nullptr); 0212 m_folders.append(folder); 0213 } 0214 } 0215 } 0216 0217 endResetModel(); 0218 } 0219 0220 void PinnedModel::save() 0221 { 0222 if (!m_applet) { 0223 return; 0224 } 0225 0226 QJsonArray arr; 0227 for (int i = 0; i < m_applications.size() && i < m_folders.size(); i++) { 0228 if (m_applications[i]) { 0229 arr.push_back(m_applications[i]->toJson()); 0230 } else if (m_folders[i]) { 0231 arr.push_back(m_folders[i]->toJson()); 0232 } 0233 } 0234 QByteArray data = QJsonDocument(arr).toJson(QJsonDocument::Compact); 0235 0236 m_applet->config().writeEntry("Pinned", QString::fromStdString(data.toStdString())); 0237 Q_EMIT m_applet->configNeedsSaving(); 0238 } 0239 0240 void PinnedModel::addAppFromFolder(const QString &storageId) 0241 { 0242 addApp(storageId, 0); 0243 }