/* SPDX-FileCopyrightText: 2021 Waqar Ahmed SPDX-License-Identifier: LGPL-2.0-or-later */ #include "kcommandbarmodel_p.h" #include "kcommandbar.h" // For ActionGroup #include "kconfigwidgets_debug.h" #include #include #include #include QString KCommandBarModel::Item::displayName() const { const QString group = KLocalizedString::removeAcceleratorMarker(groupName); const QString command = KLocalizedString::removeAcceleratorMarker(action->text()); return group + QStringLiteral(": ") + command; } KCommandBarModel::KCommandBarModel(QObject *parent) : QAbstractTableModel(parent) { m_clearHistoryAction = new QAction(tr("Clear History"), this); m_clearHistoryAction->setIcon(QIcon::fromTheme(QStringLiteral("edit-clear-history"))); connect(m_clearHistoryAction, &QAction::triggered, this, [this]() { m_lastTriggered.clear(); }); } void fillRows(QList &rows, const QString &title, const QList &actions, std::unordered_set &uniqueActions) { for (const auto &action : actions) { // We don't want diabled actions if (!action->isEnabled()) { continue; } // Is this action actually a menu? if (auto menu = action->menu()) { auto menuActionList = menu->actions(); // Empty? => Maybe the menu loads action on aboutToShow()? if (menuActionList.isEmpty()) { Q_EMIT menu->aboutToShow(); menuActionList = menu->actions(); } const QString menuTitle = menu->title(); fillRows(rows, menuTitle, menuActionList, uniqueActions); continue; } if (action->text().isEmpty() && !action->isSeparator()) { qCWarning(KCONFIG_WIDGETS_LOG) << "Action" << action << "in group" << title << "has no text"; continue; } if (uniqueActions.insert(action).second) { rows.push_back(KCommandBarModel::Item{title, action, -1}); } } } void KCommandBarModel::refresh(const QList &actionGroups) { int totalActions = std::accumulate(actionGroups.begin(), actionGroups.end(), 0, [](int a, const KCommandBar::ActionGroup &ag) { return a + ag.actions.count(); }); ++totalActions; // for m_clearHistoryAction QList temp_rows; std::unordered_set uniqueActions; temp_rows.reserve(totalActions); for (const auto &ag : actionGroups) { const auto &agActions = ag.actions; fillRows(temp_rows, ag.name, agActions, uniqueActions); } temp_rows.push_back({tr("Command Bar"), m_clearHistoryAction, -1}); /** * For each action in last triggered actions, * - Find it in the actions * - Use the score variable to set its score * * Items in m_lastTriggered are stored in descending order * by their usage i.e., the first item in the vector is the most * recently invoked action. * * Here we traverse them in reverse order, i.e., from least recent to * most recent and then assign a score to them in a way that most recent * ends up having the highest score. Thus when proxy model does the sorting * later, most recent item will end up on the top */ int score = 0; std::for_each(m_lastTriggered.crbegin(), m_lastTriggered.crend(), [&score, &temp_rows](const QString &act) { auto it = std::find_if(temp_rows.begin(), temp_rows.end(), [act](const KCommandBarModel::Item &i) { return i.action->text() == act; }); if (it != temp_rows.end()) { it->score = score++; } }); beginResetModel(); m_rows = std::move(temp_rows); endResetModel(); } QVariant KCommandBarModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return {}; } const auto &entry = m_rows[index.row()]; const int col = index.column(); switch (role) { case Qt::DisplayRole: if (col == Column_Command) { return entry.displayName(); } Q_ASSERT(col == Column_Shortcut); return entry.action->shortcut().toString(); case Qt::DecorationRole: if (col == Column_Command) { return entry.action->icon(); } break; case Qt::ToolTipRole: { QString toolTip = entry.displayName(); if (!entry.action->shortcut().isEmpty()) { toolTip += QLatin1Char('\n'); toolTip += entry.action->shortcut().toString(); } return toolTip; } case Qt::UserRole: { return QVariant::fromValue(entry.action); } case Role::Score: return entry.score; } return {}; } void KCommandBarModel::actionTriggered(const QString &name) { if (m_lastTriggered.size() == 6) { m_lastTriggered.pop_back(); } m_lastTriggered.push_front(name); } QStringList KCommandBarModel::lastUsedActions() const { return m_lastTriggered; } void KCommandBarModel::setLastUsedActions(const QStringList &actionNames) { m_lastTriggered = actionNames; while (m_lastTriggered.size() > 6) { m_lastTriggered.pop_back(); } } #include "moc_kcommandbarmodel_p.cpp"