SPDX-FileCopyrightText: 2024 Evgeny Chesnokov <echesnokov@astralinux.ru>
SPDX-License-Identifier: GPL-2.0-or-later
*/
#include "userlayoutmodel.h"
#include <QItemSelectionModel>
#include "debug.h"
#include "keyboard_config.h"
#include "x11_helper.h"
#include "xkb_rules.h"
UserLayoutModel::UserLayoutModel(Rules *rules, KeyboardConfig *config, QObject *parent) noexcept
: QAbstractListModel(parent)
, m_selectionModel(new QItemSelectionModel(this))
, m_rules(rules)
, m_config(config)
{
}
QItemSelectionModel *UserLayoutModel::selectionModel() const
{
return m_selectionModel;
}
int UserLayoutModel::rowCount(const QModelIndex &parent) const
{
return m_config->layouts().count();
}
QVariant UserLayoutModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() >= m_config->layouts().size())
return QVariant();
const auto &layout = m_config->layouts().at(index.row());
if (role == Roles::LayoutRole) {
return QVariant::fromValue(layout.layout());
} else if (role == Roles::LayoutNameRole) {
const LayoutInfo *layoutInfo = m_rules->getLayoutInfo(layout.layout());
return layoutInfo != nullptr ? layoutInfo->description : layout.layout();
} else if (role == Roles::VariantRole) {
return QVariant::fromValue(layout.variant());
} else if (role == Roles::VariantNameRole) {
if (layout.variant().isEmpty())
return QVariant();
const LayoutInfo *layoutInfo = m_rules->getLayoutInfo(layout.layout());
if (layoutInfo == nullptr)
return QVariant();
const VariantInfo *variantInfo = layoutInfo->getVariantInfo(layout.variant());
return variantInfo != nullptr ? variantInfo->description : layout.variant();
} else if (role == Roles::DisplayNameRole) {
return QVariant::fromValue(layout.getDisplayName());
} else if (role == Roles::ShortcutRole) {
return QVariant::fromValue(layout.getShortcut());
}
return QVariant();
}
bool UserLayoutModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != Roles::DisplayNameRole && role != Roles::ShortcutRole && role != Roles::VariantRole) {
return false;
}
if (index.row() >= m_config->layouts().size() || index.data(role) == value) {
return false;
}
LayoutUnit &layoutUnit = m_config->layouts()[index.row()];
if (role == Roles::DisplayNameRole) {
QString displayText = value.toString().left(3);
layoutUnit.setDisplayName(displayText);
Q_EMIT dataChanged(index, index, {Roles::DisplayNameRole});
return true;
}
if (role == Roles::ShortcutRole) {
layoutUnit.setShortcut(QKeySequence(value.toString()));
Q_EMIT dataChanged(index, index, {Roles::ShortcutRole});
return true;
}
if (role == Roles::VariantRole) {
layoutUnit.setVariant(value.toString());
Q_EMIT dataChanged(index, index, {Roles::VariantRole, Roles::VariantNameRole});
return true;
}
return false;
}
QHash<int, QByteArray> UserLayoutModel::roleNames() const
{
return {
{Roles::LayoutRole, QByteArrayLiteral("layout")},
{Roles::LayoutNameRole, QByteArrayLiteral("layoutName")},
{Roles::VariantRole, QByteArrayLiteral("variant")},
{Roles::VariantNameRole, QByteArrayLiteral("variantName")},
{Roles::DisplayNameRole, QByteArrayLiteral("displayName")},
{Roles::ShortcutRole, QByteArrayLiteral("shortcut")},
};
}
void UserLayoutModel::reset()
{
m_selectionModel->clear();
beginResetModel();
endResetModel();
}
void UserLayoutModel::clear()
{
m_config->layouts().clear();
reset();
}
void UserLayoutModel::moveSelectedLayouts(int shift)
{
if (!m_selectionModel->hasSelection()) {
return;
}
const QModelIndexList &selected = m_selectionModel->selectedRows();
QList<int> rows(selected.size());
std::transform(selected.cbegin(), selected.cend(), rows.begin(), [](const QModelIndex &index) -> int {
return index.row();
});
std::sort(rows.begin(), rows.end(), [shift](int left, int right) -> bool {
return shift < 0 ? left < right : left > right;
});
const int newFirstRow = (shift > 0 ? rows.first() : rows.last()) + shift;
const int newLastRow = (shift > 0 ? rows.last() : rows.first()) + shift;
if (newFirstRow < 0 || newLastRow >= m_config->layouts().size()) {
return;
}
m_selectionModel->clearSelection();
for (const int row : rows) {
const int destinationRow = row + shift;
if (beginMoveRows(QModelIndex(), row, row, QModelIndex(), row < destinationRow ? destinationRow + 1 : destinationRow)) {
m_config->layouts().move(row, destinationRow);
endMoveRows();
}
m_selectionModel->select(UserLayoutModel::index(destinationRow, 0), QItemSelectionModel::SelectionFlag::Select);
}
}
void UserLayoutModel::addLayout(const QString &layout, const QString &variant, const QKeySequence &shortcut, const QString &displayName)
{
LayoutUnit unit = LayoutUnit(layout, variant);
unit.setShortcut(shortcut);
if (!displayName.isEmpty()) {
unit.setDisplayName(displayName);
}
beginInsertRows(QModelIndex(), m_config->layouts().count(), m_config->layouts().count());
m_config->layouts().append(unit);
endInsertRows();
}
void UserLayoutModel::removeSelected()
{
if (!m_selectionModel->hasSelection()) {
return;
}
const QModelIndexList &selected = m_selectionModel->selectedRows();
QList<int> rows(selected.size());
std::transform(selected.cbegin(), selected.cend(), rows.begin(), [](const QModelIndex &index) -> int {
return index.row();
});
std::sort(rows.begin(), rows.end(), [](int left, int right) -> bool {
return left > right;
});
for (const int row : rows) {
beginRemoveRows(QModelIndex(), row, row);
m_config->layouts().removeAt(row);
endRemoveRows();
}
}
#include "moc_userlayoutmodel.cpp"
#include "userlayoutmodel.moc"