diff --git a/CMakeLists.txt b/CMakeLists.txt index 08d2452..f8eace9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,15 +25,23 @@ set(PROJECT_SOURCES networkselector.cpp networkselector.h networkselector.ui + genericsettings.ui ethernetsettings.h ethernetsettings.cpp - ethernetsettings.ui networkcreator.h networkcreator.cpp networkcreator.ui networkdeleter.h networkdeleter.cpp networkdeleter.ui + generalsettingstab.h + generalsettingstab.cpp + generalsettingstab.ui + connectionsettingsengine.h + connectionsettingsengine.cpp + ethernetsettingstab.h + ethernetsettingstab.cpp + ethernetsettingstab.ui ${TS_FILES} ) diff --git a/README.md b/README.md new file mode 100644 index 0000000..7f919e4 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# lubuntu-connection-editor - A simple application for creating, removing, and modifying NetworkManager connections + +This is a straightforward-as-possible Qt reimplmentation of the nm-connection-editor tool from GNOME. It uses NetworkManagerQt (from the KDE project) behind the scenes to do all the heavy lifting. + +THIS PROJECT IS IN EARLY ALPHA. It may crash or eat your computer, so treat it with caution. + +## Build instructions + + sudo apt build-dep lubuntu-connection-editor + mkdir build + cd build + cmake .. + make -j$(nproc) + +Do not use `sudo make install` - this will bypass the apt package manager and possibly cause trouble. Instead, package this for your distribution following the guidelines and best practices of that distro. If building for Ubuntu, we recommend using either `debuild` (if working on Ubuntu packages is something you do rarely and you want something that's quick to set up) or `sbuild` (if you need to build packages all the time). diff --git a/connectionsettingsengine.cpp b/connectionsettingsengine.cpp new file mode 100644 index 0000000..0b7a710 --- /dev/null +++ b/connectionsettingsengine.cpp @@ -0,0 +1,16 @@ +#include "connectionsettingsengine.h" + +/* + * The configuration map: + * + * autoconnectEnabled: bool + * autoconnectPriority: int + * allUsersMayConnect: bool + * vpnAutoconnectEnabled: bool + * autoconnectVpn: QString + * meteredConnection: QString + */ + +ConnectionSettingsEngine::ConnectionSettingsEngine() +{ +} diff --git a/connectionsettingsengine.h b/connectionsettingsengine.h new file mode 100644 index 0000000..9ce8fcb --- /dev/null +++ b/connectionsettingsengine.h @@ -0,0 +1,16 @@ +#ifndef CONNECTIONSETTINGSENGINE_H +#define CONNECTIONSETTINGSENGINE_H + +#include +#include + +class ConnectionSettingsEngine +{ +public: + ConnectionSettingsEngine(); + + static QVariantMap readConnectionSettings(QString connUuidStr); + static void modifyConnectionSettings(QString connUuidStr, QVariantMap settings); +}; + +#endif // CONNECTIONSETTINGSENGINE_H diff --git a/ethernetsettings.cpp b/ethernetsettings.cpp index 8786c63..4dbc702 100644 --- a/ethernetsettings.cpp +++ b/ethernetsettings.cpp @@ -1,15 +1,22 @@ #include "ethernetsettings.h" -#include "ui_ethernetsettings.h" +#include "ui_genericsettings.h" EthernetSettings::EthernetSettings(QString title, QWidget *parent) : QDialog(parent), - ui(new Ui::EthernetSettings) + ui(new Ui::GenericSettings) { ui->setupUi(this); this->setWindowTitle(title); + ui->connectionNameLineEdit->setText(title); + generalSettingsTab = new GeneralSettingsTab(); + ethernetSettingsTab = new EthernetSettingsTab(); + ui->tabWidget->addTab(generalSettingsTab, "General"); + ui->tabWidget->addTab(ethernetSettingsTab, "Ethernet"); } EthernetSettings::~EthernetSettings() { delete ui; + delete generalSettingsTab; + delete ethernetSettingsTab; } diff --git a/ethernetsettings.h b/ethernetsettings.h index 4c3628b..f4d2c66 100644 --- a/ethernetsettings.h +++ b/ethernetsettings.h @@ -1,10 +1,13 @@ #ifndef ETHERNETSETTINGS_H #define ETHERNETSETTINGS_H +#include "generalsettingstab.h" +#include "ethernetsettingstab.h" + #include namespace Ui { -class EthernetSettings; +class GenericSettings; } class EthernetSettings : public QDialog @@ -16,7 +19,10 @@ public: ~EthernetSettings(); private: - Ui::EthernetSettings *ui; + Ui::GenericSettings *ui; + + GeneralSettingsTab *generalSettingsTab; + EthernetSettingsTab *ethernetSettingsTab; }; #endif // ETHERNETSETTINGS_H diff --git a/ethernetsettings.ui b/ethernetsettings.ui deleted file mode 100644 index 851ba4a..0000000 --- a/ethernetsettings.ui +++ /dev/null @@ -1,19 +0,0 @@ - - - EthernetSettings - - - - 0 - 0 - 400 - 300 - - - - Dialog - - - - - diff --git a/ethernetsettingstab.cpp b/ethernetsettingstab.cpp new file mode 100644 index 0000000..677e889 --- /dev/null +++ b/ethernetsettingstab.cpp @@ -0,0 +1,14 @@ +#include "ethernetsettingstab.h" +#include "ui_ethernetsettingstab.h" + +EthernetSettingsTab::EthernetSettingsTab(QWidget *parent) : + QWidget(parent), + ui(new Ui::EthernetSettingsTab) +{ + ui->setupUi(this); +} + +EthernetSettingsTab::~EthernetSettingsTab() +{ + delete ui; +} diff --git a/ethernetsettingstab.h b/ethernetsettingstab.h new file mode 100644 index 0000000..ee023d2 --- /dev/null +++ b/ethernetsettingstab.h @@ -0,0 +1,22 @@ +#ifndef ETHERNETSETTINGSTAB_H +#define ETHERNETSETTINGSTAB_H + +#include + +namespace Ui { +class EthernetSettingsTab; +} + +class EthernetSettingsTab : public QWidget +{ + Q_OBJECT + +public: + explicit EthernetSettingsTab(QWidget *parent = nullptr); + ~EthernetSettingsTab(); + +private: + Ui::EthernetSettingsTab *ui; +}; + +#endif // ETHERNETSETTINGSTAB_H diff --git a/ethernetsettingstab.ui b/ethernetsettingstab.ui new file mode 100644 index 0000000..1f04506 --- /dev/null +++ b/ethernetsettingstab.ui @@ -0,0 +1,207 @@ + + + EthernetSettingsTab + + + + 0 + 0 + 665 + 238 + + + + Form + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Cloned MAC address + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Link negotiation + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + Device + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Duplex + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + MTU + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + 0 + 0 + + + + Speed + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + 0 + 0 + + + + + + + + + 0 + 0 + + + + bytes + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/generalsettingstab.cpp b/generalsettingstab.cpp new file mode 100644 index 0000000..1b75b93 --- /dev/null +++ b/generalsettingstab.cpp @@ -0,0 +1,50 @@ +#include "generalsettingstab.h" +#include "ui_generalsettingstab.h" + +GeneralSettingsTab::GeneralSettingsTab(QWidget *parent) : + QWidget(parent), + ui(new Ui::GeneralSettingsTab) +{ + ui->setupUi(this); +} + +GeneralSettingsTab::~GeneralSettingsTab() +{ + delete ui; +} + +// Refer to connectionsettingsengine.cpp for configuration map details + +QVariantMap GeneralSettingsTab::readSettings() +{ + QVariantMap output; + output.insert("autoconnectEnabled", QVariant(ui->autoconnectCheckBox->isChecked())); + output.insert("autoconnectPriority", QVariant(ui->autoconnectPrioritySpinBox->value())); + output.insert("allUsersMayConnect", QVariant(ui->allUsersMayConnectCheckBox->isChecked())); + output.insert("vpnAutoconnectEnabled", QVariant(ui->vpnAutoconnectCheckBox->isChecked())); + output.insert("autoconnectVpn", QVariant(ui->vpnSelectComboBox->currentText())); + output.insert("meteredConnection", QVariant(ui->meteredConnectionComboBox->currentText())); + return output; +} + +void GeneralSettingsTab::loadSettings(QVariantMap settings) +{ + if (settings["autoconnectEnabled"].isValid()) { + ui->autoconnectCheckBox->setChecked(settings["autoconnectEnabled"].toBool()); + } + if (settings["autoconnectPriority"].isValid()) { + ui->autoconnectPrioritySpinBox->setValue(settings["autoconnectPriority"].toInt()); + } + if (settings["allUsersMayConnect"].isValid()) { + ui->allUsersMayConnectCheckBox->setChecked(settings["allUsersMayConnect"].toBool()); + } + if (settings["vpnAutoconnectEnabled"].isValid()) { + ui->vpnAutoconnectCheckBox->setChecked(settings["vpnAutoconnectEnabled"].toBool()); + } + if (settings["autoconnectVpn"].isValid()) { + ui->vpnSelectComboBox->setCurrentText(settings["autoconnectVpn"].toString()); + } + if (settings["meteredConnection"].isValid()) { + ui->meteredConnectionComboBox->setCurrentText(settings["meteredConnection"].toString()); + } +} diff --git a/generalsettingstab.h b/generalsettingstab.h new file mode 100644 index 0000000..b03abd8 --- /dev/null +++ b/generalsettingstab.h @@ -0,0 +1,27 @@ +#ifndef GENERALSETTINGSTAB_H +#define GENERALSETTINGSTAB_H + +#include +#include +#include + +namespace Ui { +class GeneralSettingsTab; +} + +class GeneralSettingsTab : public QWidget +{ + Q_OBJECT + +public: + explicit GeneralSettingsTab(QWidget *parent = nullptr); + ~GeneralSettingsTab(); + + QVariantMap readSettings(); + void loadSettings(QVariantMap settings); + +private: + Ui::GeneralSettingsTab *ui; +}; + +#endif // GENERALSETTINGSTAB_H diff --git a/generalsettingstab.ui b/generalsettingstab.ui new file mode 100644 index 0000000..692feff --- /dev/null +++ b/generalsettingstab.ui @@ -0,0 +1,71 @@ + + + GeneralSettingsTab + + + + 0 + 0 + 400 + 300 + + + + Form + + + + + + All users may connect to this network + + + + + + + Connect automatically with priority + + + + + + + Metered connection: + + + + + + + + + + + + + + + + Automatically connect to VPN + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + diff --git a/genericsettings.ui b/genericsettings.ui new file mode 100644 index 0000000..68b41f1 --- /dev/null +++ b/genericsettings.ui @@ -0,0 +1,81 @@ + + + GenericSettings + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + + + + Connection name + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 0 + 0 + + + + Cancel + + + + + + + + 0 + 0 + + + + Save + + + + + + + + + + diff --git a/main.cpp b/main.cpp index 0f03959..1dd1721 100644 --- a/main.cpp +++ b/main.cpp @@ -3,6 +3,7 @@ #include #include #include +#include int main(int argc, char *argv[]) { diff --git a/networkdeleter.cpp b/networkdeleter.cpp index 9c9dc1c..a0f73f5 100644 --- a/networkdeleter.cpp +++ b/networkdeleter.cpp @@ -5,11 +5,58 @@ NetworkDeleter::NetworkDeleter(QString networkName, QString networkUuidStr, QWid QDialog(parent), ui(new Ui::NetworkDeleter) { + targetNetworkName = networkName; + targetNetworkUuidStr = networkUuidStr; ui->setupUi(this); - this->setWindowTitle("Delete connection " + networkName + "?"); + this->setWindowTitle(tr("Delete connection %1?").arg(networkName)); + ui->connectionDeleteWarningLabel->setText(tr("Are you sure you want to delete connection %1?").arg(networkName)); + this->layout()->setSizeConstraint(QLayout::SetFixedSize); + connect(ui->cancelButton, &QPushButton::clicked, this, &NetworkDeleter::onCancelClicked); + connect(ui->deleteButton, &QPushButton::clicked, this, &NetworkDeleter::onDeleteClicked); } NetworkDeleter::~NetworkDeleter() { delete ui; } + +void NetworkDeleter::onCancelClicked() +{ + this->done(0); +} + +void NetworkDeleter::onDeleteClicked() +{ + NetworkManager::Connection::Ptr conn = NetworkManager::findConnectionByUuid(targetNetworkUuidStr); + + if (!conn || conn->uuid().isEmpty()) { + QMessageBox errorMsg(QMessageBox::Critical, tr("Connection removal failed"), tr("Could not remove connection %1.").arg(targetNetworkName)); + errorMsg.exec(); + } else { + // Copied and adapted from plasma-nm + // Remove slave connections + for (const NetworkManager::Connection::Ptr &connection : NetworkManager::listConnections()) { + NetworkManager::ConnectionSettings::Ptr settings = connection->settings(); + if (settings->master() == conn->uuid()) { + connection->remove(); + } + } + + QDBusPendingReply<> reply = conn->remove(); + auto watcher = new QDBusPendingCallWatcher(reply, this); + connect(watcher, &QDBusPendingCallWatcher::finished, this, &NetworkDeleter::deleteReplyFinished); + ui->connectionDeleteWarningLabel->setText(tr("Deleting connection %1...").arg(targetNetworkName)); + ui->deleteButton->setEnabled(false); + } +} + +void NetworkDeleter::deleteReplyFinished(QDBusPendingCallWatcher *watcher) +{ + // Inspired by plasma-nm + QDBusPendingReply<> reply = *watcher; + if (reply.isError() || !reply.isValid()) { + QMessageBox errorMsg(QMessageBox::Critical, tr("Connection removal failed"), tr("Could not remove connection %1.").arg(targetNetworkName)); + errorMsg.exec(); + } + this->done(0); +} diff --git a/networkdeleter.h b/networkdeleter.h index 7688248..b45eee6 100644 --- a/networkdeleter.h +++ b/networkdeleter.h @@ -2,6 +2,14 @@ #define NETWORKDELETER_H #include +#include +#include +#include +#include +#include +#include +#include +#include namespace Ui { class NetworkDeleter; @@ -15,8 +23,15 @@ public: explicit NetworkDeleter(QString networkName, QString networkUuidStr, QWidget *parent = nullptr); ~NetworkDeleter(); +private slots: + void onCancelClicked(); + void onDeleteClicked(); + void deleteReplyFinished(QDBusPendingCallWatcher *watcher); + private: Ui::NetworkDeleter *ui; + QString targetNetworkName; + QString targetNetworkUuidStr; }; #endif // NETWORKDELETER_H diff --git a/networkdeleter.ui b/networkdeleter.ui index 89d6ba1..f64a766 100644 --- a/networkdeleter.ui +++ b/networkdeleter.ui @@ -1,3 +1,4 @@ + NetworkDeleter @@ -6,12 +7,48 @@ 0 0 400 - 300 + 68 + + + 0 + 0 + + Dialog + + + + + connectionDeleteWarningLabel + + + true + + + + + + + + + Cancel + + + + + + + Delete + + + + + + diff --git a/networkselector.cpp b/networkselector.cpp index f4c8661..f5a23f9 100644 --- a/networkselector.cpp +++ b/networkselector.cpp @@ -8,7 +8,6 @@ NetworkSelector::NetworkSelector(QWidget *parent) { ui->setupUi(this); regenConnTree(); - ui->modifyConnButton->setEnabled(false); connect(ui->connTree, &QTreeView::clicked, this, &NetworkSelector::onTreeSingleClicked); connect(ui->connTree, &QTreeView::doubleClicked, this, &NetworkSelector::onTreeDoubleClicked); connect(ui->createConnButton, &QPushButton::clicked, this, &NetworkSelector::onCreateClicked); @@ -26,9 +25,11 @@ void NetworkSelector::onTreeSingleClicked(QModelIndex index) { QVariant connUuid = index.data(Qt::UserRole+1); if (!connUuid.isValid()) { + ui->deleteConnButton->setEnabled(false); ui->modifyConnButton->setEnabled(false); return; } + ui->deleteConnButton->setEnabled(true); ui->modifyConnButton->setEnabled(true); } @@ -234,6 +235,11 @@ void NetworkSelector::regenConnTree() connTreeModel->appendRow(currentItemWrap); } + connTreeModel->sort(0); + + ui->modifyConnButton->setEnabled(false); + ui->deleteConnButton->setEnabled(false); + ui->connTree->setModel(connTreeModel); ui->connTree->setColumnWidth(0, 500); }