File indexing completed on 2024-05-12 05:35:45

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 : std::as_const(m_components)) {
0078         if (component.pendingDeletion) {
0079             return true;
0080         }
0081         for (const auto &action : std::as_const(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 : std::as_const(m_components)) {
0093         for (const auto &action : std::as_const(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 }