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

0001 /*
0002     SPDX-FileCopyrightText: 2010-2012 Lamarque Souza <lamarque@kde.org>
0003     SPDX-FileCopyrightText: 2013 Lukas Tinkl <ltinkl@redhat.com>
0004 
0005     SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0006 */
0007 
0008 #include "mobileconnectionwizard.h"
0009 #include "uiutils.h"
0010 
0011 #include <QVBoxLayout>
0012 
0013 #include <KLocalizedString>
0014 #include <Solid/Device>
0015 
0016 #include <NetworkManagerQt/ModemDevice>
0017 
0018 #include <ModemManagerQt/Manager>
0019 #include <ModemManagerQt/Modem>
0020 
0021 #define NUMBER_OF_STATIC_ENTRIES 3
0022 
0023 MobileConnectionWizard::MobileConnectionWizard(NetworkManager::ConnectionSettings::ConnectionType connectionType, QWidget *parent)
0024     : QWizard(parent)
0025 {
0026     if (connectionType == NetworkManager::ConnectionSettings::Unknown) {
0027         mInitialMethodType = false;
0028     } else {
0029         mInitialMethodType = true;
0030 
0031         if (connectionType == NetworkManager::ConnectionSettings::Bluetooth) {
0032             mType = NetworkManager::ConnectionSettings::Gsm;
0033         } else {
0034             mType = connectionType;
0035         }
0036     }
0037 
0038     mProviders = new MobileProviders();
0039     setWindowTitle(i18nc("Mobile Connection Wizard", "New Mobile Broadband Connection"));
0040     addPage(createIntroPage());
0041     addPage(createCountryPage());
0042     addPage(createProvidersPage());
0043     addPage(createPlansPage());
0044     addPage(createConfirmPage());
0045     setOptions(QWizard::NoBackButtonOnStartPage);
0046 }
0047 
0048 MobileConnectionWizard::~MobileConnectionWizard()
0049 {
0050     delete mProviders;
0051 }
0052 
0053 MobileProviders::ErrorCodes MobileConnectionWizard::getError()
0054 {
0055     if (mProviders) {
0056         return mProviders->getError();
0057     }
0058     return MobileProviders::Success;
0059 }
0060 
0061 void MobileConnectionWizard::initializePage(int id)
0062 {
0063     switch (id) {
0064     case 1: { // Country Page
0065         if (country.isEmpty()) {
0066             country = mProviders->countryFromLocale();
0067         }
0068 
0069         if (country.isEmpty())
0070             mCountryList->setCurrentRow(0);
0071         else {
0072             const QList<QListWidgetItem *> items = mCountryList->findItems(mProviders->getCountryName(country), Qt::MatchExactly);
0073             if (!items.empty()) {
0074                 mCountryList->setCurrentItem(items.first());
0075             }
0076         }
0077 
0078         if (!mInitialMethodType) {
0079             NetworkManager::Device::Ptr iface = NetworkManager::findNetworkInterface(mDeviceComboBox->itemData(mDeviceComboBox->currentIndex()).toString());
0080             if (iface) {
0081                 NetworkManager::ModemDevice::Ptr nmModemIface = iface.objectCast<NetworkManager::ModemDevice>();
0082                 if (nmModemIface && UiUtils::modemSubType(nmModemIface->currentCapabilities()) == NetworkManager::ModemDevice::CdmaEvdo) {
0083                     mType = NetworkManager::ConnectionSettings::Cdma;
0084                 } else {
0085                     mType = NetworkManager::ConnectionSettings::Gsm;
0086                 }
0087             } else {
0088                 mType = static_cast<NetworkManager::ConnectionSettings::ConnectionType>(mDeviceComboBox->itemData(mDeviceComboBox->currentIndex()).toUInt());
0089             }
0090         }
0091 
0092         if (mProviders->getError() != MobileProviders::Success) {
0093             accept();
0094         }
0095         break;
0096     }
0097 
0098     case 2: // Providers Page
0099         country = mCountryList->currentItem()->text();
0100         mProvidersList->clear();
0101         lineEditProvider->clear();
0102         radioAutoProvider->setChecked(true);
0103 
0104         switch (type()) {
0105         case NetworkManager::ConnectionSettings::Gsm:
0106             mProvidersList->insertItems(0, mProviders->getProvidersList(country, NetworkManager::ConnectionSettings::Gsm));
0107             break;
0108         case NetworkManager::ConnectionSettings::Cdma:
0109             mProvidersList->insertItems(0, mProviders->getProvidersList(country, NetworkManager::ConnectionSettings::Cdma));
0110             break;
0111         default:
0112             break;
0113         }
0114         mProvidersList->setCurrentRow(0);
0115         if (mProvidersList->count() > 0) {
0116             mProvidersList->setEnabled(true);
0117             radioAutoProvider->setEnabled(true);
0118             mProvidersList->setFocus();
0119         } else {
0120             mProvidersList->setEnabled(false);
0121             radioAutoProvider->setEnabled(false);
0122             radioManualProvider->setChecked(true);
0123             // TODO: this does not work, try reimplementing QWizardPage::isComplete()
0124             // button(QWizard::NextButton)->setEnabled(false);
0125         }
0126         break;
0127 
0128     case 3: // Plans Page
0129         disconnect(mPlanComboBox, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &MobileConnectionWizard::slotEnablePlanEditBox);
0130         mPlanComboBox->clear();
0131         if (type() != NetworkManager::ConnectionSettings::Gsm) {
0132             goto OUT_3;
0133         }
0134         if (radioManualProvider->isChecked()) {
0135             mPlanComboBox->addItem(i18nc("Mobile Connection Wizard", "My plan is not listed…"));
0136 
0137             if (lineEditProvider->text().isEmpty()) {
0138                 lineEditProvider->setText(i18nc("Mobile Connection Wizard", "Unknown Provider"));
0139             }
0140         } else {
0141             if (mProvidersList->currentItem() != nullptr) {
0142                 const QStringList mApns = mProviders->getApns(mProvidersList->currentItem()->text());
0143 
0144                 if (!mApns.isEmpty()) {
0145                     mPlanComboBox->insertItems(0, mApns);
0146                     mPlanComboBox->setItemText(0, i18nc("Mobile Connection Wizard", "Default"));
0147                 }
0148             }
0149 
0150             if (mPlanComboBox->count()) {
0151                 mPlanComboBox->insertSeparator(1);
0152             }
0153             mPlanComboBox->addItem(i18nc("Mobile Connection Wizard", "My plan is not listed…"));
0154         }
0155         mPlanComboBox->setCurrentIndex(0);
0156         slotEnablePlanEditBox(mPlanComboBox->currentIndex());
0157     OUT_3:
0158         connect(mPlanComboBox, QOverload<int>::of(&KComboBox::currentIndexChanged), this, &MobileConnectionWizard::slotEnablePlanEditBox);
0159         break;
0160 
0161     case 4: // Confirm Page
0162         if (radioManualProvider->isChecked()) {
0163             labelProvider->setText("    " + lineEditProvider->text() + ", " + country);
0164             provider = lineEditProvider->text();
0165         } else {
0166             labelProvider->setText("    " + mProvidersList->currentItem()->text() + ", " + country);
0167             provider = mProvidersList->currentItem()->text();
0168         }
0169 
0170         if (type() == NetworkManager::ConnectionSettings::Cdma) {
0171             labelPlanLabel->hide();
0172             labelPlan->hide();
0173             labelApn->hide();
0174             userApn->clear();
0175             apn.clear();
0176         } else {
0177             labelPlanLabel->show();
0178             labelPlan->show();
0179             labelApn->show();
0180 
0181             if (mPlanComboBox->currentText() == i18nc("Mobile Connection Wizard", "My plan is not listed…")) {
0182                 labelPlan->setText("    " + userApn->text());
0183                 labelApn->setText("    " + i18nc("Mobile Connection Wizard", "APN: %1", userApn->text()));
0184                 apn = userApn->text();
0185             } else {
0186                 int i = mPlanComboBox->currentIndex();
0187                 i = i > 1 ? (i - 1) : 0; // ignores separator's index (i == 1).
0188 
0189                 QStringList mApns = mProviders->getApns(mProvidersList->currentItem()->text());
0190                 labelPlan->setText("    " + mPlanComboBox->currentText());
0191                 labelApn->setText("    " + i18nc("Mobile Connection Wizard", "APN: %1", mApns.at(i)));
0192                 apn = mApns.at(i);
0193             }
0194         }
0195         break;
0196     }
0197 }
0198 
0199 int MobileConnectionWizard::nextId() const
0200 {
0201     // Providers page
0202     if (currentId() == 2 && type() != NetworkManager::ConnectionSettings::Gsm) {
0203         // Jumps to Confirm page instead of Plans page if type != Gsm.
0204         return 4;
0205     } else {
0206         return QWizard::nextId();
0207     }
0208 }
0209 
0210 QVariantList MobileConnectionWizard::args()
0211 {
0212     QVariantList temp;
0213 
0214     switch (type()) {
0215     case NetworkManager::ConnectionSettings::Cdma:
0216         temp << provider << mProviders->getCdmaInfo(provider);
0217         break;
0218 
0219     case NetworkManager::ConnectionSettings::Gsm:
0220         temp << provider /*<< mProviders->getNetworkIds(provider)*/ << mProviders->getApnInfo(apn);
0221         break;
0222 
0223     default:
0224         break;
0225     }
0226     return temp;
0227 }
0228 
0229 /**********************************************************/
0230 /* Intro page */
0231 /**********************************************************/
0232 
0233 QWizardPage *MobileConnectionWizard::createIntroPage()
0234 {
0235     auto page = new QWizardPage();
0236     page->setTitle(i18nc("Mobile Connection Wizard", "Set up a Mobile Broadband Connection"));
0237     auto layout = new QVBoxLayout;
0238 
0239     auto label =
0240         new QLabel(i18nc("Mobile Connection Wizard", "This assistant helps you easily set up a mobile broadband connection to a cellular (3G) network."));
0241     label->setWordWrap(true);
0242     layout->addWidget(label);
0243 
0244     label = new QLabel(QLatin1Char('\n') + i18nc("Mobile Connection Wizard", "You will need the following information:"));
0245     layout->addWidget(label);
0246 
0247     label = new QLabel(QStringLiteral("  . %1\n  . %2\n  . %3")
0248                            .arg(i18nc("Mobile Connection Wizard", "Your broadband provider's name"),
0249                                 i18nc("Mobile Connection Wizard", "Your broadband billing plan name"),
0250                                 i18nc("Mobile Connection Wizard", "(in some cases) Your broadband billing plan APN (Access Point Name)")));
0251     layout->addWidget(label);
0252 
0253     if (!mInitialMethodType) {
0254         label = new QLabel('\n' + i18nc("Mobile Connection Wizard", "Create a connection for &this mobile broadband device:"));
0255         layout->addWidget(label);
0256 
0257         mDeviceComboBox = new KComboBox();
0258         mDeviceComboBox->addItem(i18nc("Mobile Connection Wizard", "Any GSM device"));
0259         mDeviceComboBox->setItemData(0, NetworkManager::ConnectionSettings::Gsm);
0260         mDeviceComboBox->addItem(i18nc("Mobile Connection Wizard", "Any CDMA device"));
0261         mDeviceComboBox->setItemData(1, NetworkManager::ConnectionSettings::Cdma);
0262         mDeviceComboBox->insertSeparator(NUMBER_OF_STATIC_ENTRIES - 1);
0263         label->setBuddy(mDeviceComboBox);
0264         layout->addWidget(mDeviceComboBox);
0265 
0266         connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceAdded, this, &MobileConnectionWizard::introDeviceAdded);
0267         connect(NetworkManager::notifier(), &NetworkManager::Notifier::deviceRemoved, this, &MobileConnectionWizard::introDeviceRemoved);
0268         connect(NetworkManager::notifier(), &NetworkManager::Notifier::statusChanged, this, &MobileConnectionWizard::introStatusChanged);
0269 
0270         introAddInitialDevices();
0271     }
0272 
0273     page->setLayout(layout);
0274 
0275     return page;
0276 }
0277 
0278 void MobileConnectionWizard::introAddDevice(const NetworkManager::Device::Ptr &device)
0279 {
0280     QString desc;
0281 
0282     ModemManager::ModemDevice::Ptr modem = ModemManager::findModemDevice(device->udi());
0283     if (modem) {
0284         ModemManager::Modem::Ptr modemInterface = modem->interface(ModemManager::ModemDevice::ModemInterface).objectCast<ModemManager::Modem>();
0285         if (modemInterface->powerState() == MM_MODEM_POWER_STATE_ON) {
0286             desc.append(modemInterface->manufacturer());
0287             desc.append(QLatin1Char(' '));
0288             desc.append(modemInterface->model());
0289         } else {
0290             QString deviceName = modemInterface->device();
0291             for (const Solid::Device &d : Solid::Device::allDevices()) {
0292                 if (d.udi().contains(deviceName, Qt::CaseInsensitive)) {
0293                     deviceName = d.product();
0294                     if (!deviceName.startsWith(d.vendor())) {
0295                         deviceName = d.vendor() + QLatin1Char(' ') + deviceName;
0296                     }
0297                     desc.append(deviceName);
0298                     break;
0299                 }
0300             }
0301         }
0302     }
0303 
0304     NetworkManager::ModemDevice::Ptr nmModemIface = device.objectCast<NetworkManager::ModemDevice>();
0305     if (!nmModemIface) {
0306         return;
0307     }
0308 
0309     if (UiUtils::modemSubType(nmModemIface->currentCapabilities()) == NetworkManager::ModemDevice::GsmUmts) {
0310         if (desc.isEmpty()) {
0311             desc.append(i18nc("Mobile Connection Wizard", "Installed GSM device"));
0312         }
0313     } else if (UiUtils::modemSubType(nmModemIface->currentCapabilities()) == NetworkManager::ModemDevice::CdmaEvdo) {
0314         if (desc.isEmpty()) {
0315             desc.append(i18nc("Mobile Connection Wizard", "Installed CDMA device"));
0316         }
0317     } else {
0318         return;
0319     }
0320 
0321     mDeviceComboBox->addItem(desc, device->uni());
0322 
0323     if (mDeviceComboBox->count() == NUMBER_OF_STATIC_ENTRIES) {
0324         mDeviceComboBox->setCurrentIndex(0);
0325     } else {
0326         mDeviceComboBox->setCurrentIndex(NUMBER_OF_STATIC_ENTRIES);
0327     }
0328 }
0329 
0330 void MobileConnectionWizard::introDeviceAdded(const QString &uni)
0331 {
0332     introAddDevice(NetworkManager::findNetworkInterface(uni));
0333 }
0334 
0335 void MobileConnectionWizard::introDeviceRemoved(const QString &uni)
0336 {
0337     int index = mDeviceComboBox->findData(uni);
0338 
0339     mDeviceComboBox->removeItem(index);
0340 
0341     if (mDeviceComboBox->count() == NUMBER_OF_STATIC_ENTRIES) {
0342         mDeviceComboBox->setCurrentIndex(0);
0343         if (currentId() > 0) {
0344             close();
0345         }
0346     } else {
0347         mDeviceComboBox->setCurrentIndex(NUMBER_OF_STATIC_ENTRIES);
0348     }
0349 }
0350 
0351 void MobileConnectionWizard::introStatusChanged(NetworkManager::Status status)
0352 {
0353     switch (status) {
0354     case NetworkManager::Unknown:
0355     case NetworkManager::Asleep:
0356     case NetworkManager::Disconnected:
0357     case NetworkManager::Disconnecting:
0358         introRemoveAllDevices();
0359         break;
0360     case NetworkManager::Connecting:
0361     case NetworkManager::ConnectedLinkLocal:
0362     case NetworkManager::ConnectedSiteOnly:
0363     case NetworkManager::Connected:
0364         introAddInitialDevices();
0365         break;
0366     }
0367 }
0368 
0369 void MobileConnectionWizard::introAddInitialDevices()
0370 {
0371     for (const NetworkManager::Device::Ptr &n : NetworkManager::networkInterfaces()) {
0372         introAddDevice(n);
0373     }
0374 
0375     if (mDeviceComboBox->count() == NUMBER_OF_STATIC_ENTRIES) {
0376         mDeviceComboBox->setCurrentIndex(0);
0377     } else {
0378         mDeviceComboBox->setCurrentIndex(NUMBER_OF_STATIC_ENTRIES);
0379     }
0380 }
0381 
0382 void MobileConnectionWizard::introRemoveAllDevices()
0383 {
0384     mDeviceComboBox->clear();
0385     mDeviceComboBox->addItem(i18nc("Mobile Connection Wizard", "Any GSM device"));
0386     mDeviceComboBox->setItemData(0, NetworkManager::ConnectionSettings::Gsm);
0387     mDeviceComboBox->addItem(i18nc("Mobile Connection Wizard", "Any CDMA device"));
0388     mDeviceComboBox->setItemData(1, NetworkManager::ConnectionSettings::Cdma);
0389     mDeviceComboBox->insertSeparator(NUMBER_OF_STATIC_ENTRIES - 1);
0390     mDeviceComboBox->setCurrentIndex(0);
0391 }
0392 
0393 /**********************************************************/
0394 /* Country page */
0395 /**********************************************************/
0396 
0397 QWizardPage *MobileConnectionWizard::createCountryPage()
0398 {
0399     auto page = new QWizardPage();
0400     page->setTitle(i18nc("Mobile Connection Wizard", "Choose your Provider's Country"));
0401     auto layout = new QVBoxLayout;
0402 
0403     auto label = new QLabel(i18nc("Mobile Connection Wizard", "Country List:"));
0404     layout->addWidget(label);
0405 
0406     mCountryList = new QListWidget();
0407     mCountryList->addItem(i18nc("Mobile Connection Wizard", "My country is not listed"));
0408     mCountryList->insertItems(1, mProviders->getCountryList());
0409     layout->addWidget(mCountryList);
0410 
0411     page->setLayout(layout);
0412 
0413     return page;
0414 }
0415 
0416 /**********************************************************/
0417 /* Providers page */
0418 /**********************************************************/
0419 
0420 QWizardPage *MobileConnectionWizard::createProvidersPage()
0421 {
0422     auto page = new QWizardPage();
0423     page->setTitle(i18nc("Mobile Connection Wizard", "Choose your Provider"));
0424     auto layout = new QVBoxLayout;
0425 
0426     radioAutoProvider = new QRadioButton(i18nc("Mobile Connection Wizard", "Select your provider from a &list:"));
0427     radioAutoProvider->setChecked(true);
0428     layout->addWidget(radioAutoProvider);
0429 
0430     mProvidersList = new QListWidget();
0431     connect(mProvidersList, &QListWidget::itemSelectionChanged, this, &MobileConnectionWizard::slotCheckProviderList);
0432     connect(mProvidersList, &QListWidget::itemClicked, this, &MobileConnectionWizard::slotCheckProviderList);
0433     layout->addWidget(mProvidersList);
0434 
0435     radioManualProvider = new QRadioButton(i18nc("Mobile Connection Wizard", "I cannot find my provider and I wish to enter it &manually:"));
0436     layout->addWidget(radioManualProvider);
0437     connect(radioManualProvider, &QRadioButton::toggled, this, &MobileConnectionWizard::slotEnableProviderEdit);
0438 
0439     lineEditProvider = new KLineEdit();
0440     layout->addWidget(lineEditProvider);
0441     connect(lineEditProvider, &KLineEdit::textEdited, this, &MobileConnectionWizard::slotCheckProviderEdit);
0442 
0443     page->setLayout(layout);
0444 
0445     return page;
0446 }
0447 
0448 void MobileConnectionWizard::slotEnableProviderEdit(bool checked)
0449 {
0450     if (checked) {
0451         lineEditProvider->setFocus();
0452     } else {
0453         mProvidersList->setFocus();
0454     }
0455 }
0456 
0457 void MobileConnectionWizard::slotCheckProviderEdit()
0458 {
0459     radioManualProvider->setChecked(true);
0460     // TODO: this does not work, try reimplementing QWizardPage::isComplete()
0461     // button(QWizard::NextButton)->setEnabled(true);
0462 }
0463 
0464 void MobileConnectionWizard::slotCheckProviderList()
0465 {
0466     radioAutoProvider->setChecked(true);
0467     lineEditProvider->clear();
0468 }
0469 
0470 /**********************************************************/
0471 /* Plan page */
0472 /**********************************************************/
0473 
0474 QWizardPage *MobileConnectionWizard::createPlansPage()
0475 {
0476     auto page = new QWizardPage();
0477     page->setTitle(i18nc("Mobile Connection Wizard", "Choose your Billing Plan"));
0478     auto layout = new QBoxLayout(QBoxLayout::TopToBottom);
0479 
0480     auto label = new QLabel(i18nc("Mobile Connection Wizard", "&Select your plan:"));
0481     layout->addWidget(label);
0482 
0483     mPlanComboBox = new KComboBox();
0484     label->setBuddy(mPlanComboBox);
0485     layout->addWidget(mPlanComboBox);
0486 
0487     label = new QLabel('\n' + i18nc("Mobile Connection Wizard", "Selected plan &APN (Access Point Name):"));
0488     layout->addWidget(label);
0489 
0490     userApn = new KLineEdit();
0491     userApn->setEnabled(false);
0492     label->setBuddy(userApn);
0493     layout->addWidget(userApn);
0494 
0495     auto layout2 = new QHBoxLayout();
0496     label = new QLabel();
0497     label->setPixmap(QIcon::fromTheme(QStringLiteral("dialog-warning")).pixmap(32));
0498     layout2->addWidget(label, 0, Qt::AlignTop);
0499     label = new QLabel(i18nc("Mobile Connection Wizard",
0500                              "Warning: Selecting an incorrect plan may result in billing issues for your broadband account or may prevent connectivity.\n\nIf "
0501                              "you are unsure of your plan please ask your provider for your plan's APN."));
0502     label->setWordWrap(true);
0503     layout2->addWidget(label);
0504     layout->addWidget(new QLabel());
0505     layout->addLayout(layout2);
0506 
0507     page->setLayout(layout);
0508 
0509     return page;
0510 }
0511 
0512 void MobileConnectionWizard::slotEnablePlanEditBox(int index)
0513 {
0514     const QString text = mPlanComboBox->itemText(index);
0515     if (type() != NetworkManager::ConnectionSettings::Gsm) {
0516         return;
0517     }
0518     if (text == i18nc("Mobile Connection Wizard", "My plan is not listed…")) {
0519         userApn->clear();
0520         userApn->setEnabled(true);
0521     } else {
0522         if (mProvidersList->currentItem() != nullptr) {
0523             int i = mPlanComboBox->currentIndex();
0524             if (i > 0)
0525                 i = i - 1; // Skipping the separator (i==1)
0526             QStringList mApns = mProviders->getApns(mProvidersList->currentItem()->text());
0527             userApn->setText(mApns.at(i));
0528         }
0529         userApn->setEnabled(false);
0530     }
0531 }
0532 
0533 /**********************************************************/
0534 /* Confirm page */
0535 /**********************************************************/
0536 
0537 QWizardPage *MobileConnectionWizard::createConfirmPage()
0538 {
0539     auto page = new QWizardPage();
0540     page->setTitle(i18nc("Mobile Connection Wizard", "Confirm Mobile Broadband Settings"));
0541     auto layout = new QVBoxLayout;
0542 
0543     auto label = new QLabel(i18nc("Mobile Connection Wizard", "Your mobile broadband connection is configured with the following settings:"));
0544     label->setWordWrap(true);
0545     layout->addWidget(label);
0546 
0547     label = new QLabel('\n' + i18nc("Mobile Connection Wizard", "Your Provider:"));
0548     layout->addWidget(label);
0549     labelProvider = new QLabel();
0550     layout->addWidget(labelProvider);
0551 
0552     labelPlanLabel = new QLabel(QLatin1Char('\n') + i18nc("Mobile Connection Wizard", "Your Plan:"));
0553     layout->addWidget(labelPlanLabel);
0554     labelPlan = new QLabel();
0555     layout->addWidget(labelPlan);
0556     labelApn = new QLabel();
0557     labelApn->setEnabled(false);
0558     layout->addWidget(labelApn);
0559 
0560     page->setLayout(layout);
0561 
0562     return page;
0563 }
0564 
0565 #include "moc_mobileconnectionwizard.cpp"