Files
RedBear-OS/local/recipes/kde/kf6-kconfigwidgets/source/src/kcommandbarmodel_p.cpp
T
2026-04-14 10:51:06 +01:00

177 lines
5.2 KiB
C++

/*
SPDX-FileCopyrightText: 2021 Waqar Ahmed <waqar.17a@gmail.com>
SPDX-License-Identifier: LGPL-2.0-or-later
*/
#include "kcommandbarmodel_p.h"
#include "kcommandbar.h" // For ActionGroup
#include "kconfigwidgets_debug.h"
#include <KLocalizedString>
#include <QAction>
#include <QMenu>
#include <unordered_set>
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<KCommandBarModel::Item> &rows, const QString &title, const QList<QAction *> &actions, std::unordered_set<QAction *> &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<KCommandBar::ActionGroup> &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<Item> temp_rows;
std::unordered_set<QAction *> 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"