/* SPDX-FileCopyrightText: 2024 Evgeny Chesnokov SPDX-License-Identifier: GPL-2.0-or-later */ #include "userlayoutmodel.h" #include #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 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 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 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"