From 215f0a17b076a5bc67c9e0efbb79d28d229e3f05 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 8 Jun 2024 08:02:16 +0330 Subject: [PATCH] feat: Continue implementing new route GUI --- db/RouteEntity.cpp | 44 ++++++++------- db/RouteEntity.h | 6 +- ui/widget/RouteItem.cpp | 122 +++++++++++++++++++++++++++++++++++++++- ui/widget/RouteItem.h | 8 ++- ui/widget/RouteItem.ui | 17 ++++++ 5 files changed, 171 insertions(+), 26 deletions(-) diff --git a/db/RouteEntity.cpp b/db/RouteEntity.cpp index 063f9be..6c0b116 100644 --- a/db/RouteEntity.cpp +++ b/db/RouteEntity.cpp @@ -13,7 +13,7 @@ namespace NekoGui { return res; } - QJsonObject RouteRule::get_rule_json() const { + QJsonObject RouteRule::get_rule_json(bool forView) const { QJsonObject obj; if (ip_version != "") obj["ip_version"] = ip_version.toInt(); @@ -36,20 +36,24 @@ namespace NekoGui { if (!rule_set.empty()) obj["rule_set"] = get_as_array(rule_set); if (invert) obj["invert"] = invert; - switch (outboundID) { // TODO use constants - case -2: - obj["outbound"] = "direct"; - case -3: - obj["outbound"] = "block"; - case -4: - obj["outbound"] = "dns_out"; - default: - auto prof = NekoGui::profileManager->GetProfile(outboundID); - if (prof == nullptr) { - MW_show_log("The outbound described in the rule chain is missing, maybe your data is corrupted"); - return {}; - } - obj["outbound"] = prof->bean->DisplayName(); + if (forView) { + switch (outboundID) { // TODO use constants + case -2: + obj["outbound"] = "direct"; + case -3: + obj["outbound"] = "block"; + case -4: + obj["outbound"] = "dns_out"; + default: + auto prof = NekoGui::profileManager->GetProfile(outboundID); + if (prof == nullptr) { + MW_show_log("The outbound described in the rule chain is missing, maybe your data is corrupted"); + return {}; + } + obj["outbound"] = prof->bean->DisplayName(); + } + } else { + obj["outbound"] = outboundID; } return obj; @@ -95,13 +99,13 @@ namespace NekoGui { QStringList RouteRule::get_values_for_field(const QString& fieldName) { if (fieldName == "ip_version") { - return {"4", "6"}; + return {"", "4", "6"}; } if (fieldName == "network") { - return {"tcp", "udp"}; + return {"", "tcp", "udp"}; } if (fieldName == "protocol") { - return {"http", "tls", "quic", "stun", "dns", "bittorrent"}; + return {"", "http", "tls", "quic", "stun", "dns", "bittorrent"}; } return {}; } @@ -226,10 +230,10 @@ namespace NekoGui { } } - QJsonArray RoutingChain::get_route_rules() { + QJsonArray RoutingChain::get_route_rules(bool forView) { QJsonArray res; for (const auto &item: Rules) { - auto rule_json = item->get_rule_json(); + auto rule_json = item->get_rule_json(forView); if (rule_json.empty()) { MW_show_log("Aborted generating routing section, an error has occurred"); return {}; diff --git a/db/RouteEntity.h b/db/RouteEntity.h index cc0c975..56096be 100644 --- a/db/RouteEntity.h +++ b/db/RouteEntity.h @@ -27,9 +27,9 @@ namespace NekoGui { QList process_path; QList rule_set; bool invert = false; - int outboundID = -1; // -2 is direct -3 is block -4 is dns_out + int outboundID = -1; // -1 is invalid -2 is direct -3 is block -4 is dns_out - [[nodiscard]] QJsonObject get_rule_json() const; + [[nodiscard]] QJsonObject get_rule_json(bool forView = false) const; static QStringList get_attributes(); static inputType get_input_type(const QString& fieldName); static QStringList get_values_for_field(const QString& fieldName); @@ -44,7 +44,7 @@ namespace NekoGui { QString name = ""; QList> Rules; - QJsonArray get_route_rules(); + QJsonArray get_route_rules(bool forView = false); static std::shared_ptr GetDefaultChain(); }; diff --git a/ui/widget/RouteItem.cpp b/ui/widget/RouteItem.cpp index 359f923..33dbc88 100644 --- a/ui/widget/RouteItem.cpp +++ b/ui/widget/RouteItem.cpp @@ -3,7 +3,6 @@ #include "db/RouteEntity.h" #include "db/Database.hpp" -#define ADJUST_SIZE runOnUiThread([=] { adjustSize(); adjustPosition(mainwindow); }, this); int RouteItem::getIndexOf(const QString& name) const { for (int i=0;iRules.size();i++) { @@ -23,6 +22,18 @@ QString get_outbound_name(int id) { return "INVALID OUTBOUND"; } +int get_outbound_id(const QString& name) { + if (name == "direct") return -2; + if (name == "block") return -3; + if (name == "dns_out") return -4; + auto profiles = NekoGui::profileManager->profiles; + for (const auto& item: profiles) { + if (item.second->bean->name == name) return item.first; + } + + return -1; +} + QStringList get_all_outbounds() { QStringList res; auto profiles = NekoGui::profileManager->profiles; @@ -40,7 +51,27 @@ RouteItem::RouteItem(QWidget *parent, const std::shared_ptrRules) { + std::map valueMap; + for (auto &item: chain->Rules) { + auto baseName = item->name; + int randPart; + if (baseName == "") { + randPart = GetRandomUint64()%1000; + baseName = "rule_" + Int2String(randPart); + lastNum = std::max(lastNum, randPart); + } + while (true) { + valueMap[baseName]++; + if (valueMap[baseName] > 1) { + valueMap[baseName]--; + randPart = GetRandomUint64()%1000; + baseName = "rule_" + Int2String(randPart); + lastNum = std::max(lastNum, randPart); + continue; + } + item->name = baseName; + break; + } ui->route_items->addItem(item->name); } @@ -52,6 +83,26 @@ RouteItem::RouteItem(QWidget *parent, const std::shared_ptrrule_attr_text->hide(); ui->rule_attr_data->setTitle(""); + connect(ui->route_name, &QLineEdit::textChanged, this, [=](const QString& text) { + chain->name = text; + }); + + connect(ui->route_view_json, &QPushButton::clicked, this, [=] { + QString res; + auto rules = chain->get_route_rules(true); + for (int i=0;irule_name, &QLineEdit::textChanged, this, [=](const QString& text) { + if (currentIndex == -1) return; + chain->Rules[currentIndex]->name = text; + }); + connect(ui->rule_attr_selector, &QComboBox::currentTextChanged, this, [=](const QString& text){ if (currentIndex == -1) return; chain->Rules[currentIndex]->set_field_value(ui->rule_attr->currentText(), {text}); @@ -63,12 +114,23 @@ RouteItem::RouteItem(QWidget *parent, const std::shared_ptrRules[currentIndex]->set_field_value(ui->rule_attr->currentText(), currentVal); }); + connect(ui->rule_out, &QComboBox::currentTextChanged, this, [=](const QString& text) { + if (currentIndex == -1) return; + auto id = get_outbound_id(text); + if (id == -1) { + MessageBoxWarning("Invalid state", "selected outbound does not exists in the database, try restarting the app."); + return; + } + chain->Rules[currentIndex]->outboundID = id; + }); + connect(ui->route_items, &QListWidget::itemClicked, this, [=](const QListWidgetItem *item) { auto idx = getIndexOf(item->text()); if (idx == -1) return; currentIndex = idx; auto ruleItem = chain->Rules[idx]; ui->rule_out->setCurrentText(get_outbound_name(ruleItem->outboundID)); + setDefaultRuleData(ruleItem->ip_version); }); connect(ui->rule_attr, &QComboBox::currentTextChanged, this, [=](const QString& text){ @@ -96,12 +158,33 @@ RouteItem::RouteItem(QWidget *parent, const std::shared_ptrnew_route_item, &QPushButton::clicked, this, &RouteItem::on_new_route_item_clicked); + connect(ui->moveup_route_item, &QPushButton::clicked, this, &RouteItem::on_moveup_route_item_clicked); + connect(ui->movedown_route_item, &QPushButton::clicked, this, &RouteItem::on_movedown_route_item_clicked); + connect(ui->delete_route_item, &QPushButton::clicked, this, &RouteItem::on_delete_route_item_clicked); } RouteItem::~RouteItem() { delete ui; } +void RouteItem::updateRouteItemsView() { + ui->route_items->clear(); + if (chain->Rules.empty()) return; + + for (const auto& item: chain->Rules) { + ui->route_items->addItem(item->name); + } + ui->route_items->setCurrentRow(currentIndex); +} + +void RouteItem::setDefaultRuleData(const QString& currentData) { + ui->rule_attr->setCurrentText("ip_version"); + ui->rule_attr_data->setTitle("ip_version"); + showSelectItem(NekoGui::RouteRule::get_values_for_field("ip_version"), currentData); +} + void RouteItem::showSelectItem(const QStringList& items, const QString& currentItem) { ui->rule_attr_text->hide(); ui->rule_attr_selector->clear(); @@ -120,3 +203,38 @@ void RouteItem::showTextEnterItem(const QStringList& items) { ui->rule_attr_text->setText(items.join('\n')); adjustSize(); } + +void RouteItem::on_new_route_item_clicked() { + auto routeItem = std::make_shared(NekoGui::RouteRule()); + routeItem->name = "rule_" + Int2String(++lastNum); + chain->Rules << routeItem; + currentIndex = chain->Rules.size() - 1; + updateRouteItemsView(); + setDefaultRuleData(""); +} + +void RouteItem::on_moveup_route_item_clicked() { + if (currentIndex == -1 || currentIndex == 0) return; + chain->Rules.swapItemsAt(currentIndex, currentIndex-1); + currentIndex--; + updateRouteItemsView(); +} + +void RouteItem::on_movedown_route_item_clicked() { + if (currentIndex == -1 || currentIndex == chain->Rules.size() - 1) return; + chain->Rules.swapItemsAt(currentIndex, currentIndex+1); + currentIndex++; + updateRouteItemsView(); +} + +void RouteItem::on_delete_route_item_clicked() { + if (currentIndex == -1) return; + chain->Rules.removeAt(currentIndex); + if (chain->Rules.empty()) currentIndex = -1; + else { + currentIndex--; + if (currentIndex == -1) currentIndex = 0; + setDefaultRuleData(chain->Rules[currentIndex]->ip_version); + } + updateRouteItemsView(); +} \ No newline at end of file diff --git a/ui/widget/RouteItem.h b/ui/widget/RouteItem.h index cb04f2d..bd74e56 100644 --- a/ui/widget/RouteItem.h +++ b/ui/widget/RouteItem.h @@ -27,17 +27,23 @@ private: Ui::RouteItem *ui; int currentIndex = -1; + int lastNum; + [[nodiscard]] int getIndexOf(const QString& name) const; void showSelectItem(const QStringList& items, const QString& currentItem); void showTextEnterItem(const QStringList& items); + void setDefaultRuleData(const QString& currentData); + + void updateRouteItemsView(); + private slots: void on_ok_button_clicked(); void on_cancel_button_clicked(); void on_new_route_item_clicked(); void on_moveup_route_item_clicked(); void on_movedown_route_item_clicked(); - void on_route_view_json_clicked(); + void on_delete_route_item_clicked(); }; diff --git a/ui/widget/RouteItem.ui b/ui/widget/RouteItem.ui index a9b2cd1..f433e0f 100644 --- a/ui/widget/RouteItem.ui +++ b/ui/widget/RouteItem.ui @@ -70,6 +70,13 @@ + + + + Delete + + + @@ -82,6 +89,16 @@ + + + + Name + + + + + +