File indexing completed on 2024-04-21 05:45:48

0001 /*******************************************************************************
0002  * Copyright (C) 2008-2013 Konstantinos Smanis <konstantinos.smanis@gmail.com> *
0003  *                                                                             *
0004  * This program is free software: you can redistribute it and/or modify it     *
0005  * under the terms of the GNU General Public License as published by the Free  *
0006  * Software Foundation, either version 3 of the License, or (at your option)   *
0007  * any later version.                                                          *
0008  *                                                                             *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT *
0010  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
0011  * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
0012  * more details.                                                               *
0013  *                                                                             *
0014  * You should have received a copy of the GNU General Public License along     *
0015  * with this program. If not, see <http://www.gnu.org/licenses/>.              *
0016  *******************************************************************************/
0017 
0018 // Krazy
0019 // krazy:excludeall=cpp
0020 
0021 // Own
0022 #include "kcm_grub2.h"
0023 
0024 // Qt
0025 #include <QDebug>
0026 #include <QDesktopWidget>
0027 #include <QIcon>
0028 #include <QMenu>
0029 #include <QProgressDialog>
0030 #include <QPushButton>
0031 #include <QStandardItemModel>
0032 #include <QTreeView>
0033 
0034 // KDE
0035 #include <KAuth/Action>
0036 #include <KAuth/ExecuteJob>
0037 #include <KLocalizedString>
0038 #include <KMessageBox>
0039 #include <KPluginFactory>
0040 
0041 using namespace KAuth;
0042 
0043 // Project
0044 #include "common.h"
0045 #include "config.h"
0046 #if HAVE_IMAGEMAGICK
0047 #include "convertDlg.h"
0048 #endif
0049 #include "entry.h"
0050 #include "installDlg.h"
0051 #if HAVE_QAPT || HAVE_QPACKAGEKIT
0052 #include "removeDlg.h"
0053 #endif
0054 #include "textinputdialog.h"
0055 
0056 // Ui
0057 #include "ui_kcm_grub2.h"
0058 
0059 K_PLUGIN_CLASS_WITH_JSON(KCMGRUB2, "kcm_grub2.json")
0060 
0061 KCMGRUB2::KCMGRUB2(QObject *parent, const KPluginMetaData &data, const QVariantList &list)
0062     : KCModule(parent, data, list)
0063 {
0064     // Make this setAuthActionName in KF6
0065     setAuthAction(Action(QStringLiteral("org.kde.kcontrol.kcmgrub2.save")));
0066 
0067     ui = new Ui::KCMGRUB2;
0068     ui->setupUi(widget());
0069     setupObjects();
0070     setupConnections();
0071 }
0072 KCMGRUB2::~KCMGRUB2()
0073 {
0074     delete ui;
0075 }
0076 
0077 void KCMGRUB2::defaults()
0078 {
0079     Action defaultsAction(QStringLiteral("org.kde.kcontrol.kcmgrub2.defaults"));
0080     defaultsAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmgrub2"));
0081     defaultsAction.setParentWidget(widget());
0082 
0083     KAuth::ExecuteJob *defaultsJob = defaultsAction.execute();
0084     if (defaultsJob->exec()) {
0085         load();
0086         save();
0087         KMessageBox::information(widget(), i18nc("@info", "Successfully restored the default values."));
0088     } else {
0089         KMessageBox::detailedError(widget(), i18nc("@info", "Failed to restore the default values."), defaultsJob->errorText());
0090     }
0091 }
0092 void KCMGRUB2::load()
0093 {
0094     readAll();
0095 
0096     QString grubDefault = unquoteWord(m_settings.value(QStringLiteral("GRUB_DEFAULT")));
0097     if (grubDefault == QLatin1String("saved")) {
0098         grubDefault = (m_env.value(QStringLiteral("saved_entry")).isEmpty() ? QString(QLatin1Char('0')) : m_env.value(QStringLiteral("saved_entry")));
0099     }
0100 
0101     ui->combobox_default->clear();
0102     if (!m_entries.isEmpty()) {
0103         int maxLen = 0, maxLvl = 0;
0104         QStandardItemModel *model = new QStandardItemModel(ui->combobox_default);
0105         QTreeView *view = qobject_cast<QTreeView *>(ui->combobox_default->view());
0106         QList<QStandardItem *> ancestors;
0107         ancestors.append(model->invisibleRootItem());
0108         for (int i = 0; i < m_entries.size(); i++) {
0109             const Entry &entry = m_entries.at(i);
0110             const QString &prettyTitle = entry.prettyTitle();
0111             if (prettyTitle.length() > maxLen) {
0112                 maxLen = prettyTitle.length();
0113             }
0114             if (entry.level() > maxLvl) {
0115                 maxLvl = entry.level();
0116             }
0117             QStandardItem *item = new QStandardItem(prettyTitle);
0118             item->setData(entry.fullTitle());
0119             item->setSelectable(entry.type() == Entry::Menuentry);
0120             ancestors.last()->appendRow(item);
0121             if (i + 1 < m_entries.size()) {
0122                 int n = m_entries.at(i + 1).level() - entry.level();
0123                 if (n == 1) {
0124                     ancestors.append(item);
0125                 } else if (n < 0) {
0126                     for (int j = 0; j > n; j--) {
0127                         ancestors.removeLast();
0128                     }
0129                 }
0130             }
0131         }
0132         view->setModel(model);
0133         view->expandAll();
0134         ui->combobox_default->setModel(model);
0135         ui->combobox_default->setMinimumContentsLength(maxLen + maxLvl * 3);
0136 
0137         bool numericDefault = QRegExp(QLatin1String("((\\d)+>)*(\\d)+")).exactMatch(grubDefault);
0138         int entryIndex = -1;
0139         for (int i = 0; i < m_entries.size(); i++) {
0140             if ((numericDefault && m_entries.at(i).fullNumTitle() == grubDefault) || (!numericDefault && m_entries.at(i).fullTitle() == grubDefault)) {
0141                 entryIndex = i;
0142                 break;
0143             }
0144         }
0145         if (entryIndex != -1) {
0146             const Entry &entry = m_entries.at(entryIndex);
0147             if (entry.level() == 0) {
0148                 ui->combobox_default->setCurrentIndex(entry.title().num);
0149             } else {
0150                 QStandardItem *item = model->item(entry.ancestors().at(0).num);
0151                 for (int i = 1; i < entry.level(); i++) {
0152                     item = item->child(entry.ancestors().at(i).num);
0153                 }
0154                 ui->combobox_default->setRootModelIndex(model->indexFromItem(item));
0155                 ui->combobox_default->setCurrentIndex(entry.title().num);
0156                 ui->combobox_default->setRootModelIndex(model->indexFromItem(model->invisibleRootItem()));
0157             }
0158         } else {
0159             qWarning() << "Invalid GRUB_DEFAULT value";
0160         }
0161     }
0162     ui->pushbutton_remove->setEnabled(!m_entries.isEmpty());
0163     ui->checkBox_savedefault->setChecked(unquoteWord(m_settings.value(QStringLiteral("GRUB_SAVEDEFAULT"))).compare(QLatin1String("true")) == 0);
0164 
0165     QString grubHiddenTimeoutRaw = unquoteWord(m_settings.value(QStringLiteral("GRUB_HIDDEN_TIMEOUT")));
0166     if (grubHiddenTimeoutRaw.isEmpty()) {
0167         ui->checkBox_hiddenTimeout->setChecked(false);
0168     } else {
0169         bool ok;
0170         int grubHiddenTimeout = grubHiddenTimeoutRaw.toInt(&ok);
0171         if (ok && grubHiddenTimeout >= 0) {
0172             ui->checkBox_hiddenTimeout->setChecked(true);
0173             ui->spinBox_hiddenTimeout->setValue(grubHiddenTimeout);
0174             ui->checkBox_hiddenTimeoutShowTimer->setChecked(
0175                 unquoteWord(m_settings.value(QStringLiteral("GRUB_HIDDEN_TIMEOUT_QUIET"))).compare(QLatin1String("true")) != 0);
0176         } else {
0177             qWarning() << "Invalid GRUB_HIDDEN_TIMEOUT value";
0178         }
0179     }
0180     bool ok = true;
0181     int grubTimeout =
0182         (m_settings.value(QStringLiteral("GRUB_TIMEOUT")).isEmpty() ? 5 : unquoteWord(m_settings.value(QStringLiteral("GRUB_TIMEOUT"))).toInt(&ok));
0183     if (ok && grubTimeout >= -1) {
0184         ui->checkBox_timeout->setChecked(grubTimeout > -1);
0185         ui->radioButton_timeout0->setChecked(grubTimeout == 0);
0186         ui->radioButton_timeout->setChecked(grubTimeout > 0);
0187         ui->spinBox_timeout->setValue(grubTimeout);
0188     } else {
0189         qWarning() << "Invalid GRUB_TIMEOUT value";
0190     }
0191 
0192     showLocales();
0193     int languageIndex = ui->combobox_language->findData(unquoteWord(m_settings.value(QStringLiteral("LANGUAGE"))));
0194     if (languageIndex != -1) {
0195         ui->combobox_language->setCurrentIndex(languageIndex);
0196     } else {
0197         qWarning() << "Invalid LANGUAGE value";
0198     }
0199     ui->checkBox_recovery->setChecked(unquoteWord(m_settings.value(QStringLiteral("GRUB_DISABLE_RECOVERY"))).compare(QLatin1String("true")) != 0);
0200     ui->checkBox_memtest->setVisible(m_memtest);
0201     ui->checkBox_memtest->setChecked(m_memtestOn);
0202     ui->checkBox_osProber->setChecked(unquoteWord(m_settings.value(QStringLiteral("GRUB_DISABLE_OS_PROBER"))).compare(QLatin1String("true")) != 0);
0203 
0204     QString grubGfxmode = unquoteWord(m_settings.value(QStringLiteral("GRUB_GFXMODE")));
0205     if (grubGfxmode.isEmpty()) {
0206         grubGfxmode = QStringLiteral("auto");
0207     }
0208     if (grubGfxmode != QLatin1String("auto") && !m_resolutions.contains(grubGfxmode)) {
0209         m_resolutions.append(grubGfxmode);
0210     }
0211     QString grubGfxpayloadLinux = unquoteWord(m_settings.value(QStringLiteral("GRUB_GFXPAYLOAD_LINUX")));
0212     if (!grubGfxpayloadLinux.isEmpty() && grubGfxpayloadLinux != QLatin1String("text") && grubGfxpayloadLinux != QLatin1String("keep")
0213         && !m_resolutions.contains(grubGfxpayloadLinux)) {
0214         m_resolutions.append(grubGfxpayloadLinux);
0215     }
0216     m_resolutions.removeDuplicates();
0217     sortResolutions();
0218     showResolutions();
0219     ui->combobox_gfxmode->setCurrentIndex(ui->combobox_gfxmode->findData(grubGfxmode));
0220     ui->toolButton_refreshGfxmode->setVisible(HAVE_HD && m_resolutionsEmpty);
0221     ui->combobox_gfxpayload->setCurrentIndex(ui->combobox_gfxpayload->findData(grubGfxpayloadLinux));
0222     ui->toolButton_refreshGfxpayload->setVisible(HAVE_HD && m_resolutionsEmpty);
0223 
0224     QString grubColorNormal = unquoteWord(m_settings.value(QStringLiteral("GRUB_COLOR_NORMAL")));
0225     if (!grubColorNormal.isEmpty()) {
0226         int normalForegroundIndex = ui->combobox_normalForeground->findData(grubColorNormal.section(QLatin1Char('/'), 0, 0));
0227         int normalBackgroundIndex = ui->combobox_normalBackground->findData(grubColorNormal.section(QLatin1Char('/'), 1));
0228         if (normalForegroundIndex == -1 || normalBackgroundIndex == -1) {
0229             qWarning() << "Invalid GRUB_COLOR_NORMAL value";
0230         }
0231         if (normalForegroundIndex != -1) {
0232             ui->combobox_normalForeground->setCurrentIndex(normalForegroundIndex);
0233         }
0234         if (normalBackgroundIndex != -1) {
0235             ui->combobox_normalBackground->setCurrentIndex(normalBackgroundIndex);
0236         }
0237     }
0238     QString grubColorHighlight = unquoteWord(m_settings.value(QStringLiteral("GRUB_COLOR_HIGHLIGHT")));
0239     if (!grubColorHighlight.isEmpty()) {
0240         int highlightForegroundIndex = ui->combobox_highlightForeground->findData(grubColorHighlight.section(QLatin1Char('/'), 0, 0));
0241         int highlightBackgroundIndex = ui->combobox_highlightBackground->findData(grubColorHighlight.section(QLatin1Char('/'), 1));
0242         if (highlightForegroundIndex == -1 || highlightBackgroundIndex == -1) {
0243             qWarning() << "Invalid GRUB_COLOR_HIGHLIGHT value";
0244         }
0245         if (highlightForegroundIndex != -1) {
0246             ui->combobox_highlightForeground->setCurrentIndex(highlightForegroundIndex);
0247         }
0248         if (highlightBackgroundIndex != -1) {
0249             ui->combobox_highlightBackground->setCurrentIndex(highlightBackgroundIndex);
0250         }
0251     }
0252 
0253     QString grubBackground = unquoteWord(m_settings.value(QStringLiteral("GRUB_BACKGROUND")));
0254     ui->kurlrequester_background->setText(grubBackground);
0255     ui->pushbutton_preview->setEnabled(!grubBackground.isEmpty());
0256     ui->kurlrequester_theme->setText(unquoteWord(m_settings.value(QStringLiteral("GRUB_THEME"))));
0257 
0258     ui->lineedit_cmdlineDefault->setText(unquoteWord(m_settings.value(QStringLiteral("GRUB_CMDLINE_LINUX_DEFAULT"))));
0259     ui->lineedit_cmdline->setText(unquoteWord(m_settings.value(QStringLiteral("GRUB_CMDLINE_LINUX"))));
0260 
0261     QString grubTerminal = unquoteWord(m_settings.value(QStringLiteral("GRUB_TERMINAL")));
0262     ui->lineedit_terminal->setText(grubTerminal);
0263     ui->lineedit_terminalInput->setReadOnly(!grubTerminal.isEmpty());
0264     ui->lineedit_terminalOutput->setReadOnly(!grubTerminal.isEmpty());
0265     ui->lineedit_terminalInput->setText(!grubTerminal.isEmpty() ? grubTerminal : unquoteWord(m_settings.value(QStringLiteral("GRUB_TERMINAL_INPUT"))));
0266     ui->lineedit_terminalOutput->setText(!grubTerminal.isEmpty() ? grubTerminal : unquoteWord(m_settings.value(QStringLiteral("GRUB_TERMINAL_OUTPUT"))));
0267 
0268     ui->lineedit_distributor->setText(unquoteWord(m_settings.value(QStringLiteral("GRUB_DISTRIBUTOR"))));
0269     ui->lineedit_serial->setText(unquoteWord(m_settings.value(QStringLiteral("GRUB_SERIAL_COMMAND"))));
0270     ui->lineedit_initTune->setText(unquoteWord(m_settings.value(QStringLiteral("GRUB_INIT_TUNE"))));
0271     ui->checkBox_uuid->setChecked(unquoteWord(m_settings.value(QStringLiteral("GRUB_DISABLE_LINUX_UUID"))).compare(QLatin1String("true")) != 0);
0272 
0273     m_dirtyBits.fill(0);
0274     setNeedsSave(false);
0275 }
0276 void KCMGRUB2::save()
0277 {
0278     QString grubDefault;
0279     if (!m_entries.isEmpty()) {
0280         m_settings[QStringLiteral("GRUB_DEFAULT")] = QStringLiteral("saved");
0281         QStandardItemModel *model = qobject_cast<QStandardItemModel *>(ui->combobox_default->model());
0282         QTreeView *view = qobject_cast<QTreeView *>(ui->combobox_default->view());
0283         // Ugly, ugly hack. The view's current QModelIndex is invalidated
0284         // while the view is hidden and there is no access to the internal
0285         // QPersistentModelIndex (it is hidden in QComboBox's pimpl).
0286         // While the popup is shown, the QComboBox selects the current entry.
0287         // TODO: Maybe move away from the QComboBox+QTreeView implementation?
0288         ui->combobox_default->showPopup();
0289         grubDefault = model->itemFromIndex(view->currentIndex())->data().toString();
0290         ui->combobox_default->hidePopup();
0291     }
0292     if (m_dirtyBits.testBit(grubSavedefaultDirty)) {
0293         if (ui->checkBox_savedefault->isChecked()) {
0294             m_settings[QStringLiteral("GRUB_SAVEDEFAULT")] = QStringLiteral("true");
0295         } else {
0296             m_settings.remove(QStringLiteral("GRUB_SAVEDEFAULT"));
0297         }
0298     }
0299     if (m_dirtyBits.testBit(grubHiddenTimeoutDirty)) {
0300         if (ui->checkBox_hiddenTimeout->isChecked()) {
0301             m_settings[QStringLiteral("GRUB_HIDDEN_TIMEOUT")] = QString::number(ui->spinBox_hiddenTimeout->value());
0302         } else {
0303             m_settings.remove(QStringLiteral("GRUB_HIDDEN_TIMEOUT"));
0304         }
0305     }
0306     if (m_dirtyBits.testBit(grubHiddenTimeoutQuietDirty)) {
0307         if (ui->checkBox_hiddenTimeoutShowTimer->isChecked()) {
0308             m_settings.remove(QStringLiteral("GRUB_HIDDEN_TIMEOUT_QUIET"));
0309         } else {
0310             m_settings[QStringLiteral("GRUB_HIDDEN_TIMEOUT_QUIET")] = QStringLiteral("true");
0311         }
0312     }
0313     if (m_dirtyBits.testBit(grubTimeoutDirty)) {
0314         if (ui->checkBox_timeout->isChecked()) {
0315             if (ui->radioButton_timeout0->isChecked()) {
0316                 m_settings[QStringLiteral("GRUB_TIMEOUT")] = QLatin1Char('0');
0317             } else {
0318                 m_settings[QStringLiteral("GRUB_TIMEOUT")] = QString::number(ui->spinBox_timeout->value());
0319             }
0320         } else {
0321             m_settings[QStringLiteral("GRUB_TIMEOUT")] = QStringLiteral("-1");
0322         }
0323     }
0324     if (m_dirtyBits.testBit(grubLocaleDirty)) {
0325         int langIndex = ui->combobox_language->currentIndex();
0326         if (langIndex > 0) {
0327             m_settings[QStringLiteral("LANGUAGE")] = ui->combobox_language->itemData(langIndex).toString();
0328         } else {
0329             m_settings.remove(QStringLiteral("LANGUAGE"));
0330         }
0331     }
0332     if (m_dirtyBits.testBit(grubDisableRecoveryDirty)) {
0333         if (ui->checkBox_recovery->isChecked()) {
0334             m_settings.remove(QStringLiteral("GRUB_DISABLE_RECOVERY"));
0335         } else {
0336             m_settings[QStringLiteral("GRUB_DISABLE_RECOVERY")] = QStringLiteral("true");
0337         }
0338     }
0339     if (m_dirtyBits.testBit(grubDisableOsProberDirty)) {
0340         if (ui->checkBox_osProber->isChecked()) {
0341             m_settings.remove(QStringLiteral("GRUB_DISABLE_OS_PROBER"));
0342         } else {
0343             m_settings[QStringLiteral("GRUB_DISABLE_OS_PROBER")] = QStringLiteral("true");
0344         }
0345     }
0346     if (m_dirtyBits.testBit(grubGfxmodeDirty)) {
0347         if (ui->combobox_gfxmode->currentIndex() <= 0) {
0348             qCritical() << "Something went terribly wrong!";
0349         } else {
0350             m_settings[QStringLiteral("GRUB_GFXMODE")] = quoteWord(ui->combobox_gfxmode->itemData(ui->combobox_gfxmode->currentIndex()).toString());
0351         }
0352     }
0353     if (m_dirtyBits.testBit(grubGfxpayloadLinuxDirty)) {
0354         if (ui->combobox_gfxpayload->currentIndex() <= 0) {
0355             qCritical() << "Something went terribly wrong!";
0356         } else if (ui->combobox_gfxpayload->currentIndex() == 1) {
0357             m_settings.remove(QStringLiteral("GRUB_GFXPAYLOAD_LINUX"));
0358         } else if (ui->combobox_gfxpayload->currentIndex() > 1) {
0359             m_settings[QStringLiteral("GRUB_GFXPAYLOAD_LINUX")] =
0360                 quoteWord(ui->combobox_gfxpayload->itemData(ui->combobox_gfxpayload->currentIndex()).toString());
0361         }
0362     }
0363     if (m_dirtyBits.testBit(grubColorNormalDirty)) {
0364         QString normalForeground = ui->combobox_normalForeground->itemData(ui->combobox_normalForeground->currentIndex()).toString();
0365         QString normalBackground = ui->combobox_normalBackground->itemData(ui->combobox_normalBackground->currentIndex()).toString();
0366         if (normalForeground.compare(QLatin1String("light-gray")) != 0 || normalBackground.compare(QLatin1String("black")) != 0) {
0367             m_settings[QStringLiteral("GRUB_COLOR_NORMAL")] = normalForeground + QLatin1Char('/') + normalBackground;
0368         } else {
0369             m_settings.remove(QStringLiteral("GRUB_COLOR_NORMAL"));
0370         }
0371     }
0372     if (m_dirtyBits.testBit(grubColorHighlightDirty)) {
0373         QString highlightForeground = ui->combobox_highlightForeground->itemData(ui->combobox_highlightForeground->currentIndex()).toString();
0374         QString highlightBackground = ui->combobox_highlightBackground->itemData(ui->combobox_highlightBackground->currentIndex()).toString();
0375         if (highlightForeground.compare(QLatin1String("black")) != 0 || highlightBackground.compare(QLatin1String("light-gray")) != 0) {
0376             m_settings[QStringLiteral("GRUB_COLOR_HIGHLIGHT")] = highlightForeground + QLatin1Char('/') + highlightBackground;
0377         } else {
0378             m_settings.remove(QStringLiteral("GRUB_COLOR_HIGHLIGHT"));
0379         }
0380     }
0381     if (m_dirtyBits.testBit(grubBackgroundDirty)) {
0382         QString background = ui->kurlrequester_background->url().toLocalFile();
0383         if (!background.isEmpty()) {
0384             m_settings[QStringLiteral("GRUB_BACKGROUND")] = quoteWord(background);
0385         } else {
0386             m_settings.remove(QStringLiteral("GRUB_BACKGROUND"));
0387         }
0388     }
0389     if (m_dirtyBits.testBit(grubThemeDirty)) {
0390         QString theme = ui->kurlrequester_theme->url().toLocalFile();
0391         if (!theme.isEmpty()) {
0392             m_settings[QStringLiteral("GRUB_THEME")] = quoteWord(theme);
0393         } else {
0394             m_settings.remove(QStringLiteral("GRUB_THEME"));
0395         }
0396     }
0397     if (m_dirtyBits.testBit(grubCmdlineLinuxDefaultDirty)) {
0398         QString cmdlineLinuxDefault = ui->lineedit_cmdlineDefault->text();
0399         if (!cmdlineLinuxDefault.isEmpty()) {
0400             m_settings[QStringLiteral("GRUB_CMDLINE_LINUX_DEFAULT")] = quoteWord(cmdlineLinuxDefault);
0401         } else {
0402             m_settings.remove(QStringLiteral("GRUB_CMDLINE_LINUX_DEFAULT"));
0403         }
0404     }
0405     if (m_dirtyBits.testBit(grubCmdlineLinuxDirty)) {
0406         QString cmdlineLinux = ui->lineedit_cmdline->text();
0407         if (!cmdlineLinux.isEmpty()) {
0408             m_settings[QStringLiteral("GRUB_CMDLINE_LINUX")] = quoteWord(cmdlineLinux);
0409         } else {
0410             m_settings.remove(QStringLiteral("GRUB_CMDLINE_LINUX"));
0411         }
0412     }
0413     if (m_dirtyBits.testBit(grubTerminalDirty)) {
0414         QString terminal = ui->lineedit_terminal->text();
0415         if (!terminal.isEmpty()) {
0416             m_settings[QStringLiteral("GRUB_TERMINAL")] = quoteWord(terminal);
0417         } else {
0418             m_settings.remove(QStringLiteral("GRUB_TERMINAL"));
0419         }
0420     }
0421     if (m_dirtyBits.testBit(grubTerminalInputDirty)) {
0422         QString terminalInput = ui->lineedit_terminalInput->text();
0423         if (!terminalInput.isEmpty()) {
0424             m_settings[QStringLiteral("GRUB_TERMINAL_INPUT")] = quoteWord(terminalInput);
0425         } else {
0426             m_settings.remove(QStringLiteral("GRUB_TERMINAL_INPUT"));
0427         }
0428     }
0429     if (m_dirtyBits.testBit(grubTerminalOutputDirty)) {
0430         QString terminalOutput = ui->lineedit_terminalOutput->text();
0431         if (!terminalOutput.isEmpty()) {
0432             m_settings[QStringLiteral("GRUB_TERMINAL_OUTPUT")] = quoteWord(terminalOutput);
0433         } else {
0434             m_settings.remove(QStringLiteral("GRUB_TERMINAL_OUTPUT"));
0435         }
0436     }
0437     if (m_dirtyBits.testBit(grubDistributorDirty)) {
0438         QString distributor = ui->lineedit_distributor->text();
0439         if (!distributor.isEmpty()) {
0440             m_settings[QStringLiteral("GRUB_DISTRIBUTOR")] = quoteWord(distributor);
0441         } else {
0442             m_settings.remove(QStringLiteral("GRUB_DISTRIBUTOR"));
0443         }
0444     }
0445     if (m_dirtyBits.testBit(grubSerialCommandDirty)) {
0446         QString serialCommand = ui->lineedit_serial->text();
0447         if (!serialCommand.isEmpty()) {
0448             m_settings[QStringLiteral("GRUB_SERIAL_COMMAND")] = quoteWord(serialCommand);
0449         } else {
0450             m_settings.remove(QStringLiteral("GRUB_SERIAL_COMMAND"));
0451         }
0452     }
0453     if (m_dirtyBits.testBit(grubInitTuneDirty)) {
0454         QString initTune = ui->lineedit_initTune->text();
0455         if (!initTune.isEmpty()) {
0456             m_settings[QStringLiteral("GRUB_INIT_TUNE")] = quoteWord(initTune);
0457         } else {
0458             m_settings.remove(QStringLiteral("GRUB_INIT_TUNE"));
0459         }
0460     }
0461     if (m_dirtyBits.testBit(grubDisableLinuxUuidDirty)) {
0462         if (ui->checkBox_uuid->isChecked()) {
0463             m_settings.remove(QStringLiteral("GRUB_DISABLE_LINUX_UUID"));
0464         } else {
0465             m_settings[QStringLiteral("GRUB_DISABLE_LINUX_UUID")] = QStringLiteral("true");
0466         }
0467     }
0468 
0469     QString configFileContents;
0470     QTextStream stream(&configFileContents, QIODevice::WriteOnly | QIODevice::Text);
0471     QHash<QString, QString>::const_iterator it = m_settings.constBegin();
0472     QHash<QString, QString>::const_iterator end = m_settings.constEnd();
0473     for (; it != end; ++it) {
0474         stream << it.key() << '=' << it.value() << Qt::endl;
0475     }
0476 
0477     Action saveAction(QStringLiteral("org.kde.kcontrol.kcmgrub2.save"));
0478     saveAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmgrub2"));
0479     saveAction.addArgument(QStringLiteral("rawConfigFileContents"), configFileContents.toUtf8());
0480     saveAction.addArgument(QStringLiteral("rawDefaultEntry"),
0481                            !m_entries.isEmpty() ? grubDefault.toUtf8() : m_settings.value(QStringLiteral("GRUB_DEFAULT")).toUtf8());
0482     if (ui->combobox_language->currentIndex() > 0) {
0483         saveAction.addArgument(QStringLiteral("LANG"), qgetenv("LANG"));
0484         saveAction.addArgument(QStringLiteral("LANGUAGE"), m_settings.value(QStringLiteral("LANGUAGE")));
0485     }
0486     if (m_dirtyBits.testBit(memtestDirty)) {
0487         saveAction.addArgument(QStringLiteral("memtest"), ui->checkBox_memtest->isChecked());
0488     }
0489     saveAction.setParentWidget(widget());
0490     saveAction.setTimeout(60000);
0491 
0492     KAuth::ExecuteJob *saveJob = saveAction.execute(KAuth::Action::AuthorizeOnlyMode);
0493     if (!saveJob->exec()) {
0494         return;
0495     }
0496     saveJob = saveAction.execute();
0497 
0498     QProgressDialog progressDlg(widget());
0499     progressDlg.setWindowTitle(i18nc("@title:window Verb (gerund). Refers to current status.", "Saving"));
0500     progressDlg.setLabelText(i18nc("@info:progress", "Saving GRUB settings..."));
0501     progressDlg.setCancelButton(nullptr);
0502     progressDlg.setModal(true);
0503     progressDlg.setMinimum(0);
0504     progressDlg.setMaximum(0);
0505     progressDlg.show();
0506     connect(saveJob, &KJob::finished, &progressDlg, &QWidget::hide);
0507 
0508     if (saveJob->exec()) {
0509         QDialog *dialog = new QDialog(widget());
0510         dialog->setWindowTitle(i18nc("@title:window", "Information"));
0511         dialog->setModal(true);
0512         dialog->setAttribute(Qt::WA_DeleteOnClose);
0513 
0514         QPushButton *detailsButton = new QPushButton;
0515         detailsButton->setObjectName(QStringLiteral("detailsButton"));
0516         detailsButton->setText(QApplication::translate("KMessageBox", "&Details") + QStringLiteral(" >>"));
0517         detailsButton->setIcon(QIcon::fromTheme(QStringLiteral("help-about")));
0518 
0519         QDialogButtonBox *buttonBox = new QDialogButtonBox(dialog);
0520         buttonBox->addButton(detailsButton, QDialogButtonBox::HelpRole);
0521         buttonBox->addButton(QDialogButtonBox::Ok);
0522         buttonBox->button(QDialogButtonBox::Ok)->setFocus();
0523 
0524         KMessageBox::createKMessageBox(dialog,
0525                                        buttonBox,
0526                                        QMessageBox::Information,
0527                                        i18nc("@info", "Successfully saved GRUB settings."),
0528                                        QStringList(),
0529                                        QString(),
0530                                        nullptr,
0531                                        KMessageBox::Notify,
0532                                        QString::fromUtf8(saveJob->data().value(QStringLiteral("output")).toByteArray().constData())); // krazy:exclude=qclasses
0533         load();
0534     } else {
0535         KMessageBox::detailedError(widget(), i18nc("@info", "Failed to save GRUB settings."), saveJob->errorText());
0536     }
0537 }
0538 
0539 void KCMGRUB2::slotRemoveOldEntries()
0540 {
0541 #if HAVE_QAPT || HAVE_QPACKAGEKIT
0542     QPointer<RemoveDialog> removeDlg = new RemoveDialog(m_entries, widget());
0543     if (removeDlg->exec()) {
0544         load();
0545     }
0546     delete removeDlg;
0547 #endif
0548 }
0549 void KCMGRUB2::slotGrubSavedefaultChanged()
0550 {
0551     m_dirtyBits.setBit(grubSavedefaultDirty);
0552     markAsChanged();
0553 }
0554 void KCMGRUB2::slotGrubHiddenTimeoutToggled(bool checked)
0555 {
0556     ui->spinBox_hiddenTimeout->setEnabled(checked);
0557     ui->checkBox_hiddenTimeoutShowTimer->setEnabled(checked);
0558 }
0559 void KCMGRUB2::slotGrubHiddenTimeoutChanged()
0560 {
0561     m_dirtyBits.setBit(grubHiddenTimeoutDirty);
0562     markAsChanged();
0563 }
0564 void KCMGRUB2::slotGrubHiddenTimeoutQuietChanged()
0565 {
0566     m_dirtyBits.setBit(grubHiddenTimeoutQuietDirty);
0567     markAsChanged();
0568 }
0569 void KCMGRUB2::slotGrubTimeoutToggled(bool checked)
0570 {
0571     ui->radioButton_timeout0->setEnabled(checked);
0572     ui->radioButton_timeout->setEnabled(checked);
0573     ui->spinBox_timeout->setEnabled(checked && ui->radioButton_timeout->isChecked());
0574 }
0575 void KCMGRUB2::slotGrubTimeoutChanged()
0576 {
0577     m_dirtyBits.setBit(grubTimeoutDirty);
0578     markAsChanged();
0579 }
0580 void KCMGRUB2::slotGrubLanguageChanged()
0581 {
0582     m_dirtyBits.setBit(grubLocaleDirty);
0583     markAsChanged();
0584 }
0585 void KCMGRUB2::slotGrubDisableRecoveryChanged()
0586 {
0587     m_dirtyBits.setBit(grubDisableRecoveryDirty);
0588     markAsChanged();
0589 }
0590 void KCMGRUB2::slotMemtestChanged()
0591 {
0592     m_dirtyBits.setBit(memtestDirty);
0593     markAsChanged();
0594 }
0595 void KCMGRUB2::slotGrubDisableOsProberChanged()
0596 {
0597     m_dirtyBits.setBit(grubDisableOsProberDirty);
0598     markAsChanged();
0599 }
0600 void KCMGRUB2::slotGrubGfxmodeChanged()
0601 {
0602     if (ui->combobox_gfxmode->currentIndex() == 0) {
0603         bool ok;
0604         QRegExpValidator regExp(QRegExp(QLatin1String("\\d{3,4}x\\d{3,4}(x\\d{1,2})?")), this);
0605         QString resolution = TextInputDialog::getText(widget(),
0606                                                       i18nc("@title:window", "Enter screen resolution"),
0607                                                       i18nc("@label:textbox", "Please enter a GRUB resolution:"),
0608                                                       QString(),
0609                                                       &regExp,
0610                                                       &ok);
0611         if (ok) {
0612             if (!m_resolutions.contains(resolution)) {
0613                 QString gfxpayload = ui->combobox_gfxpayload->itemData(ui->combobox_gfxpayload->currentIndex()).toString();
0614                 m_resolutions.append(resolution);
0615                 sortResolutions();
0616                 showResolutions();
0617                 ui->combobox_gfxpayload->setCurrentIndex(ui->combobox_gfxpayload->findData(gfxpayload));
0618             }
0619             ui->combobox_gfxmode->setCurrentIndex(ui->combobox_gfxmode->findData(resolution));
0620         } else {
0621             ui->combobox_gfxmode->setCurrentIndex(ui->combobox_gfxmode->findData(QLatin1String("640x480")));
0622         }
0623     }
0624     m_dirtyBits.setBit(grubGfxmodeDirty);
0625     markAsChanged();
0626 }
0627 void KCMGRUB2::slotGrubGfxpayloadLinuxChanged()
0628 {
0629     if (ui->combobox_gfxpayload->currentIndex() == 0) {
0630         bool ok;
0631         QRegExpValidator regExp(QRegExp(QLatin1String("\\d{3,4}x\\d{3,4}(x\\d{1,2})?")), this);
0632         QString resolution = TextInputDialog::getText(widget(),
0633                                                       i18nc("@title:window", "Enter screen resolution"),
0634                                                       i18nc("@label:textbox", "Please enter a Linux boot resolution:"),
0635                                                       QString(),
0636                                                       &regExp,
0637                                                       &ok);
0638         if (ok) {
0639             if (!m_resolutions.contains(resolution)) {
0640                 QString gfxmode = ui->combobox_gfxmode->itemData(ui->combobox_gfxmode->currentIndex()).toString();
0641                 m_resolutions.append(resolution);
0642                 sortResolutions();
0643                 showResolutions();
0644                 ui->combobox_gfxmode->setCurrentIndex(ui->combobox_gfxmode->findData(gfxmode));
0645             }
0646             ui->combobox_gfxpayload->setCurrentIndex(ui->combobox_gfxpayload->findData(resolution));
0647         } else {
0648             ui->combobox_gfxpayload->setCurrentIndex(ui->combobox_gfxpayload->findData(QString()));
0649         }
0650     }
0651     m_dirtyBits.setBit(grubGfxpayloadLinuxDirty);
0652     markAsChanged();
0653 }
0654 void KCMGRUB2::slotResolutionsRefresh()
0655 {
0656     m_resolutionsForceRead = true;
0657     load();
0658 }
0659 void KCMGRUB2::slotGrubColorNormalChanged()
0660 {
0661     m_dirtyBits.setBit(grubColorNormalDirty);
0662     markAsChanged();
0663 }
0664 void KCMGRUB2::slotGrubColorHighlightChanged()
0665 {
0666     m_dirtyBits.setBit(grubColorHighlightDirty);
0667     markAsChanged();
0668 }
0669 void KCMGRUB2::slowGrubBackgroundChanged()
0670 {
0671     ui->pushbutton_preview->setEnabled(!ui->kurlrequester_background->text().isEmpty());
0672     m_dirtyBits.setBit(grubBackgroundDirty);
0673     markAsChanged();
0674 }
0675 void KCMGRUB2::slotPreviewGrubBackground()
0676 {
0677     QFile file(ui->kurlrequester_background->url().toLocalFile());
0678     if (!file.open(QIODevice::ReadOnly)) {
0679         return;
0680     }
0681 
0682     // TODO: Need something more elegant.
0683     QDialog *dialog = new QDialog(widget());
0684     QLabel *label = new QLabel(dialog);
0685     label->setPixmap(QPixmap::fromImage(QImage::fromData(file.readAll())).scaled(QDesktopWidget().screenGeometry(widget()).size()));
0686     dialog->setAttribute(Qt::WA_DeleteOnClose);
0687     dialog->showFullScreen();
0688     KMessageBox::information(dialog,
0689                              i18nc("@info", "Press <shortcut>Escape</shortcut> to exit fullscreen mode."),
0690                              QString(),
0691                              QStringLiteral("GRUBFullscreenPreview"));
0692 }
0693 void KCMGRUB2::slotCreateGrubBackground()
0694 {
0695 #if HAVE_IMAGEMAGICK
0696     QPointer<ConvertDialog> convertDlg = new ConvertDialog(widget());
0697     QString resolution = ui->combobox_gfxmode->itemData(ui->combobox_gfxmode->currentIndex()).toString();
0698     convertDlg->setResolution(resolution.section(QLatin1Char('x'), 0, 0).toInt(), resolution.section(QLatin1Char('x'), 1, 1).toInt());
0699     connect(convertDlg.data(), &ConvertDialog::splashImageCreated, ui->kurlrequester_background, &KUrlRequester::setText);
0700     convertDlg->exec();
0701     delete convertDlg;
0702 #endif
0703 }
0704 void KCMGRUB2::slotGrubThemeChanged()
0705 {
0706     m_dirtyBits.setBit(grubThemeDirty);
0707     markAsChanged();
0708 }
0709 void KCMGRUB2::slotGrubCmdlineLinuxDefaultChanged()
0710 {
0711     m_dirtyBits.setBit(grubCmdlineLinuxDefaultDirty);
0712     markAsChanged();
0713 }
0714 void KCMGRUB2::slotGrubCmdlineLinuxChanged()
0715 {
0716     m_dirtyBits.setBit(grubCmdlineLinuxDirty);
0717     markAsChanged();
0718 }
0719 void KCMGRUB2::slotGrubTerminalChanged()
0720 {
0721     QString grubTerminal = ui->lineedit_terminal->text();
0722     ui->lineedit_terminalInput->setReadOnly(!grubTerminal.isEmpty());
0723     ui->lineedit_terminalOutput->setReadOnly(!grubTerminal.isEmpty());
0724     ui->lineedit_terminalInput->setText(!grubTerminal.isEmpty() ? grubTerminal : unquoteWord(m_settings.value(QStringLiteral("GRUB_TERMINAL_INPUT"))));
0725     ui->lineedit_terminalOutput->setText(!grubTerminal.isEmpty() ? grubTerminal : unquoteWord(m_settings.value(QStringLiteral("GRUB_TERMINAL_OUTPUT"))));
0726     m_dirtyBits.setBit(grubTerminalDirty);
0727 }
0728 void KCMGRUB2::slotGrubTerminalInputChanged()
0729 {
0730     m_dirtyBits.setBit(grubTerminalInputDirty);
0731     markAsChanged();
0732 }
0733 void KCMGRUB2::slotGrubTerminalOutputChanged()
0734 {
0735     m_dirtyBits.setBit(grubTerminalOutputDirty);
0736     markAsChanged();
0737 }
0738 void KCMGRUB2::slotGrubDistributorChanged()
0739 {
0740     m_dirtyBits.setBit(grubDistributorDirty);
0741     markAsChanged();
0742 }
0743 void KCMGRUB2::slotGrubSerialCommandChanged()
0744 {
0745     m_dirtyBits.setBit(grubSerialCommandDirty);
0746     markAsChanged();
0747 }
0748 void KCMGRUB2::slotGrubInitTuneChanged()
0749 {
0750     m_dirtyBits.setBit(grubInitTuneDirty);
0751     markAsChanged();
0752 }
0753 void KCMGRUB2::slotGrubDisableLinuxUuidChanged()
0754 {
0755     m_dirtyBits.setBit(grubDisableLinuxUuidDirty);
0756     markAsChanged();
0757 }
0758 void KCMGRUB2::slotInstallBootloader()
0759 {
0760     QPointer<InstallDialog> installDlg = new InstallDialog(widget());
0761     installDlg->exec();
0762     delete installDlg;
0763 }
0764 
0765 void KCMGRUB2::slotUpdateSuggestions()
0766 {
0767     if (!sender()->isWidgetType()) {
0768         return;
0769     }
0770 
0771     QLineEdit *lineEdit = nullptr;
0772     if (ui->pushbutton_cmdlineDefaultSuggestions->isDown()) {
0773         lineEdit = ui->lineedit_cmdlineDefault;
0774     } else if (ui->pushbutton_cmdlineSuggestions->isDown()) {
0775         lineEdit = ui->lineedit_cmdline;
0776     } else if (ui->pushbutton_terminalSuggestions->isDown()) {
0777         lineEdit = ui->lineedit_terminal;
0778     } else if (ui->pushbutton_terminalInputSuggestions->isDown()) {
0779         lineEdit = ui->lineedit_terminalInput;
0780     } else if (ui->pushbutton_terminalOutputSuggestions->isDown()) {
0781         lineEdit = ui->lineedit_terminalOutput;
0782     } else {
0783         return;
0784     }
0785 
0786     const auto actions = qobject_cast<const QWidget *>(sender())->actions();
0787     for (QAction *action : actions) {
0788         if (!action->isCheckable()) {
0789             action->setCheckable(true);
0790         }
0791         action->setChecked(lineEdit->text().contains(QRegExp(QString(QLatin1String("\\b%1\\b")).arg(action->data().toString()))));
0792     }
0793 }
0794 void KCMGRUB2::slotTriggeredSuggestion(QAction *action)
0795 {
0796     QLineEdit *lineEdit = nullptr;
0797     void (KCMGRUB2::*updateFunction)() = nullptr;
0798     if (ui->pushbutton_cmdlineDefaultSuggestions->isDown()) {
0799         lineEdit = ui->lineedit_cmdlineDefault;
0800         updateFunction = &KCMGRUB2::slotGrubCmdlineLinuxDefaultChanged;
0801     } else if (ui->pushbutton_cmdlineSuggestions->isDown()) {
0802         lineEdit = ui->lineedit_cmdline;
0803         updateFunction = &KCMGRUB2::slotGrubCmdlineLinuxChanged;
0804     } else if (ui->pushbutton_terminalSuggestions->isDown()) {
0805         lineEdit = ui->lineedit_terminal;
0806         updateFunction = &KCMGRUB2::slotGrubTerminalChanged;
0807     } else if (ui->pushbutton_terminalInputSuggestions->isDown()) {
0808         lineEdit = ui->lineedit_terminalInput;
0809         updateFunction = &KCMGRUB2::slotGrubTerminalInputChanged;
0810     } else if (ui->pushbutton_terminalOutputSuggestions->isDown()) {
0811         lineEdit = ui->lineedit_terminalOutput;
0812         updateFunction = &KCMGRUB2::slotGrubTerminalOutputChanged;
0813     } else {
0814         return;
0815     }
0816 
0817     QString lineEditText = lineEdit->text();
0818     if (!action->isChecked()) {
0819         lineEdit->setText(lineEditText.remove(QRegExp(QString(QLatin1String("\\b%1\\b")).arg(action->data().toString()))).simplified());
0820     } else {
0821         lineEdit->setText(lineEditText.isEmpty() ? action->data().toString() : lineEditText + QLatin1Char(' ') + action->data().toString());
0822     }
0823     (this->*updateFunction)();
0824 }
0825 
0826 void KCMGRUB2::setupColors(std::initializer_list<ColorInfo> colorInfos)
0827 {
0828     for (const auto &ci : colorInfos) {
0829         QPixmap colorPixmap(16, 16);
0830         colorPixmap.fill(ci.color);
0831         const QIcon color(colorPixmap);
0832         ui->combobox_normalForeground->addItem(color, ci.text, ci.grubColor);
0833         ui->combobox_highlightForeground->addItem(color, ci.text, ci.grubColor);
0834         ui->combobox_normalBackground->addItem(color, ci.text, ci.grubColor);
0835         ui->combobox_highlightBackground->addItem(color, ci.text, ci.grubColor);
0836     }
0837 }
0838 
0839 void KCMGRUB2::setupObjects()
0840 {
0841     setButtons(Default | Apply);
0842 
0843     m_dirtyBits.resize(lastDirtyBit);
0844     m_resolutionsEmpty = true;
0845     m_resolutionsForceRead = false;
0846 
0847     QTreeView *view = new QTreeView(ui->combobox_default);
0848     view->setHeaderHidden(true);
0849     view->setItemsExpandable(false);
0850     view->setRootIsDecorated(false);
0851     ui->combobox_default->setView(view);
0852 
0853     ui->pushbutton_remove->setIcon(QIcon::fromTheme(QStringLiteral("list-remove")));
0854     ui->pushbutton_remove->setVisible(HAVE_QAPT || HAVE_QPACKAGEKIT);
0855 
0856     ui->toolButton_refreshGfxmode->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
0857     ui->toolButton_refreshGfxpayload->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh")));
0858 
0859     QPixmap black(16, 16), transparent(16, 16);
0860     black.fill(Qt::black);
0861     transparent.fill(Qt::transparent);
0862     ui->combobox_normalForeground->addItem(QIcon(black), i18nc("@item:inlistbox Refers to color.", "Black"), QLatin1String("black"));
0863     ui->combobox_highlightForeground->addItem(QIcon(black), i18nc("@item:inlistbox Refers to color.", "Black"), QLatin1String("black"));
0864     ui->combobox_normalBackground->addItem(QIcon(transparent), i18nc("@item:inlistbox Refers to color.", "Transparent"), QLatin1String("black"));
0865     ui->combobox_highlightBackground->addItem(QIcon(transparent), i18nc("@item:inlistbox Refers to color.", "Transparent"), QLatin1String("black"));
0866 
0867     setupColors({
0868         {QStringLiteral("blue"), i18nc("@item:inlistbox Refers to color.", "Blue"), QColorConstants::Svg::blue},
0869         {QStringLiteral("cyan"), i18nc("@item:inlistbox Refers to color.", "Cyan"), QColorConstants::Svg::cyan},
0870         {QStringLiteral("dark-gray"), i18nc("@item:inlistbox Refers to color.", "Dark Gray"), QColorConstants::Svg::darkgray},
0871         {QStringLiteral("green"), i18nc("@item:inlistbox Refers to color.", "Green"), QColorConstants::Svg::green},
0872         {QStringLiteral("light-cyan"), i18nc("@item:inlistbox Refers to color.", "Light Cyan"), QColorConstants::Svg::lightcyan},
0873         {QStringLiteral("light-blue"), i18nc("@item:inlistbox Refers to color.", "Light Blue"), QColorConstants::Svg::lightblue},
0874         {QStringLiteral("light-green"), i18nc("@item:inlistbox Refers to color.", "Light Green"), QColorConstants::Svg::lightgreen},
0875         {QStringLiteral("light-gray"), i18nc("@item:inlistbox Refers to color.", "Light Gray"), QColorConstants::Svg::lightgray},
0876         {QStringLiteral("light-magenta"), i18nc("@item:inlistbox Refers to color.", "Light Magenta"), QColorConstants::Svg::magenta},
0877         {QStringLiteral("light-red"), i18nc("@item:inlistbox Refers to color.", "Light Red"), QColorConstants::Svg::orangered},
0878         {QStringLiteral("magenta"), i18nc("@item:inlistbox Refers to color.", "Magenta"), QColorConstants::Svg::darkmagenta},
0879         {QStringLiteral("red"), i18nc("@item:inlistbox Refers to color.", "Red"), QColorConstants::Svg::red},
0880         {QStringLiteral("white"), i18nc("@item:inlistbox Refers to color.", "White"), QColorConstants::Svg::white},
0881         {QStringLiteral("yellow"), i18nc("@item:inlistbox Refers to color.", "Yellow"), QColorConstants::Svg::yellow},
0882     });
0883 
0884     ui->combobox_normalForeground->setCurrentIndex(ui->combobox_normalForeground->findData(QLatin1String("light-gray")));
0885     ui->combobox_normalBackground->setCurrentIndex(ui->combobox_normalBackground->findData(QLatin1String("black")));
0886     ui->combobox_highlightForeground->setCurrentIndex(ui->combobox_highlightForeground->findData(QLatin1String("black")));
0887     ui->combobox_highlightBackground->setCurrentIndex(ui->combobox_highlightBackground->findData(QLatin1String("light-gray")));
0888 
0889     ui->pushbutton_preview->setIcon(QIcon::fromTheme(QStringLiteral("image-png")));
0890     ui->pushbutton_create->setIcon(QIcon::fromTheme(QStringLiteral("insert-image")));
0891     ui->pushbutton_create->setVisible(HAVE_IMAGEMAGICK);
0892 
0893     ui->pushbutton_cmdlineDefaultSuggestions->setIcon(QIcon::fromTheme(QStringLiteral("tools-wizard")));
0894     ui->pushbutton_cmdlineDefaultSuggestions->setMenu(new QMenu(ui->pushbutton_cmdlineDefaultSuggestions));
0895     ui->pushbutton_cmdlineDefaultSuggestions->menu()->addAction(i18nc("@action:inmenu", "Quiet Boot"))->setData(QLatin1String("quiet"));
0896     ui->pushbutton_cmdlineDefaultSuggestions->menu()->addAction(i18nc("@action:inmenu", "Show Splash Screen"))->setData(QLatin1String("splash"));
0897     ui->pushbutton_cmdlineDefaultSuggestions->menu()->addAction(i18nc("@action:inmenu", "Disable Plymouth"))->setData(QLatin1String("noplymouth"));
0898     ui->pushbutton_cmdlineDefaultSuggestions->menu()->addAction(i18nc("@action:inmenu", "Turn Off ACPI"))->setData(QLatin1String("acpi=off"));
0899     ui->pushbutton_cmdlineDefaultSuggestions->menu()->addAction(i18nc("@action:inmenu", "Turn Off APIC"))->setData(QLatin1String("noapic"));
0900     ui->pushbutton_cmdlineDefaultSuggestions->menu()->addAction(i18nc("@action:inmenu", "Turn Off Local APIC"))->setData(QLatin1String("nolapic"));
0901     ui->pushbutton_cmdlineDefaultSuggestions->menu()->addAction(i18nc("@action:inmenu", "Single User Mode"))->setData(QLatin1String("single"));
0902     ui->pushbutton_cmdlineSuggestions->setIcon(QIcon::fromTheme(QStringLiteral("tools-wizard")));
0903     ui->pushbutton_cmdlineSuggestions->setMenu(new QMenu(ui->pushbutton_cmdlineSuggestions));
0904     ui->pushbutton_cmdlineSuggestions->menu()->addAction(i18nc("@action:inmenu", "Quiet Boot"))->setData(QLatin1String("quiet"));
0905     ui->pushbutton_cmdlineSuggestions->menu()->addAction(i18nc("@action:inmenu", "Show Splash Screen"))->setData(QLatin1String("splash"));
0906     ui->pushbutton_cmdlineSuggestions->menu()->addAction(i18nc("@action:inmenu", "Disable Plymouth"))->setData(QLatin1String("noplymouth"));
0907     ui->pushbutton_cmdlineSuggestions->menu()->addAction(i18nc("@action:inmenu", "Turn Off ACPI"))->setData(QLatin1String("acpi=off"));
0908     ui->pushbutton_cmdlineSuggestions->menu()->addAction(i18nc("@action:inmenu", "Turn Off APIC"))->setData(QLatin1String("noapic"));
0909     ui->pushbutton_cmdlineSuggestions->menu()->addAction(i18nc("@action:inmenu", "Turn Off Local APIC"))->setData(QLatin1String("nolapic"));
0910     ui->pushbutton_cmdlineSuggestions->menu()->addAction(i18nc("@action:inmenu", "Single User Mode"))->setData(QLatin1String("single"));
0911     ui->pushbutton_terminalSuggestions->setIcon(QIcon::fromTheme(QStringLiteral("tools-wizard")));
0912     ui->pushbutton_terminalSuggestions->setMenu(new QMenu(ui->pushbutton_terminalSuggestions));
0913     ui->pushbutton_terminalSuggestions->menu()->addAction(i18nc("@action:inmenu", "PC BIOS && EFI Console"))->setData(QLatin1String("console"));
0914     ui->pushbutton_terminalSuggestions->menu()->addAction(i18nc("@action:inmenu", "Serial Terminal"))->setData(QLatin1String("serial"));
0915     ui->pushbutton_terminalSuggestions->menu()
0916         ->addAction(i18nc("@action:inmenu 'Open' is an adjective here, not a verb. 'Open Firmware' is a former IEEE standard.", "Open Firmware Console"))
0917         ->setData(QLatin1String("ofconsole"));
0918     ui->pushbutton_terminalInputSuggestions->setIcon(QIcon::fromTheme(QStringLiteral("tools-wizard")));
0919     ui->pushbutton_terminalInputSuggestions->setMenu(new QMenu(ui->pushbutton_terminalInputSuggestions));
0920     ui->pushbutton_terminalInputSuggestions->menu()->addAction(i18nc("@action:inmenu", "PC BIOS && EFI Console"))->setData(QLatin1String("console"));
0921     ui->pushbutton_terminalInputSuggestions->menu()->addAction(i18nc("@action:inmenu", "Serial Terminal"))->setData(QLatin1String("serial"));
0922     ui->pushbutton_terminalInputSuggestions->menu()
0923         ->addAction(i18nc("@action:inmenu 'Open' is an adjective here, not a verb. 'Open Firmware' is a former IEEE standard.", "Open Firmware Console"))
0924         ->setData(QLatin1String("ofconsole"));
0925     ui->pushbutton_terminalInputSuggestions->menu()->addAction(i18nc("@action:inmenu", "PC AT Keyboard (Coreboot)"))->setData(QLatin1String("at_keyboard"));
0926     ui->pushbutton_terminalInputSuggestions->menu()
0927         ->addAction(i18nc("@action:inmenu", "USB Keyboard (HID Boot Protocol)"))
0928         ->setData(QLatin1String("usb_keyboard"));
0929     ui->pushbutton_terminalOutputSuggestions->setIcon(QIcon::fromTheme(QStringLiteral("tools-wizard")));
0930     ui->pushbutton_terminalOutputSuggestions->setMenu(new QMenu(ui->pushbutton_terminalOutputSuggestions));
0931     ui->pushbutton_terminalOutputSuggestions->menu()->addAction(i18nc("@action:inmenu", "PC BIOS && EFI Console"))->setData(QLatin1String("console"));
0932     ui->pushbutton_terminalOutputSuggestions->menu()->addAction(i18nc("@action:inmenu", "Serial Terminal"))->setData(QLatin1String("serial"));
0933     ui->pushbutton_terminalOutputSuggestions->menu()
0934         ->addAction(i18nc("@action:inmenu 'Open' is an adjective here, not a verb. 'Open Firmware' is a former IEEE standard.", "Open Firmware Console"))
0935         ->setData(QLatin1String("ofconsole"));
0936     ui->pushbutton_terminalOutputSuggestions->menu()->addAction(i18nc("@action:inmenu", "Graphics Mode Output"))->setData(QLatin1String("gfxterm"));
0937     ui->pushbutton_terminalOutputSuggestions->menu()->addAction(i18nc("@action:inmenu", "VGA Text Output (Coreboot)"))->setData(QLatin1String("vga_text"));
0938 
0939     ui->pushbutton_install->setIcon(QIcon::fromTheme(QStringLiteral("system-software-update")));
0940 }
0941 void KCMGRUB2::setupConnections()
0942 {
0943     connect(ui->combobox_default, qOverload<int>(&QComboBox::activated), this, &KCMGRUB2::markAsChanged);
0944     connect(ui->pushbutton_remove, &QAbstractButton::clicked, this, &KCMGRUB2::slotRemoveOldEntries);
0945     connect(ui->checkBox_savedefault, &QAbstractButton::clicked, this, &KCMGRUB2::slotGrubSavedefaultChanged);
0946 
0947     connect(ui->checkBox_hiddenTimeout, &QAbstractButton::toggled, this, &KCMGRUB2::slotGrubHiddenTimeoutToggled);
0948     connect(ui->checkBox_hiddenTimeout, &QAbstractButton::clicked, this, &KCMGRUB2::slotGrubHiddenTimeoutChanged);
0949     connect(ui->spinBox_hiddenTimeout, qOverload<int>(&QSpinBox::valueChanged), this, &KCMGRUB2::slotGrubHiddenTimeoutChanged);
0950     connect(ui->checkBox_hiddenTimeoutShowTimer, &QAbstractButton::clicked, this, &KCMGRUB2::slotGrubHiddenTimeoutQuietChanged);
0951 
0952     connect(ui->checkBox_timeout, &QAbstractButton::toggled, this, &KCMGRUB2::slotGrubTimeoutToggled);
0953     connect(ui->checkBox_timeout, &QAbstractButton::clicked, this, &KCMGRUB2::slotGrubTimeoutChanged);
0954     connect(ui->radioButton_timeout0, &QAbstractButton::clicked, this, &KCMGRUB2::slotGrubTimeoutChanged);
0955     connect(ui->radioButton_timeout, &QAbstractButton::toggled, ui->spinBox_timeout, &QWidget::setEnabled);
0956     connect(ui->radioButton_timeout, &QAbstractButton::clicked, this, &KCMGRUB2::slotGrubTimeoutChanged);
0957     connect(ui->spinBox_timeout, qOverload<int>(&QSpinBox::valueChanged), this, &KCMGRUB2::slotGrubTimeoutChanged);
0958 
0959     connect(ui->combobox_language, qOverload<int>(&QComboBox::activated), this, &KCMGRUB2::slotGrubLanguageChanged);
0960     connect(ui->checkBox_recovery, &QAbstractButton::clicked, this, &KCMGRUB2::slotGrubDisableRecoveryChanged);
0961     connect(ui->checkBox_memtest, &QAbstractButton::clicked, this, &KCMGRUB2::slotMemtestChanged);
0962     connect(ui->checkBox_osProber, &QAbstractButton::clicked, this, &KCMGRUB2::slotGrubDisableOsProberChanged);
0963 
0964     connect(ui->combobox_gfxmode, qOverload<int>(&QComboBox::activated), this, &KCMGRUB2::slotGrubGfxmodeChanged);
0965     connect(ui->toolButton_refreshGfxmode, &QAbstractButton::clicked, this, &KCMGRUB2::slotResolutionsRefresh);
0966     connect(ui->combobox_gfxpayload, qOverload<int>(&QComboBox::activated), this, &KCMGRUB2::slotGrubGfxpayloadLinuxChanged);
0967     connect(ui->toolButton_refreshGfxpayload, &QAbstractButton::clicked, this, &KCMGRUB2::slotResolutionsRefresh);
0968 
0969     connect(ui->combobox_normalForeground, qOverload<int>(&QComboBox::activated), this, &KCMGRUB2::slotGrubColorNormalChanged);
0970     connect(ui->combobox_normalBackground, qOverload<int>(&QComboBox::activated), this, &KCMGRUB2::slotGrubColorNormalChanged);
0971     connect(ui->combobox_highlightForeground, qOverload<int>(&QComboBox::activated), this, &KCMGRUB2::slotGrubColorHighlightChanged);
0972     connect(ui->combobox_highlightBackground, qOverload<int>(&QComboBox::activated), this, &KCMGRUB2::slotGrubColorHighlightChanged);
0973 
0974     connect(ui->kurlrequester_background, &KUrlRequester::textChanged, this, &KCMGRUB2::slowGrubBackgroundChanged);
0975     connect(ui->pushbutton_preview, &QAbstractButton::clicked, this, &KCMGRUB2::slotPreviewGrubBackground);
0976     connect(ui->pushbutton_create, &QAbstractButton::clicked, this, &KCMGRUB2::slotCreateGrubBackground);
0977     connect(ui->kurlrequester_theme, &KUrlRequester::textChanged, this, &KCMGRUB2::slotGrubThemeChanged);
0978 
0979     connect(ui->lineedit_cmdlineDefault, &QLineEdit::textEdited, this, &KCMGRUB2::slotGrubCmdlineLinuxDefaultChanged);
0980     connect(ui->pushbutton_cmdlineDefaultSuggestions->menu(), &QMenu::aboutToShow, this, &KCMGRUB2::slotUpdateSuggestions);
0981     connect(ui->pushbutton_cmdlineDefaultSuggestions->menu(), &QMenu::triggered, this, &KCMGRUB2::slotTriggeredSuggestion);
0982     connect(ui->lineedit_cmdline, &QLineEdit::textEdited, this, &KCMGRUB2::slotGrubCmdlineLinuxChanged);
0983     connect(ui->pushbutton_cmdlineSuggestions->menu(), &QMenu::aboutToShow, this, &KCMGRUB2::slotUpdateSuggestions);
0984     connect(ui->pushbutton_cmdlineSuggestions->menu(), &QMenu::triggered, this, &KCMGRUB2::slotTriggeredSuggestion);
0985 
0986     connect(ui->lineedit_terminal, &QLineEdit::textEdited, this, &KCMGRUB2::slotGrubTerminalChanged);
0987     connect(ui->pushbutton_terminalSuggestions->menu(), &QMenu::aboutToShow, this, &KCMGRUB2::slotUpdateSuggestions);
0988     connect(ui->pushbutton_terminalSuggestions->menu(), &QMenu::triggered, this, &KCMGRUB2::slotTriggeredSuggestion);
0989     connect(ui->lineedit_terminalInput, &QLineEdit::textEdited, this, &KCMGRUB2::slotGrubTerminalInputChanged);
0990     connect(ui->pushbutton_terminalInputSuggestions->menu(), &QMenu::aboutToShow, this, &KCMGRUB2::slotUpdateSuggestions);
0991     connect(ui->pushbutton_terminalInputSuggestions->menu(), &QMenu::triggered, this, &KCMGRUB2::slotTriggeredSuggestion);
0992     connect(ui->lineedit_terminalOutput, &QLineEdit::textEdited, this, &KCMGRUB2::slotGrubTerminalOutputChanged);
0993     connect(ui->pushbutton_terminalOutputSuggestions->menu(), &QMenu::aboutToShow, this, &KCMGRUB2::slotUpdateSuggestions);
0994     connect(ui->pushbutton_terminalOutputSuggestions->menu(), &QMenu::triggered, this, &KCMGRUB2::slotTriggeredSuggestion);
0995 
0996     connect(ui->lineedit_distributor, &QLineEdit::textEdited, this, &KCMGRUB2::slotGrubDistributorChanged);
0997     connect(ui->lineedit_serial, &QLineEdit::textEdited, this, &KCMGRUB2::slotGrubSerialCommandChanged);
0998     connect(ui->lineedit_initTune, &QLineEdit::textEdited, this, &KCMGRUB2::slotGrubInitTuneChanged);
0999     connect(ui->checkBox_uuid, &QAbstractButton::clicked, this, &KCMGRUB2::slotGrubDisableLinuxUuidChanged);
1000 
1001     connect(ui->pushbutton_install, &QAbstractButton::clicked, this, &KCMGRUB2::slotInstallBootloader);
1002 }
1003 
1004 bool KCMGRUB2::readFile(const QString &fileName, QByteArray &fileContents)
1005 {
1006     QFile file(fileName);
1007     if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
1008         qDebug() << "Failed to open file for reading:" << fileName;
1009         qDebug() << "Error code:" << file.error();
1010         qDebug() << "Error description:" << file.errorString();
1011         qDebug() << "The helper will now attempt to read this file.";
1012         return false;
1013     }
1014     fileContents = file.readAll();
1015     return true;
1016 }
1017 void KCMGRUB2::readAll()
1018 {
1019     QByteArray fileContents;
1020     LoadOperations operations = NoOperation;
1021 
1022     if (readFile(grubMenuPath(), fileContents)) {
1023         parseEntries(QString::fromUtf8(fileContents.constData()));
1024     } else {
1025         operations |= MenuFile;
1026     }
1027     if (readFile(grubConfigPath(), fileContents)) {
1028         parseSettings(QString::fromUtf8(fileContents.constData()));
1029     } else {
1030         operations |= ConfigurationFile;
1031     }
1032     if (readFile(grubEnvPath(), fileContents)) {
1033         parseEnv(QString::fromUtf8(fileContents.constData()));
1034     } else {
1035         operations |= EnvironmentFile;
1036     }
1037     if (QFile::exists(grubMemtestPath())) {
1038         m_memtest = true;
1039         m_memtestOn = (bool)(QFile::permissions(grubMemtestPath()) & (QFile::ExeOwner | QFile::ExeGroup | QFile::ExeOther));
1040     } else {
1041         operations |= MemtestFile;
1042     }
1043 #if HAVE_HD
1044     if (m_resolutionsEmpty) {
1045         operations |= Vbe;
1046     }
1047 #endif
1048     if (QFileInfo(grubLocalePath()).isReadable()) {
1049         m_locales = QDir(grubLocalePath())
1050                         .entryList(QStringList() << QStringLiteral("*.mo"), QDir::Files)
1051                         .replaceInStrings(QRegExp(QLatin1String("\\.mo$")), QString());
1052     } else {
1053         operations |= Locales;
1054     }
1055 
1056     // Do not prompt for password if only the VBE operation is required, unless forced.
1057     if (operations && ((operations & (~Vbe)) || m_resolutionsForceRead)) {
1058         Action loadAction(QStringLiteral("org.kde.kcontrol.kcmgrub2.load"));
1059         loadAction.setHelperId(QStringLiteral("org.kde.kcontrol.kcmgrub2"));
1060         loadAction.addArgument(QStringLiteral("operations"), (int)(operations));
1061         loadAction.setParentWidget(this);
1062 
1063         KAuth::ExecuteJob *loadJob = loadAction.execute();
1064         if (!loadJob->exec()) {
1065             qCritical() << "KAuth error!";
1066             qCritical() << "Error code:" << loadJob->error();
1067             qCritical() << "Error description:" << loadJob->errorText();
1068             return;
1069         }
1070 
1071         if (operations.testFlag(MenuFile)) {
1072             if (loadJob->data().value(QStringLiteral("menuSuccess")).toBool()) {
1073                 parseEntries(QString::fromUtf8(loadJob->data().value(QStringLiteral("menuContents")).toByteArray().constData()));
1074             } else {
1075                 qCritical() << "Helper failed to read file:" << grubMenuPath();
1076                 qCritical() << "Error code:" << loadJob->data().value(QStringLiteral("menuError")).toInt();
1077                 qCritical() << "Error description:" << loadJob->data().value(QStringLiteral("menuErrorString")).toString();
1078             }
1079         }
1080         if (operations.testFlag(ConfigurationFile)) {
1081             if (loadJob->data().value(QStringLiteral("configSuccess")).toBool()) {
1082                 parseSettings(QString::fromUtf8(loadJob->data().value(QStringLiteral("configContents")).toByteArray().constData()));
1083             } else {
1084                 qCritical() << "Helper failed to read file:" << grubConfigPath();
1085                 qCritical() << "Error code:" << loadJob->data().value(QStringLiteral("configError")).toInt();
1086                 qCritical() << "Error description:" << loadJob->data().value(QStringLiteral("configErrorString")).toString();
1087             }
1088         }
1089         if (operations.testFlag(EnvironmentFile)) {
1090             if (loadJob->data().value(QStringLiteral("envSuccess")).toBool()) {
1091                 parseEnv(QString::fromUtf8(loadJob->data().value(QStringLiteral("envContents")).toByteArray().constData()));
1092             } else {
1093                 qCritical() << "Helper failed to read file:" << grubEnvPath();
1094                 qCritical() << "Error code:" << loadJob->data().value(QStringLiteral("envError")).toInt();
1095                 qCritical() << "Error description:" << loadJob->data().value(QStringLiteral("envErrorString")).toString();
1096             }
1097         }
1098         if (operations.testFlag(MemtestFile)) {
1099             m_memtest = loadJob->data().value(QStringLiteral("memtest")).toBool();
1100             if (m_memtest) {
1101                 m_memtestOn = loadJob->data().value(QStringLiteral("memtestOn")).toBool();
1102             }
1103         }
1104         if (operations.testFlag(Vbe)) {
1105             m_resolutions = loadJob->data().value(QStringLiteral("gfxmodes")).toStringList();
1106             m_resolutionsEmpty = false;
1107             m_resolutionsForceRead = false;
1108         }
1109         if (operations.testFlag(Locales)) {
1110             m_locales = loadJob->data().value(QStringLiteral("locales")).toStringList();
1111         }
1112     }
1113 }
1114 
1115 void KCMGRUB2::showLocales()
1116 {
1117     ui->combobox_language->clear();
1118     ui->combobox_language->addItem(i18nc("@item:inlistbox", "No translation"), QString());
1119 
1120     for (const QString &locale : qAsConst(m_locales)) {
1121         QString language = QLocale(locale).nativeLanguageName();
1122         if (language.isEmpty()) {
1123             language = QLocale(locale.split(QLatin1Char('@')).first()).nativeLanguageName();
1124             if (language.isEmpty()) {
1125                 language = QLocale(locale.split(QLatin1Char('@')).first().split(QLatin1Char('_')).first()).nativeLanguageName();
1126             }
1127         }
1128         ui->combobox_language->addItem(QStringLiteral("%1 (%2)").arg(language, locale), locale);
1129     }
1130 }
1131 void KCMGRUB2::sortResolutions()
1132 {
1133     for (int i = 0; i < m_resolutions.size(); i++) {
1134         if (m_resolutions.at(i).contains(QRegExp(QLatin1String("^\\d{3,4}x\\d{3,4}$")))) {
1135             m_resolutions[i] = QStringLiteral("%1x%2x0").arg(m_resolutions.at(i).section(QLatin1Char('x'), 0, 0).rightJustified(4, QLatin1Char('0')),
1136                                                              m_resolutions.at(i).section(QLatin1Char('x'), 1).rightJustified(4, QLatin1Char('0')));
1137         } else if (m_resolutions.at(i).contains(QRegExp(QLatin1String("^\\d{3,4}x\\d{3,4}x\\d{1,2}$")))) {
1138             m_resolutions[i] = QStringLiteral("%1x%2x%3")
1139                                    .arg(m_resolutions.at(i).section(QLatin1Char('x'), 0, 0).rightJustified(4, QLatin1Char('0')),
1140                                         m_resolutions.at(i).section(QLatin1Char('x'), 1, 1).rightJustified(4, QLatin1Char('0')),
1141                                         m_resolutions.at(i).section(QLatin1Char('x'), 2).rightJustified(2, QLatin1Char('0')));
1142         }
1143     }
1144     m_resolutions.sort();
1145     for (int i = 0; i < m_resolutions.size(); i++) {
1146         if (!m_resolutions.at(i).contains(QRegExp(QLatin1String("^\\d{3,4}x\\d{3,4}x\\d{1,2}$")))) {
1147             continue;
1148         }
1149         if (m_resolutions.at(i).startsWith(QLatin1Char('0'))) {
1150             m_resolutions[i].remove(0, 1);
1151         }
1152         m_resolutions[i].replace(QLatin1String("x0"), QLatin1String("x"));
1153         if (m_resolutions.at(i).endsWith(QLatin1Char('x'))) {
1154             m_resolutions[i].remove(m_resolutions.at(i).length() - 1, 1);
1155         }
1156     }
1157 }
1158 void KCMGRUB2::showResolutions()
1159 {
1160     ui->combobox_gfxmode->clear();
1161     ui->combobox_gfxmode->addItem(i18nc("@item:inlistbox Refers to screen resolution.", "Custom..."), QLatin1String("custom"));
1162     ui->combobox_gfxmode->addItem(i18nc("@item:inlistbox Refers to screen resolution.", "Auto"), QLatin1String("auto"));
1163 
1164     ui->combobox_gfxpayload->clear();
1165     ui->combobox_gfxpayload->addItem(i18nc("@item:inlistbox Refers to screen resolution.", "Custom..."), QLatin1String("custom"));
1166     ui->combobox_gfxpayload->addItem(i18nc("@item:inlistbox Refers to screen resolution.", "Auto"), QLatin1String("auto"));
1167     ui->combobox_gfxpayload->addItem(i18nc("@item:inlistbox Refers to screen resolution.", "Unspecified"), QString());
1168     ui->combobox_gfxpayload->addItem(i18nc("@item:inlistbox", "Boot in Text Mode"), QLatin1String("text"));
1169     ui->combobox_gfxpayload->addItem(i18nc("@item:inlistbox", "Keep GRUB's Resolution"), QLatin1String("keep"));
1170 
1171     for (const QString &resolution : qAsConst(m_resolutions)) {
1172         ui->combobox_gfxmode->addItem(resolution, resolution);
1173         ui->combobox_gfxpayload->addItem(resolution, resolution);
1174     }
1175 }
1176 
1177 QString KCMGRUB2::parseTitle(const QString &line)
1178 {
1179     QChar ch;
1180     QString entry, lineStr = line;
1181     QTextStream stream(&lineStr, QIODevice::ReadOnly | QIODevice::Text);
1182 
1183     stream.skipWhiteSpace();
1184     if (stream.atEnd()) {
1185         return QString();
1186     }
1187 
1188     stream >> ch;
1189     entry += ch;
1190     if (ch == QLatin1Char('\'')) {
1191         do {
1192             if (stream.atEnd()) {
1193                 return QString();
1194             }
1195             stream >> ch;
1196             entry += ch;
1197         } while (ch != QLatin1Char('\''));
1198     } else if (ch == QLatin1Char('"')) {
1199         do {
1200             if (stream.atEnd()) {
1201                 return QString();
1202             }
1203             stream >> ch;
1204             entry += ch;
1205         } while (ch != QLatin1Char('"') || entry.at(entry.size() - 2) == QLatin1Char('\\'));
1206     } else {
1207         do {
1208             if (stream.atEnd()) {
1209                 return QString();
1210             }
1211             stream >> ch;
1212             entry += ch;
1213         } while (!ch.isSpace() || entry.at(entry.size() - 2) == QLatin1Char('\\'));
1214         entry.chop(1); // remove trailing space
1215     }
1216     return entry;
1217 }
1218 void KCMGRUB2::parseEntries(const QString &config)
1219 {
1220     bool inEntry = false;
1221     int menuLvl = 0;
1222     QList<int> levelCount;
1223     levelCount.append(0);
1224     QList<Entry::Title> submenus;
1225     QString word, configStr = config;
1226     QTextStream stream(&configStr, QIODevice::ReadOnly | QIODevice::Text);
1227 
1228     m_entries.clear();
1229     while (!stream.atEnd()) {
1230         // Read the first word of the line
1231         stream >> word;
1232         if (stream.atEnd()) {
1233             return;
1234         }
1235         // If the first word is known, process the rest of the line
1236         if (word == QLatin1String("menuentry")) {
1237             if (inEntry) {
1238                 qCritical() << "Malformed configuration file! Aborting entries' parsing.";
1239                 qDebug() << "A 'menuentry' directive was detected inside the scope of a menuentry.";
1240                 m_entries.clear();
1241                 return;
1242             }
1243             Entry entry(parseTitle(stream.readLine()), levelCount.at(menuLvl), Entry::Menuentry, menuLvl);
1244             if (menuLvl > 0) {
1245                 entry.setAncestors(submenus);
1246             }
1247             m_entries.append(entry);
1248             levelCount[menuLvl]++;
1249             inEntry = true;
1250             continue;
1251         } else if (word == QLatin1String("submenu")) {
1252             if (inEntry) {
1253                 qCritical() << "Malformed configuration file! Aborting entries' parsing.";
1254                 qDebug() << "A 'submenu' directive was detected inside the scope of a menuentry.";
1255                 m_entries.clear();
1256                 return;
1257             }
1258             Entry entry(parseTitle(stream.readLine()), levelCount.at(menuLvl), Entry::Submenu, menuLvl);
1259             if (menuLvl > 0) {
1260                 entry.setAncestors(submenus);
1261             }
1262             m_entries.append(entry);
1263             submenus.append(entry.title());
1264             levelCount[menuLvl]++;
1265             levelCount.append(0);
1266             menuLvl++;
1267             continue;
1268         } else if (word == QLatin1String("linux")) {
1269             if (!inEntry) {
1270                 qCritical() << "Malformed configuration file! Aborting entries' parsing.";
1271                 qDebug() << "A 'linux' directive was detected outside the scope of a menuentry.";
1272                 m_entries.clear();
1273                 return;
1274             }
1275             stream >> word;
1276             m_entries.last().setKernel(word);
1277         } else if (word == QLatin1String("}")) {
1278             if (inEntry) {
1279                 inEntry = false;
1280             } else if (menuLvl > 0) {
1281                 submenus.removeLast();
1282                 levelCount[menuLvl] = 0;
1283                 menuLvl--;
1284             }
1285         }
1286         // Drop the rest of the line
1287         stream.readLine();
1288     }
1289 }
1290 void KCMGRUB2::parseSettings(const QString &config)
1291 {
1292     QString line, configStr = config;
1293     QTextStream stream(&configStr, QIODevice::ReadOnly | QIODevice::Text);
1294 
1295     m_settings.clear();
1296     while (!stream.atEnd()) {
1297         line = stream.readLine().trimmed();
1298         if (line.contains(QRegExp(QLatin1String("^(GRUB_|LANGUAGE=)")))) {
1299             m_settings[line.section(QLatin1Char('='), 0, 0)] = line.section(QLatin1Char('='), 1);
1300         }
1301     }
1302 }
1303 void KCMGRUB2::parseEnv(const QString &config)
1304 {
1305     QString line, configStr = config;
1306     QTextStream stream(&configStr, QIODevice::ReadOnly | QIODevice::Text);
1307 
1308     m_env.clear();
1309     while (!stream.atEnd()) {
1310         line = stream.readLine().trimmed();
1311         if (line.startsWith(QLatin1Char('#'))) {
1312             continue;
1313         }
1314         m_env[line.section(QLatin1Char('='), 0, 0)] = line.section(QLatin1Char('='), 1);
1315     }
1316 }
1317 
1318 #include "kcm_grub2.moc"