File indexing completed on 2024-05-12 17:07:17
0001 /* 0002 SPDX-FileCopyrightText: 2020 David Redondo <kde@david-redondo.de> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "basemodel.h" 0008 0009 #include <KConfigGroup> 0010 #include <KDesktopFile> 0011 0012 #include "kcmkeys_debug.h" 0013 0014 BaseModel::BaseModel(QObject *parent) 0015 : QAbstractItemModel(parent) 0016 { 0017 } 0018 0019 void BaseModel::addShortcut(const QModelIndex &index, const QKeySequence &shortcut) 0020 { 0021 if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid) || !index.parent().isValid()) { 0022 return; 0023 } 0024 if (shortcut.isEmpty()) { 0025 return; 0026 } 0027 qCDebug(KCMKEYS) << "Adding shortcut" << index << shortcut; 0028 Action &a = m_components[index.parent().row()].actions[index.row()]; 0029 a.activeShortcuts.insert(shortcut); 0030 Q_EMIT dataChanged(index, index, {ActiveShortcutsRole, CustomShortcutsRole, IsDefaultRole}); 0031 Q_EMIT dataChanged(index.parent(), index.parent(), {IsDefaultRole}); 0032 } 0033 0034 void BaseModel::disableShortcut(const QModelIndex &index, const QKeySequence &shortcut) 0035 { 0036 if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid) || !index.parent().isValid()) { 0037 return; 0038 } 0039 qCDebug(KCMKEYS) << "Disabling shortcut" << index << shortcut; 0040 Action &a = m_components[index.parent().row()].actions[index.row()]; 0041 a.activeShortcuts.remove(shortcut); 0042 Q_EMIT dataChanged(index, index, {ActiveShortcutsRole, CustomShortcutsRole, IsDefaultRole}); 0043 Q_EMIT dataChanged(index.parent(), index.parent(), {IsDefaultRole}); 0044 } 0045 0046 void BaseModel::changeShortcut(const QModelIndex &index, const QKeySequence &oldShortcut, const QKeySequence &newShortcut) 0047 { 0048 if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid) || !index.parent().isValid()) { 0049 return; 0050 } 0051 if (newShortcut.isEmpty()) { 0052 return; 0053 } 0054 qCDebug(KCMKEYS) << "Changing Shortcut" << index << oldShortcut << " to " << newShortcut; 0055 Action &a = m_components[index.parent().row()].actions[index.row()]; 0056 a.activeShortcuts.remove(oldShortcut); 0057 a.activeShortcuts.insert(newShortcut); 0058 Q_EMIT dataChanged(index, index, {ActiveShortcutsRole, CustomShortcutsRole}); 0059 } 0060 0061 void BaseModel::defaults() 0062 { 0063 for (int i = 0; i < m_components.size(); ++i) { 0064 const auto componentIndex = index(i, 0); 0065 for (auto action_it = m_components[i].actions.begin(); action_it != m_components[i].actions.end(); ++action_it) { 0066 action_it->activeShortcuts = action_it->defaultShortcuts; 0067 } 0068 Q_EMIT dataChanged(index(0, 0, componentIndex), 0069 index(m_components[i].actions.size() - 1, 0, componentIndex), 0070 {ActiveShortcutsRole, CustomShortcutsRole, IsDefaultRole}); 0071 } 0072 Q_EMIT dataChanged(index(0, 0), index(m_components.size() - 1, 0), {IsDefaultRole}); 0073 } 0074 0075 bool BaseModel::needsSave() const 0076 { 0077 for (const auto &component : qAsConst(m_components)) { 0078 if (component.pendingDeletion) { 0079 return true; 0080 } 0081 for (const auto &action : qAsConst(component.actions)) { 0082 if (action.initialShortcuts != action.activeShortcuts) { 0083 return true; 0084 } 0085 } 0086 } 0087 return false; 0088 } 0089 0090 bool BaseModel::isDefault() const 0091 { 0092 for (const auto &component : qAsConst(m_components)) { 0093 for (const auto &action : qAsConst(component.actions)) { 0094 if (action.defaultShortcuts != action.activeShortcuts) { 0095 return false; 0096 } 0097 } 0098 } 0099 return true; 0100 } 0101 0102 QModelIndex BaseModel::index(int row, int column, const QModelIndex &parent) const 0103 { 0104 if (row < 0 || column != 0) { 0105 return QModelIndex(); 0106 } 0107 if (parent.isValid() && row < rowCount(parent) && column == 0) { 0108 return createIndex(row, column, parent.row() + 1); 0109 } else if (column == 0 && row < m_components.size()) { 0110 return createIndex(row, column, nullptr); 0111 } 0112 return QModelIndex(); 0113 } 0114 0115 QModelIndex BaseModel::parent(const QModelIndex &child) const 0116 { 0117 if (child.internalId()) { 0118 return createIndex(child.internalId() - 1, 0, nullptr); 0119 } 0120 return QModelIndex(); 0121 } 0122 0123 int BaseModel::rowCount(const QModelIndex &parent) const 0124 { 0125 if (parent.isValid()) { 0126 if (parent.parent().isValid()) { 0127 return 0; 0128 } 0129 return m_components[parent.row()].actions.size(); 0130 } 0131 return m_components.size(); 0132 } 0133 0134 int BaseModel::columnCount(const QModelIndex &parent) const 0135 { 0136 Q_UNUSED(parent); 0137 return 1; 0138 } 0139 0140 QVariant BaseModel::data(const QModelIndex &index, int role) const 0141 { 0142 if (!checkIndex(index, QAbstractItemModel::CheckIndexOption::IndexIsValid)) { 0143 return QVariant(); 0144 } 0145 0146 if (index.parent().isValid()) { 0147 const Action &action = m_components[index.parent().row()].actions[index.row()]; 0148 switch (role) { 0149 case Qt::DisplayRole: { 0150 KDesktopFile desktopFile(action.id); 0151 KConfigGroup cg = desktopFile.desktopGroup(); 0152 if (cg.readEntry<bool>("X-KDE-GlobalAccel-CommandShortcut", false)) { 0153 return cg.readEntry("Exec"); 0154 } 0155 return action.displayName.isEmpty() ? action.id : action.displayName; 0156 } 0157 case ActionRole: 0158 return action.id; 0159 case ActiveShortcutsRole: 0160 return QVariant::fromValue(action.activeShortcuts); 0161 case DefaultShortcutsRole: 0162 return QVariant::fromValue(action.defaultShortcuts); 0163 case CustomShortcutsRole: { 0164 auto shortcuts = action.activeShortcuts; 0165 return QVariant::fromValue(shortcuts.subtract(action.defaultShortcuts)); 0166 } 0167 case IsDefaultRole: 0168 return action.activeShortcuts == action.defaultShortcuts; 0169 case SupportsMultipleKeysRole: 0170 return true; 0171 } 0172 return QVariant(); 0173 } 0174 const Component &component = m_components[index.row()]; 0175 switch (role) { 0176 case Qt::DisplayRole: { 0177 KDesktopFile desktopFile(component.id); 0178 KConfigGroup cg = desktopFile.desktopGroup(); 0179 if (cg.readEntry<bool>("X-KDE-GlobalAccel-CommandShortcut", false)) { 0180 return cg.readEntry("Exec"); 0181 } 0182 return component.displayName; 0183 } 0184 case Qt::DecorationRole: 0185 return component.icon; 0186 case SectionRole: 0187 return component.type; 0188 case ComponentRole: 0189 return component.id; 0190 case CheckedRole: 0191 return component.checked; 0192 case PendingDeletionRole: 0193 return component.pendingDeletion; 0194 case IsDefaultRole: 0195 return std::all_of(component.actions.begin(), component.actions.end(), [](const Action &action) { 0196 return action.activeShortcuts == action.defaultShortcuts; 0197 }); 0198 } 0199 return QVariant(); 0200 } 0201 0202 bool BaseModel::setData(const QModelIndex &index, const QVariant &value, int role) 0203 { 0204 if (!checkIndex(index, QAbstractListModel::CheckIndexOption::IndexIsValid | QAbstractListModel::CheckIndexOption::ParentIsInvalid)) { 0205 return false; 0206 } 0207 const bool boolValue = value.toBool(); 0208 switch (role) { 0209 case CheckedRole: 0210 if (m_components[index.row()].checked != boolValue) { 0211 m_components[index.row()].checked = boolValue; 0212 Q_EMIT dataChanged(index, index, {CheckedRole}); 0213 return true; 0214 } 0215 break; 0216 case PendingDeletionRole: 0217 if (m_components[index.row()].pendingDeletion != boolValue) { 0218 m_components[index.row()].pendingDeletion = boolValue; 0219 Q_EMIT dataChanged(index, index, {PendingDeletionRole}); 0220 return true; 0221 } 0222 break; 0223 } 0224 return false; 0225 } 0226 0227 QHash<int, QByteArray> BaseModel::roleNames() const 0228 { 0229 return {{Qt::DisplayRole, QByteArrayLiteral("display")}, 0230 {Qt::DecorationRole, QByteArrayLiteral("decoration")}, 0231 {SectionRole, QByteArrayLiteral("section")}, 0232 {ComponentRole, QByteArrayLiteral("component")}, 0233 {ActiveShortcutsRole, QByteArrayLiteral("activeShortcuts")}, 0234 {DefaultShortcutsRole, QByteArrayLiteral("defaultShortcuts")}, 0235 {CustomShortcutsRole, QByteArrayLiteral("customShortcuts")}, 0236 {CheckedRole, QByteArrayLiteral("checked")}, 0237 {PendingDeletionRole, QByteArrayLiteral("pendingDeletion")}, 0238 {IsDefaultRole, QByteArrayLiteral("isDefault")}, 0239 {SupportsMultipleKeysRole, QByteArrayLiteral("supportsMultipleKeys")}}; 0240 }