File indexing completed on 2024-07-21 07:58:04

0001 /*
0002     SPDX-FileCopyrightText: 2013 Lukas Tinkl <ltinkl@redhat.com>
0003 
0004     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0005 */
0006 
0007 #include "ipv4widget.h"
0008 #include "ipv4delegate.h"
0009 #include "ui_ipv4.h"
0010 
0011 #include <QDesktopServices>
0012 #include <QDialog>
0013 #include <QDialogButtonBox>
0014 #include <QFormLayout>
0015 #include <QHostInfo>
0016 #include <QItemSelection>
0017 #include <QNetworkAddressEntry>
0018 #include <QSpinBox>
0019 #include <QStandardItemModel>
0020 #include <QUrl>
0021 
0022 #include <KEditListWidget>
0023 #include <KLocalizedString>
0024 
0025 quint32 suggestNetmask(quint32 ip)
0026 {
0027     /*
0028         A   0       0.0.0.0 <-->127.255.255.255  255.0.0.0 <--->/8
0029         B   10      128.0.0.0 <>191.255.255.255  255.255.0.0 <->/16
0030         C   110     192.0.0.0 <>223.255.255.255  255.255.255.0 >/24
0031         D   1110    224.0.0.0 <>239.255.255.255  not defined <->not defined
0032         E   1111    240.0.0.0 <>255.255.255.254  not defined <->not defined
0033     */
0034     quint32 netmask = 0;
0035 
0036     if (!(ip & 0x80000000)) {
0037         // test 0 leading bit
0038         netmask = 0xFF000000;
0039     } else if (!(ip & 0x40000000)) {
0040         // test 10 leading bits
0041         netmask = 0xFFFF0000;
0042     } else if (!(ip & 0x20000000)) {
0043         // test 110 leading bits
0044         netmask = 0xFFFFFF00;
0045     }
0046 
0047     return netmask;
0048 }
0049 
0050 class IPv4Widget::Private
0051 {
0052 public:
0053     Private()
0054         : model(0, 3)
0055     {
0056         auto headerItem = new QStandardItem(i18nc("Header text for IPv4 address", "Address"));
0057         model.setHorizontalHeaderItem(0, headerItem);
0058         headerItem = new QStandardItem(i18nc("Header text for IPv4 netmask", "Netmask"));
0059         model.setHorizontalHeaderItem(1, headerItem);
0060         headerItem = new QStandardItem(i18nc("Header text for IPv4 gateway", "Gateway"));
0061         model.setHorizontalHeaderItem(2, headerItem);
0062     }
0063     QStandardItemModel model;
0064 };
0065 
0066 IPv4Widget::IPv4Widget(const NetworkManager::Setting::Ptr &setting, QWidget *parent, Qt::WindowFlags f)
0067     : SettingWidget(setting, parent, f)
0068     , m_ui(new Ui::IPv4Widget)
0069     , d(new IPv4Widget::Private())
0070 {
0071     m_ui->setupUi(this);
0072 
0073     m_ui->tableViewAddresses->setModel(&d->model);
0074     m_ui->tableViewAddresses->horizontalHeader()->setSectionResizeMode(QHeaderView::Interactive);
0075     m_ui->tableViewAddresses->horizontalHeader()->setStretchLastSection(true);
0076 
0077     auto ipDelegate = new IpV4Delegate(this);
0078     m_ui->tableViewAddresses->setItemDelegateForColumn(0, ipDelegate);
0079     m_ui->tableViewAddresses->setItemDelegateForColumn(1, ipDelegate);
0080     m_ui->tableViewAddresses->setItemDelegateForColumn(2, ipDelegate);
0081 
0082     connect(m_ui->btnAdd, &QPushButton::clicked, this, &IPv4Widget::slotAddIPAddress);
0083     connect(m_ui->btnRemove, &QPushButton::clicked, this, &IPv4Widget::slotRemoveIPAddress);
0084 
0085     connect(m_ui->dnsMorePushButton, &QPushButton::clicked, this, &IPv4Widget::slotDnsServers);
0086     connect(m_ui->dnsSearchMorePushButton, &QPushButton::clicked, this, &IPv4Widget::slotDnsDomains);
0087 
0088     connect(m_ui->tableViewAddresses->selectionModel(), &QItemSelectionModel::selectionChanged, this, &IPv4Widget::selectionChanged);
0089 
0090     connect(&d->model, &QStandardItemModel::itemChanged, this, &IPv4Widget::tableViewItemChanged);
0091 
0092     if (setting) {
0093         loadConfig(setting);
0094     }
0095 
0096     connect(m_ui->method, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &IPv4Widget::slotModeComboChanged);
0097     slotModeComboChanged(m_ui->method->currentIndex());
0098 
0099     connect(m_ui->btnRoutes, &QPushButton::clicked, this, &IPv4Widget::slotRoutesDialog);
0100     connect(m_ui->btnAdvanced, &QPushButton::clicked, this, &IPv4Widget::slotAdvancedDialog);
0101 
0102     // Connect for setting check
0103     watchChangedSetting();
0104 
0105     // Connect for validity check
0106     connect(m_ui->dns, &KLineEdit::textChanged, this, &IPv4Widget::slotWidgetChanged);
0107     connect(m_ui->method, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &IPv4Widget::slotWidgetChanged);
0108     connect(&d->model, &QStandardItemModel::dataChanged, this, &IPv4Widget::slotWidgetChanged);
0109     connect(&d->model, &QStandardItemModel::rowsRemoved, this, &IPv4Widget::slotWidgetChanged);
0110 
0111     KAcceleratorManager::manage(this);
0112 }
0113 
0114 IPv4Widget::~IPv4Widget()
0115 {
0116     delete d;
0117     delete m_ui;
0118 }
0119 
0120 void IPv4Widget::loadConfig(const NetworkManager::Setting::Ptr &setting)
0121 {
0122     NetworkManager::Ipv4Setting::Ptr ipv4Setting = setting.staticCast<NetworkManager::Ipv4Setting>();
0123 
0124     // BUG:406118
0125     // We don't have route-metric in the UI, maybe even won't have for now, but that doesn't mean we
0126     // want to loose it when it's configured manually in a config file
0127     m_tmpIpv4Setting.setRouteMetric(ipv4Setting->routeMetric());
0128 
0129     m_tmpIpv4Setting.setRoutes(ipv4Setting->routes());
0130     m_tmpIpv4Setting.setNeverDefault(ipv4Setting->neverDefault());
0131     m_tmpIpv4Setting.setIgnoreAutoRoutes(ipv4Setting->ignoreAutoRoutes());
0132 
0133     m_tmpIpv4Setting.setDhcpHostname(ipv4Setting->dhcpHostname());
0134     m_tmpIpv4Setting.setDhcpSendHostname(ipv4Setting->dhcpSendHostname());
0135     m_tmpIpv4Setting.setDadTimeout(ipv4Setting->dadTimeout());
0136 
0137     // method
0138     switch (ipv4Setting->method()) {
0139     case NetworkManager::Ipv4Setting::Automatic:
0140         if (ipv4Setting->ignoreAutoDns()) {
0141             m_ui->method->setCurrentIndex(AutomaticOnlyIP);
0142         } else {
0143             m_ui->method->setCurrentIndex(Automatic);
0144         }
0145         break;
0146     case NetworkManager::Ipv4Setting::Manual:
0147         m_ui->method->setCurrentIndex(Manual);
0148         break;
0149     case NetworkManager::Ipv4Setting::LinkLocal:
0150         m_ui->method->setCurrentIndex(LinkLocal);
0151         break;
0152     case NetworkManager::Ipv4Setting::Shared:
0153         m_ui->method->setCurrentIndex(Shared);
0154         break;
0155     case NetworkManager::Ipv4Setting::Disabled:
0156         m_ui->method->setCurrentIndex(Disabled);
0157         break;
0158     }
0159 
0160     // dns
0161     QStringList tmp;
0162     for (const QHostAddress &addr : ipv4Setting->dns()) {
0163         tmp.append(addr.toString());
0164     }
0165     m_ui->dns->setText(tmp.join(QStringLiteral(",")));
0166     m_ui->dnsSearch->setText(ipv4Setting->dnsSearch().join(QStringLiteral(",")));
0167 
0168     m_ui->dhcpClientId->setText(ipv4Setting->dhcpClientId());
0169 
0170     // addresses
0171     for (const NetworkManager::IpAddress &addr : ipv4Setting->addresses()) {
0172         QList<QStandardItem *> item{
0173             new QStandardItem(addr.ip().toString()),
0174             new QStandardItem(addr.netmask().toString()),
0175             new QStandardItem(addr.gateway().toString()),
0176         };
0177 
0178         d->model.appendRow(item);
0179     }
0180 
0181     // may-fail
0182     m_ui->ipv4RequiredCB->setChecked(!ipv4Setting->mayFail());
0183 }
0184 
0185 QVariantMap IPv4Widget::setting() const
0186 {
0187     NetworkManager::Ipv4Setting ipv4Setting;
0188 
0189     // BUG:406118
0190     // We don't have route-metric in the UI, maybe even won't have for now, but that doesn't mean we
0191     // want to loose it when it's configured manually in a config file
0192     ipv4Setting.setRouteMetric(m_tmpIpv4Setting.routeMetric());
0193 
0194     ipv4Setting.setRoutes(m_tmpIpv4Setting.routes());
0195     ipv4Setting.setNeverDefault(m_tmpIpv4Setting.neverDefault());
0196     ipv4Setting.setIgnoreAutoRoutes(m_tmpIpv4Setting.ignoreAutoRoutes());
0197 
0198     ipv4Setting.setDhcpHostname(m_tmpIpv4Setting.dhcpHostname());
0199     ipv4Setting.setDhcpSendHostname(m_tmpIpv4Setting.dhcpSendHostname());
0200     ipv4Setting.setDadTimeout(m_tmpIpv4Setting.dadTimeout());
0201 
0202     // method
0203     switch ((MethodIndex)m_ui->method->currentIndex()) {
0204     case Automatic:
0205         ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Automatic);
0206         break;
0207     case IPv4Widget::AutomaticOnlyIP:
0208         ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Automatic);
0209         ipv4Setting.setIgnoreAutoDns(true);
0210         break;
0211     case Manual:
0212         ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Manual);
0213         break;
0214     case LinkLocal:
0215         ipv4Setting.setMethod(NetworkManager::Ipv4Setting::LinkLocal);
0216         break;
0217     case Shared:
0218         ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Shared);
0219         break;
0220     case Disabled:
0221         ipv4Setting.setMethod(NetworkManager::Ipv4Setting::Disabled);
0222         break;
0223     }
0224 
0225     // dns
0226     if (m_ui->dns->isEnabled() && !m_ui->dns->text().isEmpty()) {
0227         QStringList tmp = m_ui->dns->text().split(QLatin1Char(','));
0228         QList<QHostAddress> tmpAddrList;
0229         for (const QString &str : tmp) {
0230             QHostAddress addr(str);
0231             if (!addr.isNull())
0232                 tmpAddrList.append(addr);
0233         }
0234         ipv4Setting.setDns(tmpAddrList);
0235     }
0236     if (m_ui->dnsSearch->isEnabled() && !m_ui->dnsSearch->text().isEmpty()) {
0237         ipv4Setting.setDnsSearch(m_ui->dnsSearch->text().split(QLatin1Char(',')));
0238     }
0239 
0240     // dhcp id
0241     if (m_ui->dhcpClientId->isEnabled() && !m_ui->dhcpClientId->text().isEmpty()) {
0242         ipv4Setting.setDhcpClientId(m_ui->dhcpClientId->text());
0243     }
0244 
0245     // addresses
0246     if (m_ui->tableViewAddresses->isEnabled()) {
0247         QList<NetworkManager::IpAddress> list;
0248         for (int i = 0, rowCount = d->model.rowCount(); i < rowCount; i++) {
0249             NetworkManager::IpAddress address;
0250             address.setIp(QHostAddress(d->model.item(i, 0)->text()));
0251             address.setNetmask(QHostAddress(d->model.item(i, 1)->text()));
0252             address.setGateway(QHostAddress(d->model.item(i, 2)->text()));
0253             list << address;
0254         }
0255         if (!list.isEmpty()) {
0256             ipv4Setting.setAddresses(list);
0257         }
0258     }
0259 
0260     // may-fail
0261     if (m_ui->ipv4RequiredCB->isEnabled()) {
0262         ipv4Setting.setMayFail(!m_ui->ipv4RequiredCB->isChecked());
0263     }
0264 
0265     return ipv4Setting.toMap();
0266 }
0267 
0268 void IPv4Widget::slotModeComboChanged(int index)
0269 {
0270     if (index == Automatic) { // Automatic
0271         m_ui->dnsLabel->setText(i18n("Other DNS Servers:"));
0272         m_ui->dns->setEnabled(true);
0273         m_ui->dnsMorePushButton->setEnabled(true);
0274         m_ui->dnsSearch->setEnabled(true);
0275         m_ui->dnsSearchMorePushButton->setEnabled(true);
0276         m_ui->dhcpClientId->setEnabled(true);
0277         m_ui->ipv4RequiredCB->setEnabled(true);
0278         m_ui->btnRoutes->setEnabled(true);
0279         m_ui->tableViewAddresses->setEnabled(false);
0280         m_ui->btnAdd->setEnabled(false);
0281         m_ui->btnRemove->setEnabled(false);
0282     } else if (index == AutomaticOnlyIP) {
0283         m_ui->dnsLabel->setText(i18n("DNS Servers:"));
0284         m_ui->dns->setEnabled(true);
0285         m_ui->dnsMorePushButton->setEnabled(true);
0286         m_ui->dnsSearch->setEnabled(true);
0287         m_ui->dnsSearchMorePushButton->setEnabled(true);
0288         m_ui->dhcpClientId->setEnabled(true);
0289         m_ui->ipv4RequiredCB->setEnabled(true);
0290         m_ui->btnRoutes->setEnabled(true);
0291         m_ui->tableViewAddresses->setEnabled(false);
0292         m_ui->btnAdd->setEnabled(false);
0293         m_ui->btnRemove->setEnabled(false);
0294     } else if (index == Manual) { // Manual
0295         m_ui->dnsLabel->setText(i18n("DNS Servers:"));
0296         m_ui->dns->setEnabled(true);
0297         m_ui->dnsMorePushButton->setEnabled(true);
0298         m_ui->dnsSearch->setEnabled(true);
0299         m_ui->dnsSearchMorePushButton->setEnabled(true);
0300         m_ui->dhcpClientId->setEnabled(false);
0301         m_ui->ipv4RequiredCB->setEnabled(true);
0302         m_ui->btnRoutes->setEnabled(true);
0303         m_ui->tableViewAddresses->setEnabled(true);
0304         m_ui->btnAdd->setEnabled(true);
0305         m_ui->btnRemove->setEnabled(true);
0306     } else if (index == LinkLocal || index == Shared) { // Link-local or Shared
0307         m_ui->dnsLabel->setText(i18n("DNS Servers:"));
0308         m_ui->dns->setEnabled(false);
0309         m_ui->dnsMorePushButton->setEnabled(false);
0310         m_ui->dnsSearch->setEnabled(false);
0311         m_ui->dnsSearchMorePushButton->setEnabled(false);
0312         m_ui->dhcpClientId->setEnabled(false);
0313         m_ui->ipv4RequiredCB->setEnabled(true);
0314         m_ui->btnRoutes->setEnabled(false);
0315         m_ui->tableViewAddresses->setEnabled(false);
0316         m_ui->btnAdd->setEnabled(false);
0317         m_ui->btnRemove->setEnabled(false);
0318     } else if (index == Disabled) { // Disabled
0319         m_ui->dnsLabel->setText(i18n("DNS Servers:"));
0320         m_ui->dns->setEnabled(false);
0321         m_ui->dnsMorePushButton->setEnabled(false);
0322         m_ui->dnsSearch->setEnabled(false);
0323         m_ui->dnsSearchMorePushButton->setEnabled(false);
0324         m_ui->dhcpClientId->setEnabled(false);
0325         m_ui->ipv4RequiredCB->setEnabled(false);
0326         m_ui->btnRoutes->setEnabled(false);
0327         m_ui->tableViewAddresses->setEnabled(false);
0328         m_ui->btnAdd->setEnabled(false);
0329         m_ui->btnRemove->setEnabled(false);
0330     }
0331 }
0332 
0333 void IPv4Widget::slotAddIPAddress()
0334 {
0335     QList<QStandardItem *> item{new QStandardItem, new QStandardItem, new QStandardItem};
0336     d->model.appendRow(item);
0337 
0338     const int rowCount = d->model.rowCount();
0339     if (rowCount > 0) {
0340         m_ui->tableViewAddresses->selectRow(rowCount - 1);
0341 
0342         QItemSelectionModel *selectionModel = m_ui->tableViewAddresses->selectionModel();
0343         QModelIndexList list = selectionModel->selectedIndexes();
0344         if (!list.isEmpty()) {
0345             // QTableView is configured to select only rows.
0346             // So, list[0] - IP address.
0347             m_ui->tableViewAddresses->edit(list[0]);
0348         }
0349     }
0350 }
0351 
0352 void IPv4Widget::slotRemoveIPAddress()
0353 {
0354     QItemSelectionModel *selectionModel = m_ui->tableViewAddresses->selectionModel();
0355     if (selectionModel->hasSelection()) {
0356         QModelIndexList indexes = selectionModel->selectedIndexes();
0357         d->model.takeRow(indexes[0].row());
0358     }
0359     m_ui->btnRemove->setEnabled(m_ui->tableViewAddresses->selectionModel()->hasSelection());
0360 }
0361 
0362 void IPv4Widget::selectionChanged(const QItemSelection &selected)
0363 {
0364     m_ui->btnRemove->setEnabled(!selected.isEmpty());
0365 }
0366 
0367 void IPv4Widget::tableViewItemChanged(QStandardItem *item)
0368 {
0369     if (item->text().isEmpty()) {
0370         return;
0371     }
0372 
0373     const int column = item->column();
0374     if (column == 0) { // ip
0375         int row = item->row();
0376 
0377         QStandardItem *netmaskItem = d->model.item(row, column + 1); // netmask
0378         if (netmaskItem && netmaskItem->text().isEmpty()) {
0379             QHostAddress addr(item->text());
0380             const quint32 netmask = suggestNetmask(addr.toIPv4Address());
0381             if (netmask) {
0382                 QHostAddress v(netmask);
0383                 netmaskItem->setText(v.toString());
0384             }
0385         }
0386     }
0387 }
0388 
0389 void IPv4Widget::slotRoutesDialog()
0390 {
0391     QPointer<IpV4RoutesWidget> dlg = new IpV4RoutesWidget(this);
0392     dlg->setAttribute(Qt::WA_DeleteOnClose);
0393 
0394     dlg->setRoutes(m_tmpIpv4Setting.routes());
0395     dlg->setNeverDefault(m_tmpIpv4Setting.neverDefault());
0396     if (m_ui->method->currentIndex() == 2) { // manual
0397         dlg->setIgnoreAutoRoutesCheckboxEnabled(false);
0398     } else {
0399         dlg->setIgnoreAutoRoutes(m_tmpIpv4Setting.ignoreAutoRoutes());
0400     }
0401 
0402     connect(dlg.data(), &QDialog::accepted, [dlg, this]() {
0403         m_tmpIpv4Setting.setRoutes(dlg->routes());
0404         m_tmpIpv4Setting.setNeverDefault(dlg->neverDefault());
0405         m_tmpIpv4Setting.setIgnoreAutoRoutes(dlg->ignoreautoroutes());
0406     });
0407     dlg->setModal(true);
0408     dlg->show();
0409 }
0410 
0411 void IPv4Widget::slotAdvancedDialog()
0412 {
0413     auto dlg = new QDialog(this);
0414     dlg->setAttribute(Qt::WA_DeleteOnClose);
0415 
0416     auto layout = new QFormLayout(dlg);
0417     dlg->setLayout(layout);
0418 
0419     auto label =
0420         new QLabel(i18n("<qt>You can find more information about these values here:<br/><a "
0421                         "href='https://developer.gnome.org/NetworkManager/stable/ch01.html'>https://developer.gnome.org/NetworkManager/stable/ch01.html"
0422                         "nm-settings-nmcli.html</a></qt>"));
0423     connect(label, &QLabel::linkActivated, this, [](const QString &link) {
0424         QDesktopServices::openUrl(QUrl(link));
0425     });
0426     layout->addRow(label);
0427 
0428     auto sendHostname = new QCheckBox(dlg);
0429     sendHostname->setChecked(m_tmpIpv4Setting.dhcpSendHostname());
0430     layout->addRow(i18n("Send hostname:"), sendHostname);
0431 
0432     auto dhcpHostname = new QLineEdit(dlg);
0433     dhcpHostname->setText(m_tmpIpv4Setting.dhcpHostname());
0434     dhcpHostname->setPlaceholderText(QHostInfo::localHostName());
0435     layout->addRow(i18n("DHCP hostname:"), dhcpHostname);
0436 
0437     connect(sendHostname, &QCheckBox::toggled, dhcpHostname, &QLineEdit::setEnabled);
0438 
0439     auto dadTimeout = new QSpinBox(dlg);
0440     dadTimeout->setSpecialValueText(i18n("Default"));
0441     dadTimeout->setSuffix(i18nc("Milliseconds", " ms"));
0442     dadTimeout->setMinimum(-1);
0443     dadTimeout->setValue(m_tmpIpv4Setting.dadTimeout());
0444     layout->addRow(i18n("DAD timeout:"), dadTimeout);
0445 
0446     auto box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dlg);
0447     connect(box, &QDialogButtonBox::accepted, dlg, &QDialog::accept);
0448     connect(box, &QDialogButtonBox::rejected, dlg, &QDialog::reject);
0449     layout->addWidget(box);
0450 
0451     connect(dlg, &QDialog::accepted, this, [this, sendHostname, dhcpHostname, dadTimeout]() {
0452         m_tmpIpv4Setting.setDhcpSendHostname(sendHostname->isChecked());
0453         m_tmpIpv4Setting.setDhcpHostname(dhcpHostname->text());
0454         m_tmpIpv4Setting.setDadTimeout(dadTimeout->value());
0455     });
0456 
0457     dlg->setModal(true);
0458     dlg->show();
0459 }
0460 
0461 void IPv4Widget::slotDnsServers()
0462 {
0463     QPointer<QDialog> dialog = new QDialog(this);
0464     dialog->setAttribute(Qt::WA_DeleteOnClose);
0465     dialog->setWindowTitle(i18n("Edit DNS servers"));
0466     dialog->setLayout(new QVBoxLayout);
0467     auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog);
0468     connect(buttons, &QDialogButtonBox::accepted, dialog.data(), &QDialog::accept);
0469     connect(buttons, &QDialogButtonBox::rejected, dialog.data(), &QDialog::reject);
0470     auto listWidget = new KEditListWidget(dialog);
0471     listWidget->setItems(m_ui->dns->text().split(QLatin1Char(',')).replaceInStrings(QStringLiteral(" "), QLatin1String("")));
0472     listWidget->lineEdit()->setFocus(Qt::OtherFocusReason);
0473     dialog->layout()->addWidget(listWidget);
0474     dialog->layout()->addWidget(buttons);
0475     connect(dialog.data(), &QDialog::accepted, [listWidget, this]() {
0476         QString text = listWidget->items().join(QStringLiteral(","));
0477         if (text.endsWith(',')) {
0478             text.chop(1);
0479         }
0480         m_ui->dns->setText(text);
0481     });
0482     dialog->setModal(true);
0483     dialog->show();
0484 }
0485 
0486 void IPv4Widget::slotDnsDomains()
0487 {
0488     QPointer<QDialog> dialog = new QDialog(this);
0489     dialog->setAttribute(Qt::WA_DeleteOnClose);
0490     dialog->setWindowTitle(i18n("Edit DNS search domains"));
0491     dialog->setLayout(new QVBoxLayout);
0492     auto buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, dialog);
0493     connect(buttons, &QDialogButtonBox::accepted, dialog.data(), &QDialog::accept);
0494     connect(buttons, &QDialogButtonBox::rejected, dialog.data(), &QDialog::reject);
0495     auto listWidget = new KEditListWidget(dialog);
0496     listWidget->setItems(m_ui->dnsSearch->text().split(QLatin1Char(',')).replaceInStrings(QStringLiteral(" "), QLatin1String("")));
0497     listWidget->lineEdit()->setFocus(Qt::OtherFocusReason);
0498     dialog->layout()->addWidget(listWidget);
0499     dialog->layout()->addWidget(buttons);
0500     connect(dialog.data(), &QDialog::accepted, [listWidget, this]() {
0501         QString text = listWidget->items().join(QStringLiteral(","));
0502         if (text.endsWith(',')) {
0503             text.chop(1);
0504         }
0505         m_ui->dnsSearch->setText(text);
0506     });
0507     dialog->setModal(true);
0508     dialog->show();
0509 }
0510 
0511 bool IPv4Widget::isValid() const
0512 {
0513     if (m_ui->method->currentIndex() == Manual) {
0514         if (!d->model.rowCount()) {
0515             return false;
0516         }
0517 
0518         for (int i = 0, rowCount = d->model.rowCount(); i < rowCount; i++) {
0519             QHostAddress ip = QHostAddress(d->model.item(i, 0)->text());
0520             QHostAddress netmask = QHostAddress(d->model.item(i, 1)->text());
0521             QHostAddress gateway = QHostAddress(d->model.item(i, 2)->text());
0522 
0523             if (ip.isNull() || netmask.isNull() || (gateway.isNull() && !d->model.item(i, 2)->text().isEmpty())) {
0524                 return false;
0525             }
0526         }
0527     }
0528 
0529     if (!m_ui->dns->text().isEmpty()
0530         && (m_ui->method->currentIndex() == Automatic || m_ui->method->currentIndex() == Manual || m_ui->method->currentIndex() == AutomaticOnlyIP)) {
0531         const QStringList tmp = m_ui->dns->text().split(QLatin1Char(','));
0532         for (const QString &str : tmp) {
0533             QHostAddress addr(str);
0534             if (addr.isNull()) {
0535                 return false;
0536             }
0537         }
0538     }
0539 
0540     return true;
0541 }
0542 
0543 #include "moc_ipv4widget.cpp"