File indexing completed on 2024-05-05 03:58:34
0001 /* 0002 SPDX-FileCopyrightText: KDE Developers 0003 0004 SPDX-License-Identifier: LGPL-2.0-or-later 0005 */ 0006 0007 #include <QFileDialog> 0008 #include <QTableWidgetItem> 0009 #include <QWhatsThis> 0010 0011 #include <KLocalizedString> 0012 #include <KMessageBox> 0013 0014 #include "ui_configwidget.h" 0015 #include <utils/kateconfig.h> 0016 #include <utils/kateglobal.h> 0017 #include <vimode/config/configtab.h> 0018 #include <vimode/keyparser.h> 0019 0020 using namespace KateVi; 0021 0022 ConfigTab::ConfigTab(QWidget *parent, Mappings *mappings) 0023 : KateConfigPage(parent) 0024 , m_mappings(mappings) 0025 { 0026 // This will let us have more separation between this page and 0027 // the QTabWidget edge (ereslibre) 0028 QVBoxLayout *layout = new QVBoxLayout(this); 0029 QWidget *newWidget = new QWidget(this); 0030 0031 ui = new Ui::ConfigWidget(); 0032 ui->setupUi(newWidget); 0033 0034 // Make the header take all the width in equal parts. 0035 ui->tblNormalModeMappings->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 0036 ui->tblInsertModeMappings->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 0037 ui->tblVisualModeMappings->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); 0038 0039 // What's This? help can be found in the ui file 0040 reload(); 0041 0042 // 0043 // after initial reload, connect the stuff for the changed() signal 0044 // 0045 connect(ui->chkViCommandsOverride, &QCheckBox::toggled, this, &ConfigTab::slotChanged); 0046 connect(ui->chkViRelLineNumbers, &QCheckBox::toggled, this, &ConfigTab::slotChanged); 0047 connect(ui->tblNormalModeMappings, &QTableWidget::cellChanged, this, &ConfigTab::slotChanged); 0048 connect(ui->btnAddNewRow, &QPushButton::clicked, this, &ConfigTab::addMappingRow); 0049 connect(ui->btnAddNewRow, &QPushButton::clicked, this, &ConfigTab::slotChanged); 0050 connect(ui->btnRemoveSelectedRows, &QPushButton::clicked, this, &ConfigTab::removeSelectedMappingRows); 0051 connect(ui->btnRemoveSelectedRows, &QPushButton::clicked, this, &ConfigTab::slotChanged); 0052 connect(ui->btnImportNormal, &QPushButton::clicked, this, &ConfigTab::importNormalMappingRow); 0053 connect(ui->btnImportNormal, &QPushButton::clicked, this, &ConfigTab::slotChanged); 0054 0055 layout->addWidget(newWidget); 0056 } 0057 0058 ConfigTab::~ConfigTab() 0059 { 0060 delete ui; 0061 } 0062 0063 void ConfigTab::applyTab(QTableWidget *mappingsTable, Mappings::MappingMode mode) 0064 { 0065 m_mappings->clear(mode); 0066 0067 for (int i = 0; i < mappingsTable->rowCount(); i++) { 0068 QTableWidgetItem *from = mappingsTable->item(i, 0); 0069 QTableWidgetItem *to = mappingsTable->item(i, 1); 0070 QTableWidgetItem *recursive = mappingsTable->item(i, 2); 0071 0072 if (from && to && recursive) { 0073 const Mappings::MappingRecursion recursion = recursive->checkState() == Qt::Checked ? Mappings::Recursive : Mappings::NonRecursive; 0074 m_mappings->add(mode, from->text(), to->text(), recursion); 0075 } 0076 } 0077 } 0078 0079 void ConfigTab::reloadTab(QTableWidget *mappingsTable, Mappings::MappingMode mode) 0080 { 0081 const QStringList l = m_mappings->getAll(mode); 0082 mappingsTable->setRowCount(l.size()); 0083 0084 int i = 0; 0085 for (const QString &f : l) { 0086 QTableWidgetItem *from = new QTableWidgetItem(KeyParser::self()->decodeKeySequence(f)); 0087 QString s = m_mappings->get(mode, f); 0088 QTableWidgetItem *to = new QTableWidgetItem(KeyParser::self()->decodeKeySequence(s)); 0089 QTableWidgetItem *recursive = new QTableWidgetItem(); 0090 recursive->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable); 0091 const bool isRecursive = m_mappings->isRecursive(mode, f); 0092 recursive->setCheckState(isRecursive ? Qt::Checked : Qt::Unchecked); 0093 0094 mappingsTable->setItem(i, 0, from); 0095 mappingsTable->setItem(i, 1, to); 0096 mappingsTable->setItem(i, 2, recursive); 0097 0098 i++; 0099 } 0100 } 0101 0102 void ConfigTab::apply() 0103 { 0104 // nothing changed, no need to apply stuff 0105 if (!hasChanged()) { 0106 return; 0107 } 0108 m_changed = false; 0109 0110 KateViewConfig::global()->configStart(); 0111 0112 // General options. 0113 KateViewConfig::global()->setValue(KateViewConfig::ViRelativeLineNumbers, ui->chkViRelLineNumbers->isChecked()); 0114 KateViewConfig::global()->setValue(KateViewConfig::ViInputModeStealKeys, ui->chkViCommandsOverride->isChecked()); 0115 0116 // Mappings. 0117 applyTab(ui->tblNormalModeMappings, Mappings::NormalModeMapping); 0118 applyTab(ui->tblInsertModeMappings, Mappings::InsertModeMapping); 0119 applyTab(ui->tblVisualModeMappings, Mappings::VisualModeMapping); 0120 0121 KateViewConfig::global()->configEnd(); 0122 } 0123 0124 void ConfigTab::reload() 0125 { 0126 // General options. 0127 ui->chkViRelLineNumbers->setChecked(KateViewConfig::global()->viRelativeLineNumbers()); 0128 ui->chkViCommandsOverride->setChecked(KateViewConfig::global()->viInputModeStealKeys()); 0129 0130 // Mappings. 0131 reloadTab(ui->tblNormalModeMappings, Mappings::NormalModeMapping); 0132 reloadTab(ui->tblInsertModeMappings, Mappings::InsertModeMapping); 0133 reloadTab(ui->tblVisualModeMappings, Mappings::VisualModeMapping); 0134 } 0135 0136 void ConfigTab::reset() 0137 { 0138 /* Do nothing. */ 0139 } 0140 0141 void ConfigTab::defaults() 0142 { 0143 /* Do nothing. */ 0144 } 0145 0146 void ConfigTab::showWhatsThis(const QString &text) 0147 { 0148 QWhatsThis::showText(QCursor::pos(), text); 0149 } 0150 0151 void ConfigTab::addMappingRow() 0152 { 0153 // Pick the current widget. 0154 QTableWidget *mappingsTable = ui->tblNormalModeMappings; 0155 if (ui->tabMappingModes->currentIndex() == 1) { 0156 mappingsTable = ui->tblInsertModeMappings; 0157 } else if (ui->tabMappingModes->currentIndex() == 2) { 0158 mappingsTable = ui->tblVisualModeMappings; 0159 } 0160 0161 // And add a new row. 0162 int rows = mappingsTable->rowCount(); 0163 mappingsTable->insertRow(rows); 0164 QTableWidgetItem *recursive = new QTableWidgetItem(); 0165 recursive->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable); 0166 recursive->setCheckState(Qt::Unchecked); 0167 mappingsTable->setItem(rows, 2, recursive); 0168 mappingsTable->setCurrentCell(rows, 0); 0169 mappingsTable->editItem(mappingsTable->currentItem()); 0170 } 0171 0172 void ConfigTab::removeSelectedMappingRows() 0173 { 0174 // Pick the current widget. 0175 QTableWidget *mappingsTable = ui->tblNormalModeMappings; 0176 if (ui->tabMappingModes->currentIndex() == 1) { 0177 mappingsTable = ui->tblInsertModeMappings; 0178 } else if (ui->tabMappingModes->currentIndex() == 2) { 0179 mappingsTable = ui->tblVisualModeMappings; 0180 } 0181 0182 // And remove the selected rows. 0183 const QList<QTableWidgetSelectionRange> l = mappingsTable->selectedRanges(); 0184 for (const QTableWidgetSelectionRange &range : l) { 0185 for (int i = 0; i < range.bottomRow() - range.topRow() + 1; i++) { 0186 mappingsTable->removeRow(range.topRow()); 0187 } 0188 } 0189 } 0190 0191 void ConfigTab::importNormalMappingRow() 0192 { 0193 const QString &fileName = QFileDialog::getOpenFileName(this); 0194 0195 if (fileName.isEmpty()) { 0196 return; 0197 } 0198 0199 QFile configFile(fileName); 0200 if (!configFile.open(QIODevice::ReadOnly | QIODevice::Text)) { 0201 KMessageBox::error(this, i18n("Unable to open the config file for reading."), i18n("Unable to open file")); 0202 return; 0203 } 0204 0205 QTextStream stream(&configFile); 0206 const QRegularExpression mapleader(QStringLiteral("(?:\\w:)?mapleader")); 0207 while (!stream.atEnd()) { 0208 const QStringList line = stream.readLine().split(QLatin1Char(' ')); 0209 0210 // TODO - allow recursive mappings to be read. 0211 if (line.size() > 2 0212 && (line[0] == QLatin1String("noremap") || line[0] == QLatin1String("no") || line[0] == QLatin1String("nnoremap") 0213 || line[0] == QLatin1String("nn"))) { 0214 int rows = ui->tblNormalModeMappings->rowCount(); 0215 ui->tblNormalModeMappings->insertRow(rows); 0216 ui->tblNormalModeMappings->setItem(rows, 0, new QTableWidgetItem(line[1])); 0217 ui->tblNormalModeMappings->setItem(rows, 1, new QTableWidgetItem(line[2])); 0218 QTableWidgetItem *recursive = new QTableWidgetItem(); 0219 recursive->setFlags(Qt::ItemIsEnabled | Qt::ItemIsUserCheckable | Qt::ItemIsSelectable); 0220 recursive->setCheckState(Qt::Unchecked); 0221 ui->tblNormalModeMappings->setItem(rows, 2, recursive); 0222 } else if (line.size() == 4 && line[0] == QLatin1String("let") && line[2] == QLatin1String("=") && mapleader.match(line[1]).hasMatch()) { 0223 const QStringView leader = QStringView(line[3]).mid(1, line[3].length() - 2); 0224 if (!leader.isEmpty()) { 0225 m_mappings->setLeader(leader[0]); 0226 } 0227 } 0228 } 0229 } 0230 0231 QString ConfigTab::name() const 0232 { 0233 return i18n("Vi Input Mode"); 0234 }