cf12defd28
Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent) Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
177 lines
5.2 KiB
C++
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"
|