File indexing completed on 2024-11-24 04:50:43
0001 // SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com> 0002 // SPDX-License-Identifier: LGPL-2.0-or-later 0003 0004 #include "actionsmodel.h" 0005 0006 #include <KLocalizedString> 0007 0008 #include <QAction> 0009 #include <QMenu> 0010 0011 #include <unordered_set> 0012 0013 KalCommandBarModel::KalCommandBarModel(QObject *parent) 0014 : QAbstractTableModel(parent) 0015 { 0016 } 0017 0018 void fillRows(QList<KalCommandBarModel::Item> &rows, const QString &title, const QList<QAction *> &actions, std::unordered_set<QAction *> &uniqueActions) 0019 { 0020 for (const auto &action : actions) { 0021 // We don't want disabled actions 0022 if (!action->isEnabled()) { 0023 continue; 0024 } 0025 0026 // Is this action actually a menu? 0027 if (auto menu = action->menu()) { 0028 auto menuActionList = menu->actions(); 0029 0030 // Empty? => Maybe the menu loads action on aboutToShow()? 0031 if (menuActionList.isEmpty()) { 0032 Q_EMIT menu->aboutToShow(); 0033 menuActionList = menu->actions(); 0034 } 0035 0036 const QString menuTitle = menu->title(); 0037 fillRows(rows, menuTitle, menuActionList, uniqueActions); 0038 continue; 0039 } 0040 0041 if (uniqueActions.insert(action).second) { 0042 rows.push_back(KalCommandBarModel::Item{title, action, -1}); 0043 } 0044 } 0045 } 0046 0047 void KalCommandBarModel::refresh(const QList<ActionGroup> &actionGroups) 0048 { 0049 int totalActions = std::accumulate(actionGroups.begin(), actionGroups.end(), 0, [](int a, const ActionGroup &ag) { 0050 return a + ag.actions.count(); 0051 }); 0052 0053 QList<Item> temp_rows; 0054 std::unordered_set<QAction *> uniqueActions; 0055 temp_rows.reserve(totalActions); 0056 int actionGroupIdx = 0; 0057 for (const auto &ag : actionGroups) { 0058 const auto &agActions = ag.actions; 0059 fillRows(temp_rows, ag.name, agActions, uniqueActions); 0060 0061 actionGroupIdx++; 0062 } 0063 0064 /** 0065 * For each action in last triggered actions, 0066 * - Find it in the actions 0067 * - Use the score variable to set its score 0068 * 0069 * Items in m_lastTriggered are stored in descending order 0070 * by their usage i.e., the first item in the vector is the most 0071 * recently invoked action. 0072 * 0073 * Here we traverse them in reverse order, i.e., from least recent to 0074 * most recent and then assign a score to them in a way that most recent 0075 * ends up having the highest score. Thus when proxy model does the sorting 0076 * later, most recent item will end up on the top 0077 */ 0078 int score = 0; 0079 std::for_each(m_lastTriggered.crbegin(), m_lastTriggered.crend(), [&score, &temp_rows](const QString &act) { 0080 auto it = std::find_if(temp_rows.begin(), temp_rows.end(), [act](const KalCommandBarModel::Item &i) { 0081 return i.action->text() == act; 0082 }); 0083 if (it != temp_rows.end()) { 0084 it->score = score++; 0085 } 0086 }); 0087 0088 beginResetModel(); 0089 m_rows = std::move(temp_rows); 0090 endResetModel(); 0091 } 0092 0093 QVariant KalCommandBarModel::data(const QModelIndex &index, int role) const 0094 { 0095 if (!index.isValid()) { 0096 return {}; 0097 } 0098 0099 const auto &entry = m_rows[index.row()]; 0100 const int col = index.column(); 0101 0102 switch (role) { 0103 case Qt::DisplayRole: 0104 case DisplayNameRole: 0105 if (col == 0) { 0106 QString groupName = KLocalizedString::removeAcceleratorMarker(entry.groupName); 0107 QString actionText = KLocalizedString::removeAcceleratorMarker(entry.action->text()); 0108 return QString(groupName + QStringLiteral(": ") + actionText); 0109 } else { 0110 return entry.action->shortcut().toString(); 0111 } 0112 case ShortcutRole: 0113 return entry.action->shortcut().toString(); 0114 case Qt::DecorationRole: 0115 if (col == 0) { 0116 return entry.action->icon().name(); 0117 } 0118 break; 0119 case Qt::TextAlignmentRole: 0120 if (col == 0) { 0121 return Qt::AlignLeft; 0122 } else { 0123 return Qt::AlignRight; 0124 } 0125 case Qt::UserRole: { 0126 return QVariant::fromValue(entry.action); 0127 } 0128 case Role::Score: 0129 return entry.score; 0130 } 0131 0132 return {}; 0133 } 0134 0135 void KalCommandBarModel::actionTriggered(const QString &name) 0136 { 0137 if (m_lastTriggered.size() == 6) { 0138 m_lastTriggered.pop_back(); 0139 } 0140 m_lastTriggered.push_front(name); 0141 } 0142 0143 QStringList KalCommandBarModel::lastUsedActions() const 0144 { 0145 return m_lastTriggered; 0146 } 0147 0148 void KalCommandBarModel::setLastUsedActions(const QStringList &actionNames) 0149 { 0150 m_lastTriggered = actionNames; 0151 0152 while (m_lastTriggered.size() > 6) { 0153 m_lastTriggered.pop_back(); 0154 } 0155 } 0156 0157 QHash<int, QByteArray> KalCommandBarModel::roleNames() const 0158 { 0159 auto roles = QAbstractTableModel::roleNames(); 0160 roles[Qt::UserRole] = QByteArrayLiteral("qaction"); 0161 roles[Score] = QByteArrayLiteral("score"); 0162 roles[ShortcutRole] = QByteArrayLiteral("shortcut"); 0163 roles[DisplayNameRole] = QByteArrayLiteral("displayName"); 0164 return roles; 0165 } 0166 0167 #include "moc_actionsmodel.cpp"