diff --git a/kcms/keyboard/flags.cpp b/kcms/keyboard/flags.cpp index 6b363f9d9..b8e02a21d 100644 --- a/kcms/keyboard/flags.cpp +++ b/kcms/keyboard/flags.cpp @@ -1,296 +1,296 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "flags.h" #include #include #include #include #include #include #include #include #include #include #include #include "x11_helper.h" //for text handling #include "keyboard_config.h" #include "xkb_rules.h" static const int FLAG_MAX_SIZE = 22; static const char flagTemplate[] = "kf5/locale/countries/%1/flag.png"; int iconSize(int s) { if (s < 16) { return 16; } else if (s < 22) { return 22; } else if (s < 32) { return 32; } else if (s < 48) { return 48; } else if (s < 64) { return 64; } else { return 128; } } Flags::Flags(): svg(nullptr) { transparentPixmap = new QPixmap(FLAG_MAX_SIZE, FLAG_MAX_SIZE); transparentPixmap->fill(Qt::transparent); } Flags::~Flags() { if( svg != nullptr ) { disconnect(svg, &Plasma::Svg::repaintNeeded, this, &Flags::themeChanged); delete svg; } delete transparentPixmap; } const QIcon Flags::getIcon(const QString& layout) { if( ! iconMap.contains(layout) ) { iconMap[ layout ] = createIcon(layout); } return iconMap[ layout ]; } QIcon Flags::createIcon(const QString& layout) { QIcon icon; if( ! layout.isEmpty() ) { QString file; if( layout == QLatin1String("epo") ) { file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QStringLiteral("kcmkeyboard/pics/epo.png")); } else { QString countryCode = getCountryFromLayoutName( layout ); if( ! countryCode.isEmpty() ) { file = QStandardPaths::locate(QStandardPaths::GenericDataLocation, QString(flagTemplate).arg(countryCode)); // qCDebug(KCM_KEYBOARD, ) << "Creating icon for" << layout << "with" << file; } } if (!file.isEmpty()) { QImage flagImg; flagImg.load(file); const int size = iconSize(qMax(flagImg.width(), flagImg.height())); QPixmap iconPix(size, size); iconPix.fill(Qt::transparent); QRect dest(flagImg.rect()); dest.moveCenter(iconPix.rect().center()); QPainter painter(&iconPix); painter.drawImage(dest, flagImg); painter.end(); icon.addPixmap(iconPix); } } return icon; } //static //const QStringList NON_COUNTRY_LAYOUTS = QString("ara,brai,epo,latam,mao").split(","); QString Flags::getCountryFromLayoutName(const QString& layout) const { QString countryCode = layout; if( countryCode == QLatin1String("nec_vndr/jp") ) return QStringLiteral("jp"); // if( NON_COUNTRY_LAYOUTS.contain(layout) ) if( countryCode.length() > 2 ) return QLatin1String(""); return countryCode; } //TODO: move this to some other class? QString Flags::getShortText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig) { if( layoutUnit.isEmpty() ) return QStringLiteral("--"); - QString layoutText = layoutUnit.layout; + QString layoutText = layoutUnit.layout(); foreach(const LayoutUnit& lu, keyboardConfig.layouts) { - if( layoutUnit.layout == lu.layout && layoutUnit.variant == lu.variant ) { + if( layoutUnit.layout() == lu.layout() && layoutUnit.variant() == lu.variant() ) { layoutText = lu.getDisplayName(); break; } } //TODO: good autolabel // if( layoutText == layoutUnit.layout && layoutUnit.getDisplayName() != layoutUnit.layout ) { // layoutText = layoutUnit.getDisplayName(); // } return layoutText; } QString Flags::getFullText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig, const Rules* rules) { QString shortText = Flags::getShortText(layoutUnit, keyboardConfig); QString longText = Flags::getLongText(layoutUnit, rules); return i18nc("short layout label - full layout name", "%1 - %2", shortText, longText); } static QString getDisplayText(const QString& layout, const QString& variant, const Rules* rules) { if( variant.isEmpty() ) return layout; if( rules == nullptr || rules->version == QLatin1String("1.0") ) return i18nc("layout - variant", "%1 - %2", layout, variant); return variant; } QString Flags::getLongText(const LayoutUnit& layoutUnit, const Rules* rules) { if( rules == nullptr ) { - return getDisplayText(layoutUnit.layout, layoutUnit.variant, rules); + return getDisplayText(layoutUnit.layout(), layoutUnit.variant(), rules); } - QString layoutText = layoutUnit.layout; - const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout); + QString layoutText = layoutUnit.layout(); + const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout()); if( layoutInfo != nullptr ) { layoutText = layoutInfo->description; - if( ! layoutUnit.variant.isEmpty() ) { - const VariantInfo* variantInfo = layoutInfo->getVariantInfo(layoutUnit.variant); - QString variantText = variantInfo != nullptr ? variantInfo->description : layoutUnit.variant; + if( ! layoutUnit.variant().isEmpty() ) { + const VariantInfo* variantInfo = layoutInfo->getVariantInfo(layoutUnit.variant()); + QString variantText = variantInfo != nullptr ? variantInfo->description : layoutUnit.variant(); layoutText = getDisplayText(layoutText, variantText, rules); } } return layoutText; } static QString getPixmapKey(const KeyboardConfig& keyboardConfig) { switch(keyboardConfig.indicatorType) { case KeyboardConfig::SHOW_FLAG: return QStringLiteral("_fl"); case KeyboardConfig::SHOW_LABEL_ON_FLAG: return QStringLiteral("_bt"); case KeyboardConfig::SHOW_LABEL: return QStringLiteral("_lb"); } return QStringLiteral("_"); // should not happen } void Flags::drawLabel(QPainter& painter, const QString& layoutText, bool flagShown) { QFont font = painter.font(); QRect rect = painter.window(); font.setPointSize(KFontUtils::adaptFontSize(painter, layoutText, rect.size(), rect.height())); // we init svg so that we get notification about theme change getSvg(); const QColor textColor = flagShown ? Qt::black : Plasma::Theme().color(Plasma::Theme::TextColor); painter.setPen(textColor); painter.setFont(font); painter.drawText(rect, Qt::AlignCenter, layoutText); } const QIcon Flags::getIconWithText(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig) { const QString keySuffix(getPixmapKey(keyboardConfig)); const QString key(layoutUnit.toString() + keySuffix); if( iconOrTextMap.contains(key) ) { return iconOrTextMap[ key ]; } if( keyboardConfig.indicatorType == KeyboardConfig::SHOW_FLAG ) { - QIcon icon = getIcon(layoutUnit.layout); + QIcon icon = getIcon(layoutUnit.layout()); if( ! icon.isNull() ) { iconOrTextMap[ key ] = icon; return icon; } } QString layoutText = Flags::getShortText(layoutUnit, keyboardConfig); const QSize TRAY_ICON_SIZE(128, 128); QPixmap pixmap = QPixmap(TRAY_ICON_SIZE); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); painter.setRenderHint(QPainter::SmoothPixmapTransform); // p.setRenderHint(QPainter::Antialiasing); if( keyboardConfig.indicatorType == KeyboardConfig::SHOW_LABEL_ON_FLAG ) { - QIcon iconf = createIcon(layoutUnit.layout); + QIcon iconf = createIcon(layoutUnit.layout()); painter.drawPixmap(pixmap.rect(), iconf.pixmap(TRAY_ICON_SIZE)); } drawLabel(painter, layoutText, keyboardConfig.isFlagShown()); painter.end(); QIcon icon(pixmap); iconOrTextMap[ key ] = icon; return icon; } Plasma::Svg* Flags::getSvg() { if( svg == nullptr ) { svg = new Plasma::Svg; svg->setImagePath(QStringLiteral("widgets/labeltexture")); svg->setContainsMultipleImages(true); connect(svg, &Plasma::Svg::repaintNeeded, this, &Flags::themeChanged); } return svg; } void Flags::themeChanged() { // qCDebug(KCM_KEYBOARD, ) << "Theme changed, new text color" << Plasma::Theme::defaultTheme()->color(Plasma::Theme::TextColor); clearCache(); emit pixmapChanged(); } void Flags::clearCache() { // qCDebug(KCM_KEYBOARD, ) << "Clearing flag pixmap cache"; iconOrTextMap.clear(); } diff --git a/kcms/keyboard/kcm_add_layout_dialog.cpp b/kcms/keyboard/kcm_add_layout_dialog.cpp index 7549a391c..8afc12ea6 100644 --- a/kcms/keyboard/kcm_add_layout_dialog.cpp +++ b/kcms/keyboard/kcm_add_layout_dialog.cpp @@ -1,178 +1,178 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcm_add_layout_dialog.h" #include #include #include "xkb_rules.h" #include "flags.h" #include "iso_codes.h" #include "ui_kcm_add_layout_dialog.h" #include AddLayoutDialog::AddLayoutDialog(const Rules* rules_, Flags* flags_, const QString& model_, bool showLabel, QWidget* parent): QDialog(parent), rules(rules_), flags(flags_), model(model_), selectedLanguage(QStringLiteral("no_language")) { layoutDialogUi = new Ui_AddLayoutDialog(); layoutDialogUi->setupUi(this); QSet languages; foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { QSet langs = QSet::fromList(layoutInfo->languages); languages.unite( langs ); } IsoCodes isoCodes(IsoCodes::iso_639_3); foreach(const QString& lang, languages) { const IsoCodeEntry* isoCodeEntry = isoCodes.getEntry(IsoCodes::attr_iso_639_3_id, lang); // const IsoCodeEntry* isoCodeEntry = isoCodes.getEntry(IsoCodes::attr_iso_639_2B_code, lang); // if( isoCodeEntry == NULL ) { // isoCodeEntry = isoCodes.getEntry(IsoCodes::attr_iso_639_2T_code, lang); // } QString name = isoCodeEntry != nullptr ? i18n(isoCodeEntry->value(IsoCodes::attr_name).toUtf8()) : lang; layoutDialogUi->languageComboBox->addItem(name, lang); } layoutDialogUi->languageComboBox->model()->sort(0); layoutDialogUi->languageComboBox->insertItem(0, i18n("Any language"), ""); layoutDialogUi->languageComboBox->setCurrentIndex(0); if( showLabel ) { layoutDialogUi->labelEdit->setMaxLength(LayoutUnit::MAX_LABEL_LENGTH); } else { layoutDialogUi->labelLabel->setVisible(false); layoutDialogUi->labelEdit->setVisible(false); } languageChanged(0); connect(layoutDialogUi->languageComboBox, static_cast(&QComboBox::activated), this, &AddLayoutDialog::languageChanged); connect(layoutDialogUi->layoutComboBox, static_cast(&QComboBox::activated), this, &AddLayoutDialog::layoutChanged); #ifdef NEW_GEOMETRY connect(layoutDialogUi->prevbutton, &QPushButton::clicked, this, &AddLayoutDialog::preview); #else layoutDialogUi->prevbutton->setVisible(false); #endif } void AddLayoutDialog::languageChanged(int langIdx) { QString lang = layoutDialogUi->languageComboBox->itemData(langIdx).toString(); if( lang == selectedLanguage ) return; QPixmap emptyPixmap(layoutDialogUi->layoutComboBox->iconSize()); emptyPixmap.fill(Qt::transparent); layoutDialogUi->layoutComboBox->clear(); int defaultIndex = -1; int i = 0; foreach(const LayoutInfo* layoutInfo, rules->layoutInfos) { if( lang.isEmpty() || layoutInfo->isLanguageSupportedByLayout(lang) ) { if( flags ) { QIcon icon(flags->getIcon(layoutInfo->name)); if( icon.isNull() ) { icon = QIcon(emptyPixmap); // align text with no icons } layoutDialogUi->layoutComboBox->addItem(icon, layoutInfo->description, layoutInfo->name); } else { layoutDialogUi->layoutComboBox->addItem(layoutInfo->description, layoutInfo->name); } // try to guess best default layout selection for given language if( ! lang.isEmpty() && defaultIndex == -1 && layoutInfo->isLanguageSupportedByDefaultVariant(lang) ) { defaultIndex = i; } i++; } } if( defaultIndex == -1 ) { defaultIndex = 0; } layoutDialogUi->layoutComboBox->model()->sort(0); layoutDialogUi->layoutComboBox->setCurrentIndex(defaultIndex); layoutChanged(defaultIndex); selectedLanguage = lang; } void AddLayoutDialog::layoutChanged(int layoutIdx) { QString layoutName = layoutDialogUi->layoutComboBox->itemData(layoutIdx).toString(); if( layoutName == selectedLayout ) return; QString lang = layoutDialogUi->languageComboBox->itemData(layoutDialogUi->languageComboBox->currentIndex()).toString(); layoutDialogUi->variantComboBox->clear(); const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutName); foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { if( lang.isEmpty() || layoutInfo->isLanguageSupportedByVariant(variantInfo, lang) ) { layoutDialogUi->variantComboBox->addItem(variantInfo->description, variantInfo->name); } } layoutDialogUi->variantComboBox->model()->sort(0); if( lang.isEmpty() || layoutInfo->isLanguageSupportedByDefaultVariant(lang) ) { layoutDialogUi->variantComboBox->insertItem(0, i18nc("variant", "Default"), ""); } layoutDialogUi->variantComboBox->setCurrentIndex(0); layoutDialogUi->labelEdit->setText(layoutName); selectedLayout = layoutName; } void AddLayoutDialog::accept() { - selectedLayoutUnit.layout = layoutDialogUi->layoutComboBox->itemData(layoutDialogUi->layoutComboBox->currentIndex()).toString(); - selectedLayoutUnit.variant = layoutDialogUi->variantComboBox->itemData(layoutDialogUi->variantComboBox->currentIndex()).toString(); + selectedLayoutUnit.setLayout(layoutDialogUi->layoutComboBox->itemData(layoutDialogUi->layoutComboBox->currentIndex()).toString()); + selectedLayoutUnit.setVariant(layoutDialogUi->variantComboBox->itemData(layoutDialogUi->variantComboBox->currentIndex()).toString()); QString label = layoutDialogUi->labelEdit->text(); - if( label == selectedLayoutUnit.layout ) { + if( label == selectedLayoutUnit.layout() ) { label = QLatin1String(""); } selectedLayoutUnit.setDisplayName( label ); selectedLayoutUnit.setShortcut(layoutDialogUi->kkeysequencewidget->keySequence()); QDialog::accept(); } #ifdef NEW_GEOMETRY void AddLayoutDialog::preview() { int index = layoutDialogUi->variantComboBox->currentIndex(); QString variant = layoutDialogUi->variantComboBox->itemData(index).toString(); KeyboardPainter* layoutPreview = new KeyboardPainter(); QString title = Flags::getLongText(LayoutUnit(selectedLayout, variant), rules); layoutPreview->generateKeyboardLayout(selectedLayout, variant, model, title); layoutPreview->setModal(true); layoutPreview->exec(); delete layoutPreview; } #endif diff --git a/kcms/keyboard/kcm_view_models.cpp b/kcms/keyboard/kcm_view_models.cpp index a6584f026..e75632c59 100644 --- a/kcms/keyboard/kcm_view_models.cpp +++ b/kcms/keyboard/kcm_view_models.cpp @@ -1,521 +1,521 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "kcm_view_models.h" #include #include #include #include #include #include #include #ifdef DRAG_ENABLED #include #endif #include "keyboard_config.h" #include "xkb_rules.h" #include "flags.h" #include "x11_helper.h" #include "bindings.h" const int LayoutsTableModel::MAP_COLUMN = 0; const int LayoutsTableModel::LAYOUT_COLUMN = 1; const int LayoutsTableModel::VARIANT_COLUMN = 2; const int LayoutsTableModel::DISPLAY_NAME_COLUMN = 3; const int LayoutsTableModel::SHORTCUT_COLUMN = 4; static const int COLUMN_COUNT = 5; LayoutsTableModel::LayoutsTableModel(Rules* rules_, Flags *flags_, KeyboardConfig* keyboardConfig_, QObject* parent): QAbstractTableModel(parent), keyboardConfig(keyboardConfig_), rules(rules_), countryFlags(flags_) { } void LayoutsTableModel::refresh() { beginResetModel(); endResetModel(); countryFlags->clearCache(); } int LayoutsTableModel::rowCount(const QModelIndex &/*parent*/) const { return keyboardConfig->layouts.count(); } int LayoutsTableModel::columnCount(const QModelIndex&) const { return COLUMN_COUNT; } Qt::ItemFlags LayoutsTableModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::ItemFlags(); Qt::ItemFlags flags = QAbstractTableModel::flags(index); if( index.column() == DISPLAY_NAME_COLUMN || index.column() == VARIANT_COLUMN || index.column() == SHORTCUT_COLUMN ) { flags |= Qt::ItemIsEditable; } #ifdef DRAG_ENABLED flags |= Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; #endif return flags; } #ifdef DRAG_ENABLED QStringList LayoutsTableModel::mimeTypes() const { QStringList types; types << "application/keyboard-layout-item"; return types; } QMimeData *LayoutsTableModel::mimeData(const QModelIndexList &indexes) const { QMimeData *mimeData = new QMimeData(); QByteArray encodedData; QDataStream stream(&encodedData, QIODevice::WriteOnly); QSet rows; foreach (const QModelIndex& index, indexes) { if (index.isValid()) { rows << index.row(); } } foreach (int row, rows) { stream << row; } mimeData->setData("application/keyboard-layout-item", encodedData); return mimeData; } #endif QVariant LayoutsTableModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) return QVariant(); if (index.row() >= keyboardConfig->layouts.size()) return QVariant(); const LayoutUnit& layoutUnit = keyboardConfig->layouts.at(index.row()); if (role == Qt::DecorationRole) { switch( index.column() ) { case DISPLAY_NAME_COLUMN: { // if( keyboardConfig->isFlagShown() ) { QIcon icon = countryFlags->getIconWithText(layoutUnit, *keyboardConfig); return icon.isNull() ? countryFlags->getTransparentPixmap() : icon; // } } //TODO: show the cells are editable // case VARIANT_COLUMN: { // case DISPLAY_NAME_COLUMN: { // int sz = 5; // QPixmap pm = QPixmap(sz, sz+5); // pm.fill(Qt::transparent); // QPainter p(&pm); // QPoint points[] = { QPoint(0, 0), QPoint(0, sz), QPoint(sz, 0) }; // p.drawPolygon(points, 3); // return pm; // } break; } } else if( role == Qt::BackgroundRole ) { if( keyboardConfig->layoutLoopCount != KeyboardConfig::NO_LOOPING && index.row() >= keyboardConfig->layoutLoopCount ) { return QBrush(Qt::lightGray); } } else if (role == Qt::DisplayRole) { switch( index.column() ) { case MAP_COLUMN: - return layoutUnit.layout; + return layoutUnit.layout(); break; case LAYOUT_COLUMN: { - const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout); - return layoutInfo != nullptr ? layoutInfo->description : layoutUnit.layout; + const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout()); + return layoutInfo != nullptr ? layoutInfo->description : layoutUnit.layout(); } case VARIANT_COLUMN: { - if( layoutUnit.variant.isEmpty() ) + if( layoutUnit.variant().isEmpty() ) return QVariant(); - const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout); + const LayoutInfo* layoutInfo = rules->getLayoutInfo(layoutUnit.layout()); if( layoutInfo == nullptr ) return QVariant(); - const VariantInfo* variantInfo = layoutInfo->getVariantInfo(layoutUnit.variant); - return variantInfo != nullptr ? variantInfo->description : layoutUnit.variant; + const VariantInfo* variantInfo = layoutInfo->getVariantInfo(layoutUnit.variant()); + return variantInfo != nullptr ? variantInfo->description : layoutUnit.variant(); } break; case DISPLAY_NAME_COLUMN: // if( keyboardConfig->indicatorType == KeyboardConfig::SHOW_LABEL ) { // return layoutUnit.getDisplayName(); // } break; case SHORTCUT_COLUMN: { return layoutUnit.getShortcut().toString(); } break; } } else if (role==Qt::EditRole ) { switch( index.column() ) { case DISPLAY_NAME_COLUMN: return layoutUnit.getDisplayName(); break; case VARIANT_COLUMN: - return layoutUnit.variant; + return layoutUnit.variant(); break; case SHORTCUT_COLUMN: return layoutUnit.getShortcut().toString(); break; default:; } } else if( role == Qt::TextAlignmentRole ) { switch( index.column() ) { case MAP_COLUMN: case DISPLAY_NAME_COLUMN: case SHORTCUT_COLUMN: return Qt::AlignCenter; break; default:; } } return QVariant(); } QVariant LayoutsTableModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role != Qt::DisplayRole) return QVariant(); if (orientation == Qt::Horizontal) { const QString headers[] = {i18nc("layout map name", "Map"), i18n("Layout"), i18n("Variant"), i18n("Label"), i18n("Shortcut")}; return headers[section]; } return QVariant(); } bool LayoutsTableModel::setData(const QModelIndex &index, const QVariant &value, int role) { if (role != Qt::EditRole || (index.column() != DISPLAY_NAME_COLUMN && index.column() != VARIANT_COLUMN && index.column() != SHORTCUT_COLUMN) ) return false; if (index.row() >= keyboardConfig->layouts.size() || index.data(role) == value) return false; LayoutUnit& layoutUnit = keyboardConfig->layouts[index.row()]; switch( index.column() ) { case DISPLAY_NAME_COLUMN: { QString displayText = value.toString().left(3); layoutUnit.setDisplayName(displayText); countryFlags->clearCache(); // regenerate the label } break; case VARIANT_COLUMN: { QString variant = value.toString(); - layoutUnit.variant = variant; + layoutUnit.setVariant(variant); } break; case SHORTCUT_COLUMN: { QString shortcut = value.toString(); layoutUnit.setShortcut(QKeySequence(shortcut)); } break; } emit dataChanged(index, index); return true; } // // LabelEditDelegate // LabelEditDelegate::LabelEditDelegate(const KeyboardConfig* keyboardConfig_, QObject *parent): QStyledItemDelegate(parent), keyboardConfig(keyboardConfig_) {} QWidget *LabelEditDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option , const QModelIndex & index ) const { if( keyboardConfig->indicatorType == KeyboardConfig::SHOW_FLAG ) return nullptr; QWidget* widget = QStyledItemDelegate::createEditor(parent, option, index); QLineEdit* lineEdit = static_cast(widget); if( lineEdit != nullptr ) { lineEdit->setMaxLength(LayoutUnit::MAX_LABEL_LENGTH); connect(lineEdit, &QLineEdit::textEdited, this, [this, lineEdit]() { Q_EMIT const_cast(this)->commitData(lineEdit); }); } return widget; } void LabelEditDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } //void LabelEditDelegate::paint( QPainter * painter, const QStyleOptionViewItem & option, const QModelIndex & index ) const //{ // QStyleOptionViewItem option2(option); //// option2.decorationPosition = QStyleOptionViewItem::Right; // option2.decorationAlignment = Qt::AlignHCenter | Qt::AlignVCenter; // QStyledItemDelegate::paint(painter, option2, index); //} // // VariantComboDelegate // //TODO: reuse this function in kcm_add_layout_dialog.cpp static void populateComboWithVariants(QComboBox* combo, const QString& layout, const Rules* rules) { combo->clear(); const LayoutInfo* layoutInfo = rules->getLayoutInfo(layout); foreach(const VariantInfo* variantInfo, layoutInfo->variantInfos) { combo->addItem(variantInfo->description, variantInfo->name); } combo->model()->sort(0); combo->insertItem(0, i18nc("variant", "Default"), ""); combo->setCurrentIndex(0); } VariantComboDelegate::VariantComboDelegate(const KeyboardConfig* keyboardConfig_, const Rules* rules_, QObject *parent): QStyledItemDelegate(parent), keyboardConfig(keyboardConfig_), rules(rules_) {} QWidget *VariantComboDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &/* option */, const QModelIndex & index ) const { QComboBox *editor = new QComboBox(parent); const LayoutUnit& layoutUnit = keyboardConfig->layouts[index.row()]; - populateComboWithVariants(editor, layoutUnit.layout, rules); + populateComboWithVariants(editor, layoutUnit.layout(), rules); connect(editor, &QComboBox::currentTextChanged, this, [this, editor]() { Q_EMIT const_cast(this)->commitData(editor); }); return editor; } void VariantComboDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const { QComboBox *combo = static_cast(editor); QString variant = index.model()->data(index, Qt::EditRole).toString(); int itemIndex = combo->findData(variant); if( itemIndex == -1 ) { itemIndex = 0; } combo->setCurrentIndex(itemIndex); } void VariantComboDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { QComboBox *combo = static_cast(editor); QString variant = combo->itemData(combo->currentIndex()).toString(); model->setData(index, variant, Qt::EditRole); } void VariantComboDelegate::updateEditorGeometry(QWidget *editor, const QStyleOptionViewItem &option, const QModelIndex &/* index */) const { editor->setGeometry(option.rect); } // // KKeySequenceWidgetDelegate // KKeySequenceWidgetDelegate::KKeySequenceWidgetDelegate(const KeyboardConfig* keyboardConfig_, QObject *parent): QStyledItemDelegate(parent), keyboardConfig(keyboardConfig_) {} QWidget *KKeySequenceWidgetDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /*option*/, const QModelIndex & index ) const { itemsBeingEdited.insert(index); KKeySequenceWidget *editor = new KKeySequenceWidget(parent); editor->setFocusPolicy(Qt::StrongFocus); editor->setModifierlessAllowed(false); const LayoutUnit& layoutUnit = keyboardConfig->layouts[index.row()]; editor->setKeySequence(layoutUnit.getShortcut()); editor->captureKeySequence(); connect(editor, &KKeySequenceWidget::keySequenceChanged, this, [this, editor]() { Q_EMIT const_cast(this)->commitData(editor); }); return editor; } //void KKeySequenceWidgetDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const //{ // KKeySequenceWidget *kkeysequencewidget = static_cast(editor); // QString shortcut = index.model()->data(index, Qt::EditRole).toString(); // kkeysequencewidget->setKeySequence(QKeySequence(shortcut)); // kkeysequencewidget->captureKeySequence(); // qDebug() << "set editor data"; //} void KKeySequenceWidgetDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const { KKeySequenceWidget *kkeysequencewidget = static_cast(editor); QString shortcut = kkeysequencewidget->keySequence().toString(); model->setData(index, shortcut, Qt::EditRole); itemsBeingEdited.remove(index); } void KKeySequenceWidgetDelegate::paint(QPainter* painter, const QStyleOptionViewItem& option, const QModelIndex& index) const { if (itemsBeingEdited.contains(index)) { // StyledBackgroundPainter::drawBackground(painter,option,index); } else { QStyledItemDelegate::paint(painter,option,index); } } // // Xkb Options Tree View // int XkbOptionsTreeModel::rowCount(const QModelIndex& parent) const { if( ! parent.isValid() ) return rules->optionGroupInfos.count(); if( ! parent.parent().isValid() ) return rules->optionGroupInfos[parent.row()]->optionInfos.count(); return 0; } QVariant XkbOptionsTreeModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) return QVariant(); int row = index.row(); if (role == Qt::DisplayRole) { if( ! index.parent().isValid() ) { return rules->optionGroupInfos[row]->description; } else { int groupRow = index.parent().row(); const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; return xkbGroup->optionInfos[row]->description; } } else if (role==Qt::CheckStateRole ) { if( index.parent().isValid() ) { int groupRow = index.parent().row(); const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; const QString& xkbOptionName = xkbGroup->optionInfos[row]->name; return keyboardConfig->xkbOptions.indexOf(xkbOptionName) == -1 ? Qt::Unchecked : Qt::Checked; } else { int groupRow = index.row(); const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; foreach(const OptionInfo* optionInfo, xkbGroup->optionInfos) { if( keyboardConfig->xkbOptions.indexOf(optionInfo->name) != -1 ) return Qt::PartiallyChecked; } return Qt::Unchecked; } } return QVariant(); } bool XkbOptionsTreeModel::setData(const QModelIndex & index, const QVariant & value, int role) { int groupRow = index.parent().row(); if( groupRow < 0 ) return false; const OptionGroupInfo* xkbGroup = rules->optionGroupInfos[groupRow]; const OptionInfo* option = xkbGroup->optionInfos[index.row()]; if( value.toInt() == Qt::Checked ) { if( xkbGroup->exclusive ) { // clear if exclusive (TODO: radiobutton) int idx = keyboardConfig->xkbOptions.indexOf(QRegExp(xkbGroup->name + ".*")); if( idx >= 0 ) { for(int i=0; ioptionInfos.count(); i++) if( xkbGroup->optionInfos[i]->name == keyboardConfig->xkbOptions[idx] ) { setData(createIndex(i, index.column(), static_cast(index.internalId()) - index.row() + i), Qt::Unchecked, role); break; } // m_kxkbConfig->m_options.removeAt(idx); // idx = m_kxkbConfig->m_options.indexOf(QRegExp(xkbGroupNm+".*")); } } if( keyboardConfig->xkbOptions.indexOf(option->name) < 0 ) { keyboardConfig->xkbOptions.append(option->name); } } else { keyboardConfig->xkbOptions.removeAll(option->name); } emit dataChanged(index, index); emit dataChanged(index.parent(), index.parent()); return true; } void XkbOptionsTreeModel::gotoGroup(const QString& groupName, QTreeView* view) { const OptionGroupInfo* optionGroupInfo = rules->getOptionGroupInfo(groupName); int index = rules->optionGroupInfos.indexOf(const_cast(optionGroupInfo)); if( index != -1 ) { QModelIndex modelIdx = createIndex(index,0); // view->selectionModel()->setCurrentIndex(createIndex(index,0), QItemSelectionModel::NoUpdate); view->setExpanded(modelIdx, true); view->scrollTo(modelIdx, QAbstractItemView::PositionAtTop); view->selectionModel()->setCurrentIndex(modelIdx, QItemSelectionModel::Current); view->setFocus(Qt::OtherFocusReason); } // else { // qDebug() << "can't scroll to group" << group; // } } diff --git a/kcms/keyboard/keyboard_config.cpp b/kcms/keyboard/keyboard_config.cpp index 3d1200f34..10ed657c6 100644 --- a/kcms/keyboard/keyboard_config.cpp +++ b/kcms/keyboard/keyboard_config.cpp @@ -1,213 +1,213 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "keyboard_config.h" #include "debug.h" #include #include static const char* const SWITCHING_POLICIES[] = {"Global", "Desktop", "WinClass", "Window", nullptr }; static const char LIST_SEPARATOR[] = ","; //static const char* DEFAULT_LAYOUT = "us"; static const char DEFAULT_MODEL[] = "pc104"; static const QString CONFIG_FILENAME(QStringLiteral("kxkbrc")); static const QString CONFIG_GROUPNAME(QStringLiteral("Layout")); const int KeyboardConfig::NO_LOOPING = -1; KeyboardConfig::KeyboardConfig() { setDefaults(); } QString KeyboardConfig::getSwitchingPolicyString(SwitchingPolicy switchingPolicy) { return SWITCHING_POLICIES[switchingPolicy]; } static int findStringIndex(const char* const strings[], const QString& toFind, int defaultIndex) { for(int i=0; strings[i] != nullptr; i++) { if( toFind == strings[i] ) { return i; } } return defaultIndex; } void KeyboardConfig::setDefaults() { keyboardModel = DEFAULT_MODEL; resetOldXkbOptions = false; xkbOptions.clear(); // init layouts options configureLayouts = false; layouts.clear(); // layouts.append(LayoutUnit(DEFAULT_LAYOUT)); layoutLoopCount = NO_LOOPING; // switch control options switchingPolicy = SWITCH_POLICY_GLOBAL; // stickySwitching = false; // stickySwitchingDepth = 2; // display options showIndicator = true; indicatorType = SHOW_LABEL; showSingle = false; } static KeyboardConfig::IndicatorType getIndicatorType(bool showFlag, bool showLabel) { if( showFlag ) { if( showLabel ) return KeyboardConfig::SHOW_LABEL_ON_FLAG; else return KeyboardConfig::SHOW_FLAG; } else { return KeyboardConfig::SHOW_LABEL; } } void KeyboardConfig::load() { KConfigGroup config(KSharedConfig::openConfig( CONFIG_FILENAME, KConfig::NoGlobals ), CONFIG_GROUPNAME); keyboardModel = config.readEntry("Model", ""); resetOldXkbOptions = config.readEntry("ResetOldOptions", false); QString options = config.readEntry("Options", ""); xkbOptions = options.split(LIST_SEPARATOR, QString::SkipEmptyParts); configureLayouts = config.readEntry("Use", false); QString layoutsString = config.readEntry("LayoutList", ""); QStringList layoutStrings = layoutsString.split(LIST_SEPARATOR, QString::SkipEmptyParts); // if( layoutStrings.isEmpty() ) { // layoutStrings.append(DEFAULT_LAYOUT); // } layouts.clear(); if (layoutStrings.isEmpty()) { QList x11layouts = X11Helper::getLayoutsList(); for (const LayoutUnit& layoutUnit : x11layouts) { layouts.append(layoutUnit); } } else { for (const QString& layoutString : layoutStrings) { layouts.append(LayoutUnit(layoutString)); } } configureLayouts = !layouts.isEmpty(); layoutLoopCount = config.readEntry("LayoutLoopCount", NO_LOOPING); QString layoutMode = config.readEntry("SwitchMode", "Global"); switchingPolicy = static_cast(findStringIndex(SWITCHING_POLICIES, layoutMode, SWITCH_POLICY_GLOBAL)); showIndicator = config.readEntry("ShowLayoutIndicator", true); bool showFlag = config.readEntry("ShowFlag", false); bool showLabel = config.readEntry("ShowLabel", true); indicatorType = getIndicatorType(showFlag, showLabel); showSingle = config.readEntry("ShowSingle", false); QString labelsStr = config.readEntry("DisplayNames", ""); QStringList labels = labelsStr.split(LIST_SEPARATOR, QString::KeepEmptyParts); for(int i=0; i KeyboardConfig::getDefaultLayouts() const { QList defaultLayoutList; int i = 0; foreach(const LayoutUnit& layoutUnit, layouts) { defaultLayoutList.append(layoutUnit); if( layoutLoopCount != KeyboardConfig::NO_LOOPING && i >= layoutLoopCount-1 ) break; i++; } return defaultLayoutList; } QList KeyboardConfig::getExtraLayouts() const { if( layoutLoopCount == KeyboardConfig::NO_LOOPING ) return QList(); return layouts.mid(layoutLoopCount, layouts.size()); } diff --git a/kcms/keyboard/layout_tray_icon.cpp b/kcms/keyboard/layout_tray_icon.cpp index f5281b694..4c41fb67b 100644 --- a/kcms/keyboard/layout_tray_icon.cpp +++ b/kcms/keyboard/layout_tray_icon.cpp @@ -1,126 +1,126 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "layout_tray_icon.h" #include #include #include #include "xkb_rules.h" #include "x11_helper.h" #include "xkb_helper.h" #include "keyboard_config.h" #include "flags.h" #include "layouts_menu.h" // // Layout Tray Icon // LayoutTrayIcon::LayoutTrayIcon(const Rules* rules_, const KeyboardConfig& keyboardConfig_): keyboardConfig(keyboardConfig_), rules(rules_), flags(new Flags()), layoutsMenu(new LayoutsMenu(keyboardConfig_, *rules, *flags)) { m_notifierItem = new KStatusNotifierItem(this); m_notifierItem->setCategory(KStatusNotifierItem::Hardware); m_notifierItem->setStatus(KStatusNotifierItem::Active); m_notifierItem->setToolTipTitle(i18nc("tooltip title", "Keyboard Layout")); m_notifierItem->setTitle(i18nc("tooltip title", "Keyboard Layout")); m_notifierItem->setToolTipIconByName(QStringLiteral("preferences-desktop-keyboard")); QMenu* menu = new QMenu(QLatin1String("")); m_notifierItem->setContextMenu(menu); m_notifierItem->setStandardActionsEnabled(false); layoutMapChanged(); m_notifierItem->setStatus(KStatusNotifierItem::Active); init(); } LayoutTrayIcon::~LayoutTrayIcon() { destroy(); delete flags; delete layoutsMenu; } void LayoutTrayIcon::init() { connect(m_notifierItem, &KStatusNotifierItem::activateRequested, this, &LayoutTrayIcon::toggleLayout); connect(m_notifierItem, &KStatusNotifierItem::scrollRequested, this, &LayoutTrayIcon::scrollRequested); connect(flags, &Flags::pixmapChanged, this, &LayoutTrayIcon::layoutChanged); } void LayoutTrayIcon::destroy() { disconnect(flags, &Flags::pixmapChanged, this, &LayoutTrayIcon::layoutChanged); disconnect(m_notifierItem, &KStatusNotifierItem::scrollRequested, this, &LayoutTrayIcon::scrollRequested); disconnect(m_notifierItem, &KStatusNotifierItem::activateRequested, this, &LayoutTrayIcon::toggleLayout); } void LayoutTrayIcon::layoutMapChanged() { flags->clearCache(); QMenu* menu = m_notifierItem->contextMenu(); menu->clear(); QList actions = layoutsMenu->contextualActions(); menu->addActions(actions); layoutChanged(); } void LayoutTrayIcon::layoutChanged() { LayoutUnit layoutUnit = X11Helper::getCurrentLayout(); if( layoutUnit.isEmpty() ) return; // QString shortText = Flags::getShortText(layoutUnit, *keyboardConfig); // qDebug() << "systray: LayoutChanged" << layoutUnit.toString() << shortText; QString longText = Flags::getLongText(layoutUnit, rules); m_notifierItem->setToolTipSubTitle(longText); - const QIcon icon(getFlag(layoutUnit.layout)); + const QIcon icon(getFlag(layoutUnit.layout())); m_notifierItem->setToolTipIconByPixmap(icon); QIcon textOrIcon = flags->getIconWithText(layoutUnit, keyboardConfig); m_notifierItem->setIconByPixmap( textOrIcon ); } void LayoutTrayIcon::toggleLayout() { X11Helper::switchToNextLayout(); } void LayoutTrayIcon::scrollRequested(int delta, Qt::Orientation /*orientation*/) { X11Helper::scrollLayouts(delta > 0 ? 1 : -1); } const QIcon LayoutTrayIcon::getFlag(const QString& layout) const { return keyboardConfig.isFlagShown() ? flags->getIcon(layout) : QIcon::fromTheme(QStringLiteral("preferences-desktop-keyboard")); } diff --git a/kcms/keyboard/layouts_menu.cpp b/kcms/keyboard/layouts_menu.cpp index 733826bec..71666a64b 100644 --- a/kcms/keyboard/layouts_menu.cpp +++ b/kcms/keyboard/layouts_menu.cpp @@ -1,140 +1,140 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "layouts_menu.h" #include "debug.h" #include #include #include #include "keyboard_config.h" #include "x11_helper.h" #include "xkb_helper.h" #include "flags.h" LayoutsMenu::LayoutsMenu(const KeyboardConfig& keyboardConfig_, const Rules& rules_, Flags& flags_): keyboardConfig(keyboardConfig_), rules(rules_), flags(flags_), actionGroup(nullptr) { } LayoutsMenu::~LayoutsMenu() { delete actionGroup; } const QIcon LayoutsMenu::getFlag(const QString& layout) const { return keyboardConfig.isFlagShown() ? flags.getIcon(layout) : QIcon(); } void LayoutsMenu::actionTriggered(QAction* action) { QString data = action->data().toString(); if( data == QLatin1String("config") ) { QStringList args; args << QStringLiteral("--args=--tab=layouts"); args << QStringLiteral("kcm_keyboard"); KToolInvocation::kdeinitExec(QStringLiteral("kcmshell5"), args); } else { LayoutUnit layoutUnit(LayoutUnit(action->data().toString())); switchToLayout(layoutUnit, keyboardConfig); } } int LayoutsMenu::switchToLayout(const LayoutUnit& layoutUnit, const KeyboardConfig& keyboardConfig) { QList layouts = X11Helper::getCurrentLayouts().layouts; bool res; if( layouts.contains(layoutUnit) ) { res = X11Helper::setLayout(layoutUnit); } else if ( keyboardConfig.layouts.contains(layoutUnit) ) { QList layouts(keyboardConfig.getDefaultLayouts()); layouts.removeLast(); layouts.append(layoutUnit); XkbHelper::initializeKeyboardLayouts(layouts); res = X11Helper::setLayout(layoutUnit); } else { qCWarning(KCM_KEYBOARD) << "switchToLayout with unknown layout" << layoutUnit.toString(); res = -1; } return res; } QAction* LayoutsMenu::createAction(const LayoutUnit& layoutUnit) const { QString menuText = Flags::getFullText(layoutUnit, keyboardConfig, &rules); - QAction* action = new QAction(getFlag(layoutUnit.layout), menuText, actionGroup); + QAction* action = new QAction(getFlag(layoutUnit.layout()), menuText, actionGroup); action->setData(layoutUnit.toString()); //FIXME: tooltips don't work on dbusmenus??? // if( ! layoutUnit.getShortcut().isEmpty() ) { // action->setToolTip(layoutUnit.getShortcut().toString()); // } return action; } QList LayoutsMenu::contextualActions() { if( actionGroup ) { disconnect(actionGroup, &QActionGroup::triggered, this, &LayoutsMenu::actionTriggered); delete actionGroup; } actionGroup = new QActionGroup(this); X11Helper::getLayoutsList(); //UGLY: seems to be more reliable with extra call QList currentLayouts = X11Helper::getLayoutsList(); foreach(const LayoutUnit& layoutUnit, currentLayouts) { QAction* action = createAction(layoutUnit); actionGroup->addAction(action); } if( keyboardConfig.configureLayouts ) { QList extraLayouts = keyboardConfig.layouts; foreach(const LayoutUnit& layoutUnit, currentLayouts) { extraLayouts.removeOne(layoutUnit); } if( extraLayouts.size() > 0 ) { QAction* separator = new QAction(actionGroup); separator->setSeparator(true); actionGroup->addAction(separator); foreach(const LayoutUnit& layoutUnit, extraLayouts) { QAction* action = createAction(layoutUnit); actionGroup->addAction(action); } } } QAction* separator = new QAction(actionGroup); separator->setSeparator(true); actionGroup->addAction(separator); QAction* configAction = new QAction(QIcon::fromTheme(QStringLiteral("configure")), i18n("Configure Layouts..."), actionGroup); actionGroup->addAction(configAction); configAction->setData("config"); connect(actionGroup, &QActionGroup::triggered, this, &LayoutsMenu::actionTriggered); return actionGroup->actions(); } diff --git a/kcms/keyboard/x11_helper.cpp b/kcms/keyboard/x11_helper.cpp index bd60313b0..a0808bf09 100644 --- a/kcms/keyboard/x11_helper.cpp +++ b/kcms/keyboard/x11_helper.cpp @@ -1,447 +1,447 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "x11_helper.h" #include "debug.h" #include #include #include #include #include #include #include #include #include // more information about the limit https://bugs.freedesktop.org/show_bug.cgi?id=19501 const int X11Helper::MAX_GROUP_COUNT = 4; const int X11Helper::ARTIFICIAL_GROUP_LIMIT_COUNT = 8; const char X11Helper::LEFT_VARIANT_STR[] = "("; const char X11Helper::RIGHT_VARIANT_STR[] = ")"; bool X11Helper::xkbSupported(int* xkbOpcode) { if (!QX11Info::isPlatformX11()) { return false; } // Verify the Xlib has matching XKB extension. int major = XkbMajorVersion; int minor = XkbMinorVersion; if (!XkbLibraryVersion(&major, &minor)) { qCWarning(KCM_KEYBOARD) << "Xlib XKB extension " << major << '.' << minor << " != " << XkbMajorVersion << '.' << XkbMinorVersion; return false; } // Verify the X server has matching XKB extension. int opcode_rtrn; int error_rtrn; int xkb_opcode; if( ! XkbQueryExtension(QX11Info::display(), &opcode_rtrn, &xkb_opcode, &error_rtrn, &major, &minor)) { qCWarning(KCM_KEYBOARD) << "X server XKB extension " << major << '.' << minor << " != " << XkbMajorVersion << '.' << XkbMinorVersion; return false; } if( xkbOpcode != nullptr ) { *xkbOpcode = xkb_opcode; } return true; } void X11Helper::switchToNextLayout() { int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count int group = (X11Helper::getGroup() + 1) % size; X11Helper::setGroup(group); } void X11Helper::scrollLayouts(int delta) { int size = getLayoutsList().size(); //TODO: could optimize a bit as we don't need the layouts - just count int group = X11Helper::getGroup() + delta; group = group < 0 ? size - ((-group) % size) : group % size; X11Helper::setGroup(group); } QStringList X11Helper::getLayoutsListAsString(const QList& layoutsList) { QStringList stringList; foreach(const LayoutUnit& layoutUnit, layoutsList) { stringList << layoutUnit.toString(); } return stringList; } bool X11Helper::setLayout(const LayoutUnit& layout) { QList currentLayouts = getLayoutsList(); int idx = currentLayouts.indexOf(layout); if( idx == -1 || idx >= X11Helper::MAX_GROUP_COUNT ) { qCWarning(KCM_KEYBOARD) << "Layout" << layout.toString() << "is not found in current layout list" << getLayoutsListAsString(currentLayouts); return false; } return X11Helper::setGroup((unsigned int)idx); } bool X11Helper::setDefaultLayout() { return X11Helper::setGroup(0); } bool X11Helper::isDefaultLayout() { return X11Helper::getGroup() == 0; } LayoutUnit X11Helper::getCurrentLayout() { if (!QX11Info::isPlatformX11()) { return LayoutUnit(); } QList currentLayouts = getLayoutsList(); unsigned int group = X11Helper::getGroup(); if( group < static_cast(currentLayouts.size()) ) return currentLayouts.at(static_cast(group)); qCWarning(KCM_KEYBOARD) << "Current group number" << group << "is outside of current layout list" << getLayoutsListAsString(currentLayouts); return LayoutUnit(); } LayoutSet X11Helper::getCurrentLayouts() { LayoutSet layoutSet; QList currentLayouts = getLayoutsList(); layoutSet.layouts = currentLayouts; unsigned int group = X11Helper::getGroup(); if( group < (unsigned int)currentLayouts.size() ) { layoutSet.currentLayout = currentLayouts[group]; } else { qCWarning(KCM_KEYBOARD) << "Current group number" << group << "is outside of current layout list" << getLayoutsListAsString(currentLayouts); layoutSet.currentLayout = LayoutUnit(); } return layoutSet; } //static QString addNum(const QString& str, int n) //{ // QString format("%1%2"); // if( str.length() >= 3 ) return format.arg(str.left(2)).arg(n); // return format.arg(str).arg(n); //} QList X11Helper::getLayoutsList() { if (!QX11Info::isPlatformX11()) { return QList(); } XkbConfig xkbConfig; QList layouts; if( X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::LAYOUTS_ONLY) ) { for(int i=0; ierror_code; return false; } return true; } unsigned int X11Helper::getGroup() { XkbStateRec xkbState; XkbGetState( QX11Info::display(), XkbUseCoreKbd, &xkbState ); return xkbState.group; } bool X11Helper::getGroupNames(Display* display, XkbConfig* xkbConfig, FetchType fetchType) { static const char OPTIONS_SEPARATOR[] = ","; Atom real_prop_type; int fmt; unsigned long nitems, extra_bytes; char *prop_data = nullptr; Status ret; Atom rules_atom = XInternAtom(display, _XKB_RF_NAMES_PROP_ATOM, False); /* no such atom! */ if (rules_atom == None) { /* property cannot exist */ qCWarning(KCM_KEYBOARD) << "Failed to fetch layouts from server:" << "could not find the atom" << _XKB_RF_NAMES_PROP_ATOM; return false; } ret = XGetWindowProperty(display, DefaultRootWindow(display), rules_atom, 0L, _XKB_RF_NAMES_PROP_MAXLEN, False, XA_STRING, &real_prop_type, &fmt, &nitems, &extra_bytes, (unsigned char **) (void *) &prop_data); /* property not found! */ if (ret != Success) { qCWarning(KCM_KEYBOARD) << "Failed to fetch layouts from server:" << "Could not get the property"; return false; } /* has to be array of strings */ if ((extra_bytes > 0) || (real_prop_type != XA_STRING) || (fmt != 8)) { if (prop_data) XFree(prop_data); qCWarning(KCM_KEYBOARD) << "Failed to fetch layouts from server:" << "Wrong property format"; return false; } // qCDebug(KCM_KEYBOARD) << "prop_data:" << nitems << prop_data; QStringList names; for(char* p=prop_data; p-prop_data < (long)nitems && p != nullptr; p += strlen(p)+1) { names.append( p ); // qDebug() << " " << p; } if( names.count() < 4 ) { //{ rules, model, layouts, variants, options } XFree(prop_data); return false; } if( fetchType == ALL || fetchType == LAYOUTS_ONLY ) { QStringList layouts = names[2].split(OPTIONS_SEPARATOR); QStringList variants = names[3].split(OPTIONS_SEPARATOR); for(int ii=0; iilayouts << (layouts[ii] != nullptr ? layouts[ii] : QLatin1String("")); xkbConfig->variants << (ii < variants.count() && variants[ii] != nullptr ? variants[ii] : QLatin1String("")); } qCDebug(KCM_KEYBOARD) << "Fetched layout groups from X server:" << "\tlayouts:" << xkbConfig->layouts << "\tvariants:" << xkbConfig->variants; } if( fetchType == ALL || fetchType == MODEL_ONLY ) { xkbConfig->keyboardModel = (names[1] != nullptr ? names[1] : QLatin1String("")); qCDebug(KCM_KEYBOARD) << "Fetched keyboard model from X server:" << xkbConfig->keyboardModel; } if( fetchType == ALL ) { if( names.count() >= 5 ) { QString options = (names[4] != nullptr ? names[4] : QLatin1String("")); xkbConfig->options = options.split(OPTIONS_SEPARATOR); qCDebug(KCM_KEYBOARD) << "Fetched xkbOptions from X server:" << options; } } XFree(prop_data); return true; } XEventNotifier::XEventNotifier(): xkbOpcode(-1) { if( QCoreApplication::instance() == nullptr ) { qCWarning(KCM_KEYBOARD) << "Layout Widget won't work properly without QCoreApplication instance"; } } void XEventNotifier::start() { qCDebug(KCM_KEYBOARD) << "qCoreApp" << QCoreApplication::instance(); if( QCoreApplication::instance() != nullptr && X11Helper::xkbSupported(&xkbOpcode) ) { registerForXkbEvents(QX11Info::display()); // start the event loop QCoreApplication::instance()->installNativeEventFilter(this); } } void XEventNotifier::stop() { if( QCoreApplication::instance() != nullptr ) { //TODO: unregister // XEventNotifier::unregisterForXkbEvents(QX11Info::display()); // stop the event loop QCoreApplication::instance()->removeNativeEventFilter(this); } } bool XEventNotifier::isXkbEvent(xcb_generic_event_t* event) { // qDebug() << "event response type:" << (event->response_type & ~0x80) << xkbOpcode << ((event->response_type & ~0x80) == xkbOpcode + XkbEventCode); return (event->response_type & ~0x80) == xkbOpcode + XkbEventCode; } bool XEventNotifier::processOtherEvents(xcb_generic_event_t* /*event*/) { return true; } bool XEventNotifier::processXkbEvents(xcb_generic_event_t* event) { _xkb_event *xkbevt = reinterpret_cast<_xkb_event *>(event); if( XEventNotifier::isGroupSwitchEvent(xkbevt) ) { // qDebug() << "group switch event"; emit(layoutChanged()); } else if( XEventNotifier::isLayoutSwitchEvent(xkbevt) ) { // qDebug() << "layout switch event"; emit(layoutMapChanged()); } return true; } bool XEventNotifier::nativeEventFilter(const QByteArray &eventType, void *message, long *) { // qDebug() << "event type:" << eventType; if (eventType == "xcb_generic_event_t") { xcb_generic_event_t* ev = static_cast(message); if( isXkbEvent(ev) ) { processXkbEvents(ev); } else { processOtherEvents(ev); } } return false; } //bool XEventNotifier::x11Event(XEvent * event) //{ // // qApp->x11ProcessEvent ( event ); // if( isXkbEvent(event) ) { // processXkbEvents(event); // } // else { // processOtherEvents(event); // } // return QWidget::x11Event(event); //} bool XEventNotifier::isGroupSwitchEvent(_xkb_event* xkbEvent) { // XkbEvent *xkbEvent = (XkbEvent*) event; #define GROUP_CHANGE_MASK \ ( XkbGroupStateMask | XkbGroupBaseMask | XkbGroupLatchMask | XkbGroupLockMask ) return xkbEvent->any.xkbType == XkbStateNotify && (xkbEvent->state_notify.changed & GROUP_CHANGE_MASK); } bool XEventNotifier::isLayoutSwitchEvent(_xkb_event* xkbEvent) { // XkbEvent *xkbEvent = (XkbEvent*) event; return //( (xkbEvent->any.xkb_type == XkbMapNotify) && (xkbEvent->map.changed & XkbKeySymsMask) ) || /* || ( (xkbEvent->any.xkb_type == XkbNamesNotify) && (xkbEvent->names.changed & XkbGroupNamesMask) || )*/ (xkbEvent->any.xkbType == XkbNewKeyboardNotify); } int XEventNotifier::registerForXkbEvents(Display* display) { int eventMask = XkbNewKeyboardNotifyMask | XkbStateNotifyMask; if( ! XkbSelectEvents(display, XkbUseCoreKbd, eventMask, eventMask) ) { qCWarning(KCM_KEYBOARD) << "Couldn't select desired XKB events"; return false; } return true; } static const char LAYOUT_VARIANT_SEPARATOR_PREFIX[] = "("; static const char LAYOUT_VARIANT_SEPARATOR_SUFFIX[] = ")"; static QString& stripVariantName(QString& variant) { if( variant.endsWith(LAYOUT_VARIANT_SEPARATOR_SUFFIX) ) { int suffixLen = strlen(LAYOUT_VARIANT_SEPARATOR_SUFFIX); return variant.remove(variant.length()-suffixLen, suffixLen); } return variant; } LayoutUnit::LayoutUnit(const QString& fullLayoutName) { QStringList lv = fullLayoutName.split(LAYOUT_VARIANT_SEPARATOR_PREFIX); - layout = lv[0]; - variant = lv.size() > 1 ? stripVariantName(lv[1]) : QLatin1String(""); + m_layout = lv[0]; + m_variant = lv.size() > 1 ? stripVariantName(lv[1]) : QLatin1String(""); } QString LayoutUnit::toString() const { - if( variant.isEmpty() ) - return layout; + if( m_variant.isEmpty() ) + return m_layout; - return layout + LAYOUT_VARIANT_SEPARATOR_PREFIX+variant+LAYOUT_VARIANT_SEPARATOR_SUFFIX; + return m_layout + LAYOUT_VARIANT_SEPARATOR_PREFIX + m_variant + LAYOUT_VARIANT_SEPARATOR_SUFFIX; } const int LayoutUnit::MAX_LABEL_LENGTH = 3; diff --git a/kcms/keyboard/x11_helper.h b/kcms/keyboard/x11_helper.h index e6708e399..23b03e3e7 100644 --- a/kcms/keyboard/x11_helper.h +++ b/kcms/keyboard/x11_helper.h @@ -1,212 +1,215 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #ifndef X11_HELPER_H_ #define X11_HELPER_H_ #include #include #include #include #include #include #define explicit explicit_is_keyword_in_cpp #include #include #undef explicit namespace { typedef union { /* All XKB events share these fields. */ struct { uint8_t response_type; uint8_t xkbType; uint16_t sequence; xcb_timestamp_t time; uint8_t deviceID; } any; xcb_xkb_new_keyboard_notify_event_t new_keyboard_notify; xcb_xkb_map_notify_event_t map_notify; xcb_xkb_state_notify_event_t state_notify; } _xkb_event; } class XEventNotifier : public QObject, public QAbstractNativeEventFilter { Q_OBJECT Q_SIGNALS: void layoutChanged(); void layoutMapChanged(); public: XEventNotifier(); ~XEventNotifier() override {} virtual void start(); virtual void stop(); protected: // bool x11Event(XEvent * e); virtual bool processOtherEvents(xcb_generic_event_t* e); virtual bool processXkbEvents(xcb_generic_event_t* e); bool nativeEventFilter(const QByteArray &eventType, void *message, long *) override; private: int registerForXkbEvents(Display* display); bool isXkbEvent(xcb_generic_event_t* event); bool isGroupSwitchEvent(_xkb_event* event); bool isLayoutSwitchEvent(_xkb_event* event); int xkbOpcode; }; struct XkbConfig { QString keyboardModel; QStringList layouts; QStringList variants; QStringList options; bool isValid() { return ! layouts.empty(); } }; -struct LayoutUnit { - static const int MAX_LABEL_LENGTH; - - //TODO: move these to private? - QString layout; - QString variant; - - LayoutUnit() {} - explicit LayoutUnit(const QString& fullLayoutName); - LayoutUnit(const QString& layout_, const QString& variant_) { - layout = layout_; - variant = variant_; - } +class LayoutUnit { +public: + static const int MAX_LABEL_LENGTH; + + LayoutUnit() {} + explicit LayoutUnit(const QString& fullLayoutName); + LayoutUnit(const QString& layout, const QString& variant) { + m_layout = layout; + m_variant = variant; + } /*explicit*/ LayoutUnit(const LayoutUnit& other) { operator=(other); } LayoutUnit &operator=(const LayoutUnit &other) { if (this != &other) { - layout = other.layout; - variant = other.variant; + m_layout = other.m_layout; + m_variant = other.m_variant; displayName = other.displayName; shortcut = other.shortcut; } return *this; } - QString getRawDisplayName() const { return displayName; } - QString getDisplayName() const { return !displayName.isEmpty() ? displayName : layout; } - void setDisplayName(const QString& name) { displayName = name; } - - void setShortcut(const QKeySequence& shortcut) { this->shortcut = shortcut; } - QKeySequence getShortcut() const { return shortcut; } - - bool isEmpty() const { return layout.isEmpty(); } - bool isValid() const { return ! isEmpty(); } - bool operator==(const LayoutUnit& layoutItem) const { - return layout==layoutItem.layout && variant==layoutItem.variant; - } - bool operator!=(const LayoutUnit& layoutItem) const { - return ! (*this == layoutItem); - } - QString toString() const; + QString getRawDisplayName() const { return displayName; } + QString getDisplayName() const { return !displayName.isEmpty() ? displayName : m_layout; } + void setDisplayName(const QString& name) { displayName = name; } + + void setShortcut(const QKeySequence& shortcut) { this->shortcut = shortcut; } + QKeySequence getShortcut() const { return shortcut; } + QString layout() const { return m_layout; } + void setLayout(const QString &layout) { m_layout = layout; } + QString variant() const { return m_variant; } + void setVariant(const QString &variant) { m_variant = variant; } + + bool isEmpty() const { return m_layout.isEmpty(); } + bool isValid() const { return ! isEmpty(); } + bool operator==(const LayoutUnit& layoutItem) const { + // FIXME: why not compare the other properties? + return m_layout == layoutItem.m_layout && m_variant == layoutItem.m_variant; + } + bool operator!=(const LayoutUnit& layoutItem) const { + return ! (*this == layoutItem); + } + QString toString() const; private: - QString displayName; - QKeySequence shortcut; + QString displayName; + QKeySequence shortcut; + QString m_layout; + QString m_variant; }; struct LayoutSet { QList layouts; LayoutUnit currentLayout; LayoutSet() {} - LayoutSet(const LayoutSet& currentLayouts) { - this->layouts = currentLayouts.layouts; - this->currentLayout = currentLayouts.currentLayout; + LayoutSet(const LayoutSet& other) { + operator=(other); } bool isValid() const { return currentLayout.isValid() && layouts.contains(currentLayout); } bool operator == (const LayoutSet& currentLayouts) const { return this->layouts == currentLayouts.layouts && this->currentLayout == currentLayouts.currentLayout; } LayoutSet& operator = (const LayoutSet& currentLayouts) { this->layouts = currentLayouts.layouts; this->currentLayout = currentLayouts.currentLayout; return *this; } QString toString() const { QString str(currentLayout.toString()); str += QLatin1String(": "); foreach(const LayoutUnit& layoutUnit, layouts) { str += layoutUnit.toString() + " "; } return str; } static QString toString(const QList& layoutUnits) { QString str; foreach(const LayoutUnit& layoutUnit, layoutUnits) { str += layoutUnit.toString() + ","; } return str; } }; class X11Helper { public: static const int MAX_GROUP_COUNT; static const int ARTIFICIAL_GROUP_LIMIT_COUNT; static const char LEFT_VARIANT_STR[]; static const char RIGHT_VARIANT_STR[]; static bool xkbSupported(int* xkbOpcode); static void switchToNextLayout(); static void scrollLayouts(int delta); static bool isDefaultLayout(); static bool setDefaultLayout(); static bool setLayout(const LayoutUnit& layout); static LayoutUnit getCurrentLayout(); static LayoutSet getCurrentLayouts(); static QList getLayoutsList(); static QStringList getLayoutsListAsString(const QList& layoutsList); enum FetchType { ALL, LAYOUTS_ONLY, MODEL_ONLY }; static bool getGroupNames(Display* dpy, XkbConfig* xkbConfig, FetchType fetchType); private: static unsigned int getGroup(); static bool setGroup(unsigned int group); }; #endif /* X11_HELPER_H_ */ diff --git a/kcms/keyboard/xkb_helper.cpp b/kcms/keyboard/xkb_helper.cpp index 7f454289f..949e37e69 100644 --- a/kcms/keyboard/xkb_helper.cpp +++ b/kcms/keyboard/xkb_helper.cpp @@ -1,184 +1,184 @@ /* * Copyright (C) 2010 Andriy Rysin (rysin@kde.org) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "xkb_helper.h" #include "debug.h" #include #include #include #include #include #include #include #include #include #include "keyboard_config.h" static const char SETXKBMAP_EXEC[] = "setxkbmap"; static const char XMODMAP_EXEC[] = "xmodmap"; static bool setxkbmapNotFound = false; static QString setxkbmapExe; static bool xmodmapNotFound = false; static QString xmodmapExe; static const QString COMMAND_OPTIONS_SEPARATOR(QStringLiteral(",")); static QString getSetxkbmapExe() { if( setxkbmapNotFound ) return QLatin1String(""); if( setxkbmapExe.isEmpty() ) { setxkbmapExe = QStandardPaths::findExecutable(SETXKBMAP_EXEC); if( setxkbmapExe.isEmpty() ) { setxkbmapNotFound = true; qCCritical(KCM_KEYBOARD) << "Can't find" << SETXKBMAP_EXEC << "- keyboard layouts won't be configured"; return QLatin1String(""); } } return setxkbmapExe; } static void executeXmodmap(const QString& configFileName) { if( xmodmapNotFound ) return; if( QFile(configFileName).exists() ) { if( xmodmapExe.isEmpty() ) { xmodmapExe = QStandardPaths::findExecutable(XMODMAP_EXEC); if( xmodmapExe.isEmpty() ) { xmodmapNotFound = true; qCCritical(KCM_KEYBOARD) << "Can't find" << XMODMAP_EXEC << "- xmodmap files won't be run"; return; } } KProcess xmodmapProcess; xmodmapProcess << xmodmapExe; xmodmapProcess << configFileName; qCDebug(KCM_KEYBOARD) << "Executing" << xmodmapProcess.program().join(QStringLiteral(" ")); if( xmodmapProcess.execute() != 0 ) { qCCritical(KCM_KEYBOARD) << "Failed to execute " << xmodmapProcess.program(); } } } static void restoreXmodmap() { // TODO: is just home .Xmodmap enough or should system be involved too? // QString configFileName = QDir("/etc/X11/xinit").filePath(".Xmodmap"); // executeXmodmap(configFileName); QString configFileName = QDir::home().filePath(QStringLiteral(".Xmodmap")); executeXmodmap(configFileName); } //TODO: make private bool XkbHelper::runConfigLayoutCommand(const QStringList& setxkbmapCommandArguments) { QTime timer; timer.start(); KProcess setxkbmapProcess; setxkbmapProcess << getSetxkbmapExe() << setxkbmapCommandArguments; int res = setxkbmapProcess.execute(); if( res == 0 ) { // restore Xmodmap mapping reset by setxkbmap qCDebug(KCM_KEYBOARD) << "Executed successfully in " << timer.elapsed() << "ms" << setxkbmapProcess.program().join(QStringLiteral(" ")); restoreXmodmap(); qCDebug(KCM_KEYBOARD) << "\t and with xmodmap" << timer.elapsed() << "ms"; return true; } else { qCCritical(KCM_KEYBOARD) << "Failed to run" << setxkbmapProcess.program().join(QStringLiteral(" ")) << "return code:" << res; } return false; } bool XkbHelper::initializeKeyboardLayouts(const QList& layoutUnits) { QStringList layouts; QStringList variants; foreach (const LayoutUnit& layoutUnit, layoutUnits) { - layouts.append(layoutUnit.layout); - variants.append(layoutUnit.variant); + layouts.append(layoutUnit.layout()); + variants.append(layoutUnit.variant()); } QStringList setxkbmapCommandArguments; setxkbmapCommandArguments.append(QStringLiteral("-layout")); setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); if( ! variants.join(QLatin1String("")).isEmpty() ) { setxkbmapCommandArguments.append(QStringLiteral("-variant")); setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); } return runConfigLayoutCommand(setxkbmapCommandArguments); } bool XkbHelper::initializeKeyboardLayouts(KeyboardConfig& config) { QStringList setxkbmapCommandArguments; if( ! config.keyboardModel.isEmpty() ) { XkbConfig xkbConfig; X11Helper::getGroupNames(QX11Info::display(), &xkbConfig, X11Helper::MODEL_ONLY); if( xkbConfig.keyboardModel != config.keyboardModel ) { setxkbmapCommandArguments.append(QStringLiteral("-model")); setxkbmapCommandArguments.append(config.keyboardModel); } } if( config.configureLayouts ) { QStringList layouts; QStringList variants; QList defaultLayouts = config.getDefaultLayouts(); foreach (const LayoutUnit& layoutUnit, defaultLayouts) { - layouts.append(layoutUnit.layout); - variants.append(layoutUnit.variant); + layouts.append(layoutUnit.layout()); + variants.append(layoutUnit.variant()); } setxkbmapCommandArguments.append(QStringLiteral("-layout")); setxkbmapCommandArguments.append(layouts.join(COMMAND_OPTIONS_SEPARATOR)); if( ! variants.join(QLatin1String("")).isEmpty() ) { setxkbmapCommandArguments.append(QStringLiteral("-variant")); setxkbmapCommandArguments.append(variants.join(COMMAND_OPTIONS_SEPARATOR)); } } if( config.resetOldXkbOptions ) { setxkbmapCommandArguments.append(QStringLiteral("-option")); } if( ! config.xkbOptions.isEmpty() ) { setxkbmapCommandArguments.append(QStringLiteral("-option")); setxkbmapCommandArguments.append(config.xkbOptions.join(COMMAND_OPTIONS_SEPARATOR)); } if( ! setxkbmapCommandArguments.isEmpty() ) { return runConfigLayoutCommand(setxkbmapCommandArguments); if( config.configureLayouts ) { X11Helper::setDefaultLayout(); } } return false; }