commit 18f24e03abf0343d3a4292b35b2e251625879e71 Author: Aaron Rainbolt Date: Mon Oct 23 21:50:26 2023 -0500 Initial import (main window mostly implemented) diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..08d2452 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,85 @@ +cmake_minimum_required(VERSION 3.16) + +project(lubuntu-connection-editor VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOUIC ON) +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(CMAKE_CXX_STANDARD 17) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +set(KF5_MIN_VERSION "5.102.0") + +find_package(ECM ${KF5_MIN_VERSION} REQUIRED NO_MODULE) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) + +find_package(QT NAMES Qt6 Qt5 REQUIRED COMPONENTS Widgets Network LinguistTools) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Widgets Network LinguistTools) +find_package(KF5 ${KF5_MIN_VERSION} REQUIRED NetworkManagerQt) + +set(TS_FILES lubuntu-connection-editor_en_US.ts) + +set(PROJECT_SOURCES + main.cpp + networkselector.cpp + networkselector.h + networkselector.ui + ethernetsettings.h + ethernetsettings.cpp + ethernetsettings.ui + networkcreator.h + networkcreator.cpp + networkcreator.ui + networkdeleter.h + networkdeleter.cpp + networkdeleter.ui + ${TS_FILES} +) + +if(${QT_VERSION_MAJOR} GREATER_EQUAL 6) + qt_add_executable(lubuntu-connection-editor + MANUAL_FINALIZATION + ${PROJECT_SOURCES} + ) +# Define target properties for Android with Qt 6 as: +# set_property(TARGET lubuntu-connection-editor APPEND PROPERTY QT_ANDROID_PACKAGE_SOURCE_DIR +# ${CMAKE_CURRENT_SOURCE_DIR}/android) +# For more information, see https://doc.qt.io/qt-6/qt-add-executable.html#target-creation + + qt_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) +else() + if(ANDROID) + add_library(lubuntu-connection-editor SHARED + ${PROJECT_SOURCES} + ) +# Define properties for Android with Qt 5 after find_package() calls as: +# set(ANDROID_PACKAGE_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/android") + else() + add_executable(lubuntu-connection-editor + ${PROJECT_SOURCES} + ) + endif() + + qt5_create_translation(QM_FILES ${CMAKE_SOURCE_DIR} ${TS_FILES}) +endif() + +target_link_libraries(lubuntu-connection-editor PRIVATE Qt${QT_VERSION_MAJOR}::Widgets KF5::NetworkManagerQt) + +set_target_properties(lubuntu-connection-editor PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +install(TARGETS lubuntu-connection-editor + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR} +) + +if(QT_VERSION_MAJOR EQUAL 6) + qt_finalize_executable(lubuntu-connection-editor) +endif() diff --git a/ethernetsettings.cpp b/ethernetsettings.cpp new file mode 100644 index 0000000..8786c63 --- /dev/null +++ b/ethernetsettings.cpp @@ -0,0 +1,15 @@ +#include "ethernetsettings.h" +#include "ui_ethernetsettings.h" + +EthernetSettings::EthernetSettings(QString title, QWidget *parent) : + QDialog(parent), + ui(new Ui::EthernetSettings) +{ + ui->setupUi(this); + this->setWindowTitle(title); +} + +EthernetSettings::~EthernetSettings() +{ + delete ui; +} diff --git a/ethernetsettings.h b/ethernetsettings.h new file mode 100644 index 0000000..4c3628b --- /dev/null +++ b/ethernetsettings.h @@ -0,0 +1,22 @@ +#ifndef ETHERNETSETTINGS_H +#define ETHERNETSETTINGS_H + +#include + +namespace Ui { +class EthernetSettings; +} + +class EthernetSettings : public QDialog +{ + Q_OBJECT + +public: + explicit EthernetSettings(QString title, QWidget *parent = nullptr); + ~EthernetSettings(); + +private: + Ui::EthernetSettings *ui; +}; + +#endif // ETHERNETSETTINGS_H diff --git a/ethernetsettings.ui b/ethernetsettings.ui new file mode 100644 index 0000000..851ba4a --- /dev/null +++ b/ethernetsettings.ui @@ -0,0 +1,19 @@ + + + EthernetSettings + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + diff --git a/lubuntu-connection-editor_en_US.ts b/lubuntu-connection-editor_en_US.ts new file mode 100644 index 0000000..edd0d34 --- /dev/null +++ b/lubuntu-connection-editor_en_US.ts @@ -0,0 +1,3 @@ + + + diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..0f03959 --- /dev/null +++ b/main.cpp @@ -0,0 +1,23 @@ +#include "networkselector.h" + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + QApplication a(argc, argv); + + QTranslator translator; + const QStringList uiLanguages = QLocale::system().uiLanguages(); + for (const QString &locale : uiLanguages) { + const QString baseName = "lubuntu-connection-editor_" + QLocale(locale).name(); + if (translator.load(":/i18n/" + baseName)) { + a.installTranslator(&translator); + break; + } + } + NetworkSelector w; + w.show(); + return a.exec(); +} diff --git a/networkcreator.cpp b/networkcreator.cpp new file mode 100644 index 0000000..4e647e0 --- /dev/null +++ b/networkcreator.cpp @@ -0,0 +1,14 @@ +#include "networkcreator.h" +#include "ui_networkcreator.h" + +NetworkCreator::NetworkCreator(QWidget *parent) : + QDialog(parent), + ui(new Ui::NetworkCreator) +{ + ui->setupUi(this); +} + +NetworkCreator::~NetworkCreator() +{ + delete ui; +} diff --git a/networkcreator.h b/networkcreator.h new file mode 100644 index 0000000..553f974 --- /dev/null +++ b/networkcreator.h @@ -0,0 +1,22 @@ +#ifndef NETWORKCREATOR_H +#define NETWORKCREATOR_H + +#include + +namespace Ui { +class NetworkCreator; +} + +class NetworkCreator : public QDialog +{ + Q_OBJECT + +public: + explicit NetworkCreator(QWidget *parent = nullptr); + ~NetworkCreator(); + +private: + Ui::NetworkCreator *ui; +}; + +#endif // NETWORKCREATOR_H diff --git a/networkcreator.ui b/networkcreator.ui new file mode 100644 index 0000000..8abf0ff --- /dev/null +++ b/networkcreator.ui @@ -0,0 +1,19 @@ + + + NetworkCreator + + + + 0 + 0 + 400 + 300 + + + + Create New Connection... + + + + + diff --git a/networkdeleter.cpp b/networkdeleter.cpp new file mode 100644 index 0000000..9c9dc1c --- /dev/null +++ b/networkdeleter.cpp @@ -0,0 +1,15 @@ +#include "networkdeleter.h" +#include "ui_networkdeleter.h" + +NetworkDeleter::NetworkDeleter(QString networkName, QString networkUuidStr, QWidget *parent) : + QDialog(parent), + ui(new Ui::NetworkDeleter) +{ + ui->setupUi(this); + this->setWindowTitle("Delete connection " + networkName + "?"); +} + +NetworkDeleter::~NetworkDeleter() +{ + delete ui; +} diff --git a/networkdeleter.h b/networkdeleter.h new file mode 100644 index 0000000..7688248 --- /dev/null +++ b/networkdeleter.h @@ -0,0 +1,22 @@ +#ifndef NETWORKDELETER_H +#define NETWORKDELETER_H + +#include + +namespace Ui { +class NetworkDeleter; +} + +class NetworkDeleter : public QDialog +{ + Q_OBJECT + +public: + explicit NetworkDeleter(QString networkName, QString networkUuidStr, QWidget *parent = nullptr); + ~NetworkDeleter(); + +private: + Ui::NetworkDeleter *ui; +}; + +#endif // NETWORKDELETER_H diff --git a/networkdeleter.ui b/networkdeleter.ui new file mode 100644 index 0000000..89d6ba1 --- /dev/null +++ b/networkdeleter.ui @@ -0,0 +1,18 @@ + + NetworkDeleter + + + + 0 + 0 + 400 + 300 + + + + Dialog + + + + + diff --git a/networkselector.cpp b/networkselector.cpp new file mode 100644 index 0000000..f4c8661 --- /dev/null +++ b/networkselector.cpp @@ -0,0 +1,280 @@ +#include "networkselector.h" +#include "./ui_networkselector.h" +#include + +NetworkSelector::NetworkSelector(QWidget *parent) + : QMainWindow(parent) + , ui(new Ui::NetworkSelector) +{ + 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); + connect(ui->deleteConnButton, &QPushButton::clicked, this, &NetworkSelector::onDeleteClicked); + connect(ui->modifyConnButton, &QPushButton::clicked, this, &NetworkSelector::onModifyClicked); +} + +NetworkSelector::~NetworkSelector() +{ + delete ui; + delete connTreeModel; +} + +void NetworkSelector::onTreeSingleClicked(QModelIndex index) +{ + QVariant connUuid = index.data(Qt::UserRole+1); + if (!connUuid.isValid()) { + ui->modifyConnButton->setEnabled(false); + return; + } + ui->modifyConnButton->setEnabled(true); +} + +void NetworkSelector::onTreeDoubleClicked(QModelIndex index) +{ + modifyConnection(index); +} + +void NetworkSelector::onCreateClicked() +{ + dialogWindow = new NetworkCreator(); + dialogWindow->exec(); + delete dialogWindow; + regenConnTree(); +} + +void NetworkSelector::onDeleteClicked() +{ + QModelIndexList selectedNetworks = ui->connTree->selectionModel()->selectedIndexes(); + if (selectedNetworks.length() == 0) { + return; + } + if (!selectedNetworks[0].data(Qt::UserRole+1).isValid()) { + return; + } + dialogWindow = new NetworkDeleter(selectedNetworks[0].data().toString(), selectedNetworks[0].data(Qt::UserRole+1).toString()); + dialogWindow->exec(); + delete dialogWindow; + regenConnTree(); +} + +void NetworkSelector::onModifyClicked() +{ + QModelIndexList selectedNetworks = ui->connTree->selectionModel()->selectedIndexes(); + if (selectedNetworks.length() == 0) { + return; + } + if (!selectedNetworks[0].data(Qt::UserRole+1).isValid()) { + return; + } + + modifyConnection(selectedNetworks[0]); +} + +QStandardItem *NetworkSelector::connGroupItem(QString itemName) +{ + for (int i = 0;i < connTreeList.length();i++) { + if (connTreeList[i]->text() == itemName) { + return connTreeList[i]; + } + } + return NULL; +} + +void NetworkSelector::regenConnTree() +{ + if (connTreeModel != NULL) { + delete connTreeModel; + } + connTreeList = QList(); + connTreeModel = new QStandardItemModel(0, 2); + connTreeModel->setHeaderData(0, Qt::Orientation::Horizontal, "Connection"); + connTreeModel->setHeaderData(1, Qt::Orientation::Horizontal, "Last used"); + + connList = NetworkManager::listConnections(); + + for (int i = 0;i < connList.length();i++) { + if (connList[i]->name() == "lo") { // don't show the loopback device + continue; + } + + QList infoRow; + infoRow.append(new QStandardItem(connList[i]->name())); + infoRow.append(new QStandardItem(connList[i]->settings()->timestamp().toString("yyyy-MM-dd hh:mm"))); + + // When the user double-clicks a cell in the tree, the double-click handler gets an object that can fetch a data value from the clicked cell. + // We need to identify the exact connection that was double-clicked on in order for this to work, so we bind the connection's UUID to both visible + // cells in the row representing a connection. + infoRow[0]->setData(connList[i]->uuid()); + infoRow[1]->setData(connList[i]->uuid()); + + NetworkManager::ConnectionSettings::ConnectionType connType = connList[i]->settings()->connectionType(); + QStandardItem *targetItem; + switch(connType) { + case NetworkManager::ConnectionSettings::Wired: + targetItem = connGroupItem("Ethernet"); + if (targetItem == NULL) { + targetItem = new QStandardItem("Ethernet"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Wireless: + targetItem = connGroupItem("WiFi"); + if (targetItem == NULL) { + targetItem = new QStandardItem("WiFi"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Adsl: + case NetworkManager::ConnectionSettings::Pppoe: + targetItem = connGroupItem("DSL"); + if (targetItem == NULL) { + targetItem = new QStandardItem("DSL"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Bluetooth: + targetItem = connGroupItem("Bluetooth"); + if (targetItem == NULL) { + targetItem = new QStandardItem("Bluetooth"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Bond: + case NetworkManager::ConnectionSettings::Bridge: + case NetworkManager::ConnectionSettings::Vlan: + targetItem = connGroupItem("Virtual"); + if (targetItem == NULL) { + targetItem = new QStandardItem("Virtual"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Cdma: + case NetworkManager::ConnectionSettings::Gsm: + targetItem = connGroupItem("Mobile"); + if (targetItem == NULL) { + targetItem = new QStandardItem("Mobile"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Infiniband: + targetItem = connGroupItem("Infiniband"); + if (targetItem == NULL) { + targetItem = new QStandardItem("Infiniband"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::OLPCMesh: + targetItem = connGroupItem("OLPC-Mesh"); + if (targetItem == NULL) { + targetItem = new QStandardItem("OLPC-Mesh"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Vpn: + case NetworkManager::ConnectionSettings::Tun: + case NetworkManager::ConnectionSettings::IpTunnel: + case NetworkManager::ConnectionSettings::WireGuard: + targetItem = connGroupItem("VPN"); + if (targetItem == NULL) { + targetItem = new QStandardItem("VPN"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Wimax: + targetItem = connGroupItem("WiMAX"); + if (targetItem == NULL) { + targetItem = new QStandardItem("WiMAX"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Team: + targetItem = connGroupItem("Team"); + if (targetItem == NULL) { + targetItem = new QStandardItem("Team"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Generic: + targetItem = connGroupItem("Generic"); + if (targetItem == NULL) { + targetItem = new QStandardItem("Generic"); + connTreeList.append(targetItem); + } + break; + + case NetworkManager::ConnectionSettings::Unknown: + targetItem = connGroupItem("Unknown"); + if (targetItem == NULL) { + targetItem = new QStandardItem("Unknown"); + connTreeList.append(targetItem); + } + break; + } + + targetItem->appendRow(infoRow); + } + + for (int i = 0;i < connTreeList.length();i++) { + QList currentItemWrap; + currentItemWrap.append(connTreeList[i]); + connTreeModel->appendRow(currentItemWrap); + } + + ui->connTree->setModel(connTreeModel); + ui->connTree->setColumnWidth(0, 500); +} + +void NetworkSelector::modifyConnection(QModelIndex index) +{ + QVariant connUuid = index.data(Qt::UserRole+1); + if (!connUuid.isValid()) { + return; + } + + for (int i = 0;i < connList.length();i++) { + if (connUuid.toString() == connList[i]->uuid()) { + NetworkManager::ConnectionSettings::ConnectionType connType = connList[i]->settings()->connectionType(); + switch(connType) { + case NetworkManager::ConnectionSettings::Wired: + dialogWindow = new EthernetSettings(index.data().toString()); + dialogWindow->exec(); + delete dialogWindow; + break; + case NetworkManager::ConnectionSettings::Wireless: + case NetworkManager::ConnectionSettings::Adsl: + case NetworkManager::ConnectionSettings::Pppoe: + case NetworkManager::ConnectionSettings::Bluetooth: + case NetworkManager::ConnectionSettings::Bond: + case NetworkManager::ConnectionSettings::Bridge: + case NetworkManager::ConnectionSettings::Vlan: + case NetworkManager::ConnectionSettings::Cdma: + case NetworkManager::ConnectionSettings::Gsm: + case NetworkManager::ConnectionSettings::Infiniband: + case NetworkManager::ConnectionSettings::OLPCMesh: + case NetworkManager::ConnectionSettings::Vpn: + case NetworkManager::ConnectionSettings::Tun: + case NetworkManager::ConnectionSettings::IpTunnel: + case NetworkManager::ConnectionSettings::WireGuard: + case NetworkManager::ConnectionSettings::Wimax: + case NetworkManager::ConnectionSettings::Team: + case NetworkManager::ConnectionSettings::Generic: + case NetworkManager::ConnectionSettings::Unknown: + ; + } + } + } +} diff --git a/networkselector.h b/networkselector.h new file mode 100644 index 0000000..0a0a388 --- /dev/null +++ b/networkselector.h @@ -0,0 +1,53 @@ +#ifndef NETWORKSELECTOR_H +#define NETWORKSELECTOR_H + +#include "ethernetsettings.h" +#include "networkcreator.h" +#include "networkdeleter.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE +namespace Ui { class NetworkSelector; } +QT_END_NAMESPACE + +class NetworkSelector : public QMainWindow +{ + Q_OBJECT + +public: + NetworkSelector(QWidget *parent = nullptr); + ~NetworkSelector(); + +private slots: + void onTreeSingleClicked(QModelIndex index); + void onTreeDoubleClicked(QModelIndex index); + void onCreateClicked(); + void onDeleteClicked(); + void onModifyClicked(); + +private: + QStandardItem *connGroupItem(QString itemName); + void regenConnTree(); + void modifyConnection(QModelIndex index); + + Ui::NetworkSelector *ui; + QStandardItemModel *connTreeModel; + QList connTreeList; + NetworkManager::Connection::List connList; + + QDialog *dialogWindow; +}; +#endif // NETWORKSELECTOR_H diff --git a/networkselector.ui b/networkselector.ui new file mode 100644 index 0000000..aba0561 --- /dev/null +++ b/networkselector.ui @@ -0,0 +1,55 @@ + + + NetworkSelector + + + + 0 + 0 + 800 + 600 + + + + NetworkSelector + + + + + + + QAbstractItemView::NoEditTriggers + + + + + + + + + Create + + + + + + + Delete + + + + + + + Modify + + + + + + + + + + +