diff --git a/CMakeLists.txt b/CMakeLists.txt index 9f3b5bf..b2e821b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -208,6 +208,8 @@ set(PROJECT_SOURCES src/stats/connectionLister/connectionLister.cpp src/configs/proxy/Json2Bean.cpp include/sys/windows/eventHandler.h + src/dataStore/Group.cpp + src/dataStore/ProxyEntity.cpp ) # Qt exe diff --git a/include/dataStore/Database.hpp b/include/dataStore/Database.hpp index 220db2a..79b4e9b 100644 --- a/include/dataStore/Database.hpp +++ b/include/dataStore/Database.hpp @@ -38,8 +38,6 @@ namespace NekoGui { void DeleteProfile(int id); - void MoveProfile(const std::shared_ptr &ent, int gid); - std::shared_ptr GetProfile(int id); bool AddGroup(const std::shared_ptr &ent); @@ -78,6 +76,8 @@ namespace NekoGui { static std::shared_ptr LoadGroup(const QString &jsonPath); static std::shared_ptr LoadRouteChain(const QString &jsonPath); + + void deleteProfile(int id); }; extern ProfileManager *profileManager; diff --git a/include/dataStore/Group.hpp b/include/dataStore/Group.hpp index d9446a4..9f6dfaa 100644 --- a/include/dataStore/Group.hpp +++ b/include/dataStore/Group.hpp @@ -1,9 +1,10 @@ #pragma once -#include "include/global/NekoGui.hpp" #include "ProxyEntity.hpp" +#include "include/global/NekoGui.hpp" -namespace NekoGui { +namespace NekoGui +{ class Group : public JsonStore { public: int id = -1; @@ -19,14 +20,20 @@ namespace NekoGui { // list ui bool manually_column_width = false; QList column_width; - QList order; + QList profiles; Group(); - // 按 id 顺序 - [[nodiscard]] QList> Profiles() const; + [[nodiscard]] QList Profiles() const; - // 按 显示 顺序 - [[nodiscard]] QList> ProfilesWithOrder() const; + [[nodiscard]] QList> GetProfileEnts() const; + + bool RemoveProfile(int id); + + bool AddProfile(int id); + + bool SwapProfiles(int idx1, int idx2); + + bool HasProfile(int id) const; }; -} // namespace NekoGui +}// namespace NekoGui diff --git a/include/global/NekoGui_DataStore.hpp b/include/global/NekoGui_DataStore.hpp index be6467c..63b8139 100644 --- a/include/global/NekoGui_DataStore.hpp +++ b/include/global/NekoGui_DataStore.hpp @@ -55,7 +55,6 @@ namespace NekoGui { bool flag_tray = false; bool flag_debug = false; bool flag_restart_tun_on = false; - bool flag_reorder = false; bool flag_dns_set = false; // Saved diff --git a/include/ui/utils/MyTableWidget.h b/include/ui/utils/MyTableWidget.h index 6bce9c3..3690d10 100644 --- a/include/ui/utils/MyTableWidget.h +++ b/include/ui/utils/MyTableWidget.h @@ -10,64 +10,21 @@ class MyTableWidget : public QTableWidget { public: explicit MyTableWidget(QWidget *parent = nullptr) : QTableWidget(parent) { - // 拖拽设置 - this->setDragDropMode(QAbstractItemView::InternalMove); // 内部移动 - this->setDropIndicatorShown(true); // drop位置 提示 - this->setSelectionBehavior(QAbstractItemView::SelectRows); - }; - - QList order; // id sorted (save) - std::map id2Row; // id2Row - QList row2Id; // row2Id: use this to refresh data - - std::function callback_save_order; - std::function refresh_data; - - void _save_order(bool saveToFile) { - order.clear(); - id2Row.clear(); - for (int i = 0; i < this->rowCount(); i++) { - auto id = row2Id[i]; - order += id; - id2Row[id] = i; - } - if (callback_save_order != nullptr && saveToFile) - { - callback_save_order(); - } + this->setDragDropMode(InternalMove); + this->setDropIndicatorShown(true); + this->setSelectionBehavior(SelectRows); } - void update_order(bool saveToFile) { - if (order.isEmpty()) { - _save_order(false); - return; - } - - // Then save the order - _save_order(saveToFile); - }; - + std::function rowsSwapped; protected: void dropEvent(QDropEvent *event) override { - if (order.isEmpty()) return; - - int row_src, row_dst; - row_src = this->currentRow(); - auto id_src = row2Id[row_src]; - QTableWidgetItem *item = this->itemAt(event->position().toPoint()); - if (item != nullptr) { - row_dst = item->row(); - // Modify order - row2Id.swapItemsAt(row_src, row_dst); - order.removeAt(row_src); - order.insert(row_dst, id_src); - } else { - return; + if (const QTableWidgetItem *item = this->itemAt(event->position().toPoint()); item != nullptr) { + const int row_dst = item->row(); + if (rowsSwapped) + { + rowsSwapped(row_dst, currentRow()); + clearSelection(); + } } - - // Do update order & refresh - clearSelection(); - update_order(true); - refresh_data(-1); - }; + } }; diff --git a/src/configs/sub/GroupUpdater.cpp b/src/configs/sub/GroupUpdater.cpp index d73726a..b04a1e6 100644 --- a/src/configs/sub/GroupUpdater.cpp +++ b/src/configs/sub/GroupUpdater.cpp @@ -752,12 +752,10 @@ namespace NekoGui_sub { QList> update_del; // 更新前后都有的,需要删除的新配置 QList> update_keep; // 更新前后都有的,被保留的旧配置 - // 订阅解析前 if (group != nullptr) { - in = group->Profiles(); + in = group->GetProfileEnts(); group->sub_last_update = QDateTime::currentMSecsSinceEpoch() / 1000; group->info = sub_user_info; - group->order.clear(); group->Save(); // if (NekoGui::dataStore->sub_clear) { @@ -771,7 +769,7 @@ namespace NekoGui_sub { rawUpdater->update(content); if (group != nullptr) { - out_all = group->Profiles(); + out_all = group->GetProfileEnts(); QString change_text; @@ -786,7 +784,6 @@ namespace NekoGui_sub { NekoGui::ProfileFilter::OnlyInSrc(in, out, only_in); NekoGui::ProfileFilter::OnlyInSrc(out, in, only_out); NekoGui::ProfileFilter::Common(in, out, update_keep, update_del, false); - QString notice_added; QString notice_deleted; if (only_out.size() < 1000) @@ -810,22 +807,22 @@ namespace NekoGui_sub { // sort according to order in remote - group->order = {}; + group->profiles.clear(); for (const auto &ent: rawUpdater->updated_order) { auto deleted_index = update_del.indexOf(ent); if (deleted_index >= 0) { if (deleted_index >= update_keep.count()) continue; // should not happen - auto ent2 = update_keep[deleted_index]; - group->order.append(ent2->id); + const auto& ent2 = update_keep[deleted_index]; + group->profiles.append(ent2->id); } else { - group->order.append(ent->id); + group->profiles.append(ent->id); } } group->Save(); // cleanup for (const auto &ent: out_all) { - if (!group->order.contains(ent->id)) { + if (!group->HasProfile(ent->id)) { NekoGui::profileManager->DeleteProfile(ent->id); } } diff --git a/src/dataStore/Database.cpp b/src/dataStore/Database.cpp index 2ff8e25..e340038 100644 --- a/src/dataStore/Database.cpp +++ b/src/dataStore/Database.cpp @@ -2,9 +2,7 @@ #include "include/configs/proxy/includes.h" -#include #include -#include namespace NekoGui { @@ -55,7 +53,7 @@ namespace NekoGui { } // Clear Corrupted profile for (auto id: delProfile) { - DeleteProfile(id); + deleteProfile(id); } // Load Groups auto loadedOrder = groupsTabOrder; @@ -91,71 +89,16 @@ namespace NekoGui { // First setup if (groups.empty()) { - auto defaultGroup = NekoGui::ProfileManager::NewGroup(); + auto defaultGroup = NewGroup(); defaultGroup->name = QObject::tr("Default"); - NekoGui::profileManager->AddGroup(defaultGroup); + profileManager->AddGroup(defaultGroup); } if (routes.empty()) { auto defaultRoute = RoutingChain::GetDefaultChain(); profileManager->AddRouteChain(defaultRoute); - } - - // Add default route chains - routes[IranBypassChainID] = RoutingChain::GetIranDefaultChain(); - routes[ChinaBypassChainID] = RoutingChain::GetChinaDefaultChain(); - - // - if (dataStore->flag_reorder) { - { - // remove all (contains orphan) - for (const auto &profile: profiles) { - QFile::remove(profile.second->fn); - } - } - std::map gidOld2New; - { - int i = 0; - int ii = 0; - QList newProfilesIdOrder; - std::map> newProfiles; - for (auto gid: groupsTabOrder) { - auto group = GetGroup(gid); - gidOld2New[gid] = ii++; - for (auto const &profile: group->ProfilesWithOrder()) { - auto oldId = profile->id; - auto newId = i++; - profile->id = newId; - profile->gid = gidOld2New[gid]; - profile->fn = QString("profiles/%1.json").arg(newId); - profile->Save(); - newProfiles[newId] = profile; - newProfilesIdOrder << newId; - } - group->order = {}; - group->Save(); - } - profiles = newProfiles; - profilesIdOrder = newProfilesIdOrder; - } - { - QList newGroupsIdOrder; - std::map> newGroups; - for (auto oldGid: groupsTabOrder) { - auto newId = gidOld2New[oldGid]; - auto group = groups[oldGid]; - QFile::remove(group->fn); - group->id = newId; - group->fn = QString("groups/%1.json").arg(newId); - group->Save(); - newGroups[newId] = group; - newGroupsIdOrder << newId; - } - groups = newGroups; - groupsIdOrder = newGroupsIdOrder; - groupsTabOrder = newGroupsIdOrder; - } - MessageBoxInfo(software_name, "Profiles and groups reorder complete."); + routes[IranBypassChainID] = RoutingChain::GetIranDefaultChain(); + routes[ChinaBypassChainID] = RoutingChain::GetChinaDefaultChain(); } } @@ -243,54 +186,6 @@ namespace NekoGui { return ent; } - // ProxyEntity - - ProxyEntity::ProxyEntity(NekoGui_fmt::AbstractBean *bean, const QString &type_) { - if (type_ != nullptr) this->type = type_; - - _add(new configItem("type", &type, itemType::string)); - _add(new configItem("id", &id, itemType::integer)); - _add(new configItem("gid", &gid, itemType::integer)); - _add(new configItem("yc", &latency, itemType::integer)); - _add(new configItem("dl", &dl_speed, itemType::string)); - _add(new configItem("ul", &ul_speed, itemType::string)); - _add(new configItem("report", &full_test_report, itemType::string)); - - // 可以不关联 bean,只加载 ProxyEntity 的信息 - if (bean != nullptr) { - this->bean = std::shared_ptr(bean); - // 有虚函数就要在这里 dynamic_cast - _add(new configItem("bean", dynamic_cast(bean), itemType::jsonStore)); - _add(new configItem("traffic", dynamic_cast(traffic_data.get()), itemType::jsonStore)); - } - }; - - QString ProxyEntity::DisplayTestResult() const { - QString result; - if (latency < 0) { - result = "Unavailable"; - } else if (latency > 0) { - result = UNICODE_LRO + QString("%1 ms").arg(latency); - } - if (!dl_speed.isEmpty()) result += " ↓" + dl_speed; - if (!ul_speed.isEmpty()) result += " ↑" + ul_speed; - return result; - } - - QColor ProxyEntity::DisplayLatencyColor() const { - if (latency < 0) { - return Qt::red; - } else if (latency > 0) { - if (latency <= 200) { - return Qt::darkGreen; - } else { - return Qt::darkYellow; - } - } else { - return {}; - } - } - // Profile int ProfileManager::NewProfileID() const { @@ -306,8 +201,16 @@ namespace NekoGui { return false; } - ent->gid = gid < 0 ? dataStore->current_group : gid; ent->id = NewProfileID(); + ent->gid = gid < 0 ? dataStore->current_group : gid; + if (auto group = GetGroup(ent->gid); group != nullptr) + { + group->AddProfile(ent->id); + group->Save(); + } else + { + return false; + } profiles[ent->id] = ent; profilesIdOrder.push_back(ent->id); @@ -319,26 +222,23 @@ namespace NekoGui { void ProfileManager::DeleteProfile(int id) { if (id < 0) return; if (dataStore->started_id == id) return; + auto ent = GetProfile(id); + if (ent == nullptr) return; + if (auto group = GetGroup(ent->gid); group != nullptr) + { + group->RemoveProfile(id); + group->Save(); + } + deleteProfile(id); + } + + void ProfileManager::deleteProfile(int id) + { profiles.erase(id); profilesIdOrder.removeAll(id); QFile(QString("profiles/%1.json").arg(id)).remove(); } - void ProfileManager::MoveProfile(const std::shared_ptr &ent, int gid) { - if (gid == ent->gid || gid < 0) return; - auto oldGroup = GetGroup(ent->gid); - if (oldGroup != nullptr && !oldGroup->order.isEmpty()) { - oldGroup->order.removeAll(ent->id); - oldGroup->Save(); - } - auto newGroup = GetGroup(gid); - if (newGroup != nullptr && !newGroup->order.isEmpty()) { - newGroup->order.push_back(ent->id); - newGroup->Save(); - } - ent->gid = gid; - ent->Save(); - } std::shared_ptr ProfileManager::GetProfile(int id) { return profiles.count(id) ? profiles[id] : nullptr; @@ -359,21 +259,6 @@ namespace NekoGui { } // Group - Group::Group() { - _add(new configItem("id", &id, itemType::integer)); - _add(new configItem("front_proxy_id", &front_proxy_id, itemType::integer)); - _add(new configItem("landing_proxy_id", &landing_proxy_id, itemType::integer)); - _add(new configItem("archive", &archive, itemType::boolean)); - _add(new configItem("skip_auto_update", &skip_auto_update, itemType::boolean)); - _add(new configItem("name", &name, itemType::string)); - _add(new configItem("order", &order, itemType::integerList)); - _add(new configItem("url", &url, itemType::string)); - _add(new configItem("info", &info, itemType::string)); - _add(new configItem("lastup", &sub_last_update, itemType::integer64)); - _add(new configItem("manually_column_width", &manually_column_width, itemType::boolean)); - _add(new configItem("column_width", &column_width, itemType::integerList)); - } - std::shared_ptr ProfileManager::LoadGroup(const QString &jsonPath) { auto ent = std::make_shared(); ent->fn = jsonPath; @@ -406,12 +291,10 @@ namespace NekoGui { void ProfileManager::DeleteGroup(int gid) { if (groups.size() <= 1) return; - QList toDelete; - for (const auto &[id, profile]: profiles) { - if (profile->gid == gid) toDelete += id; // map访问中,不能操作 - } - for (const auto &id: toDelete) { - DeleteProfile(id); + auto group = GetGroup(gid); + if (group == nullptr) return; + for (const auto id : group->Profiles()) { + deleteProfile(id); } groups.erase(gid); groupsIdOrder.removeAll(gid); @@ -427,48 +310,6 @@ namespace NekoGui { return GetGroup(dataStore->current_group); } - RouteRule::RouteRule() { - _add(new configItem("name", &name, itemType::string)); - _add(new configItem("ip_version", &ip_version, itemType::string)); - _add(new configItem("network", &network, itemType::string)); - _add(new configItem("protocol", &protocol, itemType::string)); - _add(new configItem("inbound", &inbound, itemType::stringList)); - _add(new configItem("domain", &domain, itemType::stringList)); - _add(new configItem("domain_suffix", &domain_suffix, itemType::stringList)); - _add(new configItem("domain_keyword", &domain_keyword, itemType::stringList)); - _add(new configItem("domain_regex", &domain_regex, itemType::stringList)); - _add(new configItem("source_ip_cidr", &source_ip_cidr, itemType::stringList)); - _add(new configItem("source_ip_is_private", &source_ip_is_private, itemType::boolean)); - _add(new configItem("ip_cidr", &ip_cidr, itemType::stringList)); - _add(new configItem("ip_is_private", &ip_is_private, itemType::boolean)); - _add(new configItem("source_port", &source_port, itemType::stringList)); - _add(new configItem("source_port_range", &source_port_range, itemType::stringList)); - _add(new configItem("port", &port, itemType::stringList)); - _add(new configItem("port_range", &port_range, itemType::stringList)); - _add(new configItem("process_name", &process_name, itemType::stringList)); - _add(new configItem("process_path", &process_path, itemType::stringList)); - _add(new configItem("process_path_regex", &process_path_regex, itemType::stringList)); - _add(new configItem("rule_set", &rule_set, itemType::stringList)); - _add(new configItem("invert", &invert, itemType::boolean)); - _add(new configItem("outboundID", &outboundID, itemType::integer)); - _add(new configItem("actionType", &action, itemType::string)); - _add(new configItem("rejectMethod", &rejectMethod, itemType::string)); - _add(new configItem("noDrop", &no_drop, itemType::boolean)); - _add(new configItem("override_address", &override_address, itemType::string)); - _add(new configItem("override_port", &override_port, itemType::integer)); - _add(new configItem("sniffers", &sniffers, itemType::stringList)); - _add(new configItem("sniffOverrideDest", &sniffOverrideDest, itemType::boolean)); - _add(new configItem("strategy", &strategy, itemType::string)); - _add(new configItem("type", &type, itemType::integer)); - _add(new configItem("simple_action", &simpleAction, itemType::integer)); - } - - RoutingChain::RoutingChain() { - _add(new configItem("id", &id, itemType::integer)); - _add(new configItem("name", &name, itemType::string)); - _add(new configItem("rules", &castedRules, itemType::jsonStoreList)); - } - std::shared_ptr ProfileManager::NewRouteChain() { auto route = std::make_shared(); return route; @@ -518,25 +359,4 @@ namespace NekoGui { } } - QList> Group::Profiles() const { - QList> ret; - for (const auto &[_, profile]: profileManager->profiles) { - if (id == profile->gid) ret += profile; - } - return ret; - } - - QList> Group::ProfilesWithOrder() const { - if (order.isEmpty()) { - return Profiles(); - } else { - QList> ret; - for (auto _id: order) { - auto ent = profileManager->GetProfile(_id); - if (ent != nullptr) ret += ent; - } - return ret; - } - } - } // namespace NekoGui \ No newline at end of file diff --git a/src/dataStore/Group.cpp b/src/dataStore/Group.cpp new file mode 100644 index 0000000..ad8c483 --- /dev/null +++ b/src/dataStore/Group.cpp @@ -0,0 +1,65 @@ +#include + +#include "include/ui/profile/dialog_edit_profile.h" + +namespace NekoGui +{ + Group::Group() { + _add(new configItem("id", &id, itemType::integer)); + _add(new configItem("front_proxy_id", &front_proxy_id, itemType::integer)); + _add(new configItem("landing_proxy_id", &landing_proxy_id, itemType::integer)); + _add(new configItem("archive", &archive, itemType::boolean)); + _add(new configItem("skip_auto_update", &skip_auto_update, itemType::boolean)); + _add(new configItem("name", &name, itemType::string)); + _add(new configItem("profiles", &profiles, itemType::integerList)); + _add(new configItem("url", &url, itemType::string)); + _add(new configItem("info", &info, itemType::string)); + _add(new configItem("lastup", &sub_last_update, itemType::integer64)); + _add(new configItem("manually_column_width", &manually_column_width, itemType::boolean)); + _add(new configItem("column_width", &column_width, itemType::integerList)); + } + + QList Group::Profiles() const { + return profiles; + } + + QList> Group::GetProfileEnts() const + { + auto res = QList>{}; + for (auto id : profiles) + { + res.append(profileManager->GetProfile(id)); + } + return res; + } + + + bool Group::AddProfile(int id) + { + if (HasProfile(id)) + { + return false; + } + profiles.append(id); + return true; + } + + bool Group::RemoveProfile(int id) + { + if (!HasProfile(id)) return false; + profiles.removeAll(id); + return true; + } + + bool Group::SwapProfiles(int idx1, int idx2) + { + if (profiles.size() <= idx1 || profiles.size() <= idx2) return false; + profiles.swapItemsAt(idx1, idx2); + return true; + } + + bool Group::HasProfile(int id) const + { + return profiles.contains(id); + } +} diff --git a/src/dataStore/ProxyEntity.cpp b/src/dataStore/ProxyEntity.cpp new file mode 100644 index 0000000..15b1d28 --- /dev/null +++ b/src/dataStore/ProxyEntity.cpp @@ -0,0 +1,48 @@ +#include + +namespace NekoGui +{ + ProxyEntity::ProxyEntity(NekoGui_fmt::AbstractBean *bean, const QString &type_) { + if (type_ != nullptr) this->type = type_; + + _add(new configItem("type", &type, itemType::string)); + _add(new configItem("id", &id, itemType::integer)); + _add(new configItem("gid", &gid, itemType::integer)); + _add(new configItem("yc", &latency, itemType::integer)); + _add(new configItem("dl", &dl_speed, itemType::string)); + _add(new configItem("ul", &ul_speed, itemType::string)); + _add(new configItem("report", &full_test_report, itemType::string)); + + if (bean != nullptr) { + this->bean = std::shared_ptr(bean); + _add(new configItem("bean", dynamic_cast(bean), itemType::jsonStore)); + _add(new configItem("traffic", dynamic_cast(traffic_data.get()), itemType::jsonStore)); + } + }; + + QString ProxyEntity::DisplayTestResult() const { + QString result; + if (latency < 0) { + result = "Unavailable"; + } else if (latency > 0) { + result = UNICODE_LRO + QString("%1 ms").arg(latency); + } + if (!dl_speed.isEmpty()) result += " ↓" + dl_speed; + if (!ul_speed.isEmpty()) result += " ↑" + ul_speed; + return result; + } + + QColor ProxyEntity::DisplayLatencyColor() const { + if (latency < 0) { + return Qt::red; + } else if (latency > 0) { + if (latency <= 200) { + return Qt::darkGreen; + } else { + return Qt::darkYellow; + } + } else { + return {}; + } + } +} \ No newline at end of file diff --git a/src/dataStore/RouteEntity.cpp b/src/dataStore/RouteEntity.cpp index ba99cce..9035b1e 100644 --- a/src/dataStore/RouteEntity.cpp +++ b/src/dataStore/RouteEntity.cpp @@ -22,6 +22,42 @@ namespace NekoGui { return false; } + RouteRule::RouteRule() { + _add(new configItem("name", &name, itemType::string)); + _add(new configItem("ip_version", &ip_version, itemType::string)); + _add(new configItem("network", &network, itemType::string)); + _add(new configItem("protocol", &protocol, itemType::string)); + _add(new configItem("inbound", &inbound, itemType::stringList)); + _add(new configItem("domain", &domain, itemType::stringList)); + _add(new configItem("domain_suffix", &domain_suffix, itemType::stringList)); + _add(new configItem("domain_keyword", &domain_keyword, itemType::stringList)); + _add(new configItem("domain_regex", &domain_regex, itemType::stringList)); + _add(new configItem("source_ip_cidr", &source_ip_cidr, itemType::stringList)); + _add(new configItem("source_ip_is_private", &source_ip_is_private, itemType::boolean)); + _add(new configItem("ip_cidr", &ip_cidr, itemType::stringList)); + _add(new configItem("ip_is_private", &ip_is_private, itemType::boolean)); + _add(new configItem("source_port", &source_port, itemType::stringList)); + _add(new configItem("source_port_range", &source_port_range, itemType::stringList)); + _add(new configItem("port", &port, itemType::stringList)); + _add(new configItem("port_range", &port_range, itemType::stringList)); + _add(new configItem("process_name", &process_name, itemType::stringList)); + _add(new configItem("process_path", &process_path, itemType::stringList)); + _add(new configItem("process_path_regex", &process_path_regex, itemType::stringList)); + _add(new configItem("rule_set", &rule_set, itemType::stringList)); + _add(new configItem("invert", &invert, itemType::boolean)); + _add(new configItem("outboundID", &outboundID, itemType::integer)); + _add(new configItem("actionType", &action, itemType::string)); + _add(new configItem("rejectMethod", &rejectMethod, itemType::string)); + _add(new configItem("noDrop", &no_drop, itemType::boolean)); + _add(new configItem("override_address", &override_address, itemType::string)); + _add(new configItem("override_port", &override_port, itemType::integer)); + _add(new configItem("sniffers", &sniffers, itemType::stringList)); + _add(new configItem("sniffOverrideDest", &sniffOverrideDest, itemType::boolean)); + _add(new configItem("strategy", &strategy, itemType::string)); + _add(new configItem("type", &type, itemType::integer)); + _add(new configItem("simple_action", &simpleAction, itemType::integer)); + } + RouteRule::RouteRule(const RouteRule& other) { name = other.name; ip_version = other.ip_version; @@ -805,6 +841,12 @@ namespace NekoGui { } } + RoutingChain::RoutingChain() { + _add(new configItem("id", &id, itemType::integer)); + _add(new configItem("name", &name, itemType::string)); + _add(new configItem("rules", &castedRules, itemType::jsonStoreList)); + } + RoutingChain::RoutingChain(const RoutingChain& other) : JsonStore(other) { id = other.id; name = QString(other.name); diff --git a/src/main.cpp b/src/main.cpp index 14ad17c..8d282c1 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -87,7 +87,6 @@ int main(int argc, char* argv[]) { if (NekoGui::dataStore->argv.contains("-debug")) NekoGui::dataStore->flag_debug = true; if (NekoGui::dataStore->argv.contains("-flag_restart_tun_on")) NekoGui::dataStore->flag_restart_tun_on = true; if (NekoGui::dataStore->argv.contains("-flag_restart_dns_set")) NekoGui::dataStore->flag_dns_set = true; - if (NekoGui::dataStore->argv.contains("-flag_reorder")) NekoGui::dataStore->flag_reorder = true; #ifdef NKR_CPP_USE_APPDATA NekoGui::dataStore->flag_use_appdata = true; // Example: Package & MacOS #endif diff --git a/src/ui/mainwindow.cpp b/src/ui/mainwindow.cpp index 330c134..5df1ff5 100644 --- a/src/ui/mainwindow.cpp +++ b/src/ui/mainwindow.cpp @@ -261,12 +261,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi ui->graph_tab->layout()->addWidget(speedChartWidget); // table UI - ui->proxyListTable->callback_save_order = [=] { + ui->proxyListTable->rowsSwapped = [=](int row1, int row2) + { auto group = NekoGui::profileManager->CurrentGroup(); - group->order = ui->proxyListTable->order; - group->Save(); + group->SwapProfiles(row1, row2); + refresh_proxy_list(group->profiles[row1]); + refresh_proxy_list(group->profiles[row2]); }; - ui->proxyListTable->refresh_data = [=](int id) { refresh_proxy_list_impl_refresh_data(id); }; if (auto button = ui->proxyListTable->findChild(QString(), Qt::FindDirectChildrenOnly)) { // Corner Button connect(button, &QAbstractButton::clicked, this, [=] { refresh_proxy_list_impl(-1, {GroupSortMethod::ById}); }); @@ -446,7 +447,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi urltest_current_group(get_now_selected_list()); }); connect(ui->actionUrl_Test_Group, &QAction::triggered, this, [=]() { - urltest_current_group(NekoGui::profileManager->CurrentGroup()->ProfilesWithOrder()); + urltest_current_group(NekoGui::profileManager->CurrentGroup()->GetProfileEnts()); }); connect(ui->actionSpeedtest_Current, &QAction::triggered, this, [=]() { @@ -461,7 +462,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi }); connect(ui->actionSpeedtest_Group, &QAction::triggered, this, [=]() { - speedtest_current_group(NekoGui::profileManager->CurrentGroup()->ProfilesWithOrder()); + speedtest_current_group(NekoGui::profileManager->CurrentGroup()->GetProfileEnts()); }); connect(ui->menu_stop_testing, &QAction::triggered, this, [=]() { stopTests(); }); // @@ -805,7 +806,6 @@ void MainWindow::on_menu_exit_triggered() { arguments.removeFirst(); arguments.removeAll("-tray"); arguments.removeAll("-flag_restart_tun_on"); - arguments.removeAll("-flag_reorder"); arguments.removeAll("-flag_restart_dns_set"); } auto program = QApplication::applicationFilePath(); @@ -1267,73 +1267,24 @@ void MainWindow::refresh_proxy_list(const int &id) { void MainWindow::refresh_proxy_list_impl(const int &id, GroupSortAction groupSortAction) { ui->proxyListTable->setUpdatesEnabled(false); if (id < 0) { - ui->proxyListTable->row2Id.clear(); - ui->proxyListTable->setRowCount(0); - auto oldOrder = QList(); - oldOrder << ui->proxyListTable->order; - auto group = NekoGui::profileManager->CurrentGroup(); - if (group == nullptr) + auto currentGroup = NekoGui::profileManager->CurrentGroup(); + if (currentGroup == nullptr) { - ui->proxyListTable->setUpdatesEnabled(true); + MW_show_log("Could not find current group!"); return; } - - QSet currProfs; - // remove old ones - ui->proxyListTable->order.clear(); - for (const int oldID : oldOrder) - { - if (NekoGui::profileManager->GetProfile(oldID) != nullptr) - { - ui->proxyListTable->order << oldID; - currProfs.insert(oldID); - } - } - - // add new ones - for (const auto& profile : NekoGui::profileManager->profiles) - { - if (profile.second->gid == group->id && !currProfs.contains(profile.first)) - { - ui->proxyListTable->order << profile.first; - } - } - switch (groupSortAction.method) { case GroupSortMethod::Raw: { - QList newGroupOrder; - QSet newGroupIds; - for (const int oldId : group->order) - { - if (NekoGui::profileManager->GetProfile(oldId) != nullptr) - { - newGroupOrder << oldId; - newGroupIds.insert(oldId); - } - } - for (const auto& profile : NekoGui::profileManager->profiles) - { - if (profile.second->gid == group->id && !newGroupIds.contains(profile.first)) - { - newGroupOrder << profile.first; - } - } - group->order.clear(); - group->order << newGroupOrder; - ui->proxyListTable->order = group->order; break; } case GroupSortMethod::ById: { - // Clear Order - ui->proxyListTable->order.clear(); - ui->proxyListTable->callback_save_order(); break; } case GroupSortMethod::ByAddress: case GroupSortMethod::ByName: case GroupSortMethod::ByLatency: case GroupSortMethod::ByType: { - std::sort(ui->proxyListTable->order.begin(), ui->proxyListTable->order.end(), + std::sort(currentGroup->profiles.begin(), currentGroup->profiles.end(), [=](int a, int b) { QString ms_a; QString ms_b; @@ -1380,26 +1331,7 @@ void MainWindow::refresh_proxy_list_impl(const int &id, GroupSortAction groupSor } } - if (ui->proxyListTable->order.isEmpty()) - { - for (const auto& ent : group->Profiles()) - { - ui->proxyListTable->order << ent->id; - } - } - - bool needSave = oldOrder.size() != ui->proxyListTable->order.size(); - for (int i=0;iproxyListTable->order[i]) - { - needSave = true; - } - } - - ui->proxyListTable->row2Id << ui->proxyListTable->order; - ui->proxyListTable->setRowCount(ui->proxyListTable->order.size()); - ui->proxyListTable->update_order(needSave); + ui->proxyListTable->setRowCount(currentGroup->profiles.count()); } // refresh data @@ -1408,24 +1340,24 @@ void MainWindow::refresh_proxy_list_impl(const int &id, GroupSortAction groupSor void MainWindow::refresh_proxy_list_impl_refresh_data(const int &id, bool stopping) { ui->proxyListTable->setUpdatesEnabled(false); + auto currentGroup = NekoGui::profileManager->CurrentGroup(); if (id >= 0) { - if (ui->proxyListTable->id2Row.count(id) == 0) + if (!currentGroup->HasProfile(id)) { - qDebug("Invalid proxy list id, data might be corrupted"); ui->proxyListTable->setUpdatesEnabled(true); return; } - auto rowID = ui->proxyListTable->id2Row[id]; + auto rowID = currentGroup->profiles.indexOf(id); auto profile = NekoGui::profileManager->GetProfile(id); refresh_table_item(rowID, profile, stopping); } else { ui->proxyListTable->blockSignals(true); - for (int row = 0; row < ui->proxyListTable->rowCount(); row++) { - auto profileId = ui->proxyListTable->row2Id[row]; + int row = 0; + for (const auto profileId : currentGroup->profiles) { auto profile = NekoGui::profileManager->GetProfile(profileId); - refresh_table_item(row, profile, stopping); + refresh_table_item(row++, profile, stopping); } ui->proxyListTable->blockSignals(false); } @@ -1523,8 +1455,8 @@ void MainWindow::on_menu_delete_repeat_triggered () { QList> out; QList> out_del; - NekoGui::ProfileFilter::Uniq (NekoGui::profileManager-> CurrentGroup ()-> Profiles (), out, true , false ); - NekoGui::ProfileFilter::OnlyInSrc_ByPointer (NekoGui::profileManager-> CurrentGroup ()-> Profiles (), out, out_del); + NekoGui::ProfileFilter::Uniq (NekoGui::profileManager-> CurrentGroup ()-> GetProfileEnts (), out, true , false ); + NekoGui::ProfileFilter::OnlyInSrc_ByPointer (NekoGui::profileManager-> CurrentGroup ()-> GetProfileEnts (), out, out_del); int remove_display_count = 0 ; QString remove_display; @@ -1539,9 +1471,9 @@ void MainWindow::on_menu_delete_repeat_triggered () { if (!out_del.empty() && QMessageBox::question ( this , tr ( " Confirmation " ), tr ( " Remove %1 item(s) ? " ). arg (out_del. length ()) + " \n " + remove_display) == QMessageBox::StandardButton::Yes) { for ( const auto &ent: out_del) { - NekoGui::profileManager-> DeleteProfile (ent-> id ); + NekoGui::profileManager->DeleteProfile(ent-> id ); } - refresh_proxy_list (); + refresh_proxy_list(); } } @@ -1868,7 +1800,7 @@ void MainWindow::on_menu_remove_invalid_triggered() { auto currentGroup = NekoGui::profileManager->GetGroup(NekoGui::dataStore->current_group); if (currentGroup == nullptr) return; - for (const auto &profile : currentGroup->Profiles()) { + for (const auto &profile : currentGroup->GetProfileEnts()) { if (!IsValid(profile)) out_del += profile; } @@ -1927,7 +1859,8 @@ void MainWindow::on_menu_resolve_domain_triggered() { auto resolve_count = std::atomic(0); NekoGui::dataStore->resolve_count = profiles.count(); - for (const auto &profile: profiles) { + for (const auto id: profiles) { + auto profile = NekoGui::profileManager->GetProfile(id); profile->bean->ResolveDomainToIP([=] { profile->Save(); if (--NekoGui::dataStore->resolve_count != 0) return; @@ -1957,9 +1890,9 @@ QList> MainWindow::get_selected_or_group() QList> profiles; if (selected_or_group > 0) { profiles = get_now_selected_list(); - if (profiles.isEmpty() && selected_or_group == 2) profiles = NekoGui::profileManager->CurrentGroup()->ProfilesWithOrder(); + if (profiles.isEmpty() && selected_or_group == 2) profiles = NekoGui::profileManager->CurrentGroup()->GetProfileEnts(); } else { - profiles = NekoGui::profileManager->CurrentGroup()->ProfilesWithOrder(); + profiles = NekoGui::profileManager->CurrentGroup()->GetProfileEnts(); } return profiles; } diff --git a/src/ui/profile/dialog_edit_profile.cpp b/src/ui/profile/dialog_edit_profile.cpp index 99a1e70..a12a682 100644 --- a/src/ui/profile/dialog_edit_profile.cpp +++ b/src/ui/profile/dialog_edit_profile.cpp @@ -564,7 +564,7 @@ void DialogEditProfile::do_apply_to_group(const std::shared_ptr auto stream = GetStreamSettings(ent->bean.get()); auto copyStream = [=](void *p) { - for (const auto &profile: group->Profiles()) { + for (const auto &profile: group->GetProfileEnts()) { auto newStream = GetStreamSettings(profile->bean.get()); if (newStream == nullptr) continue; if (stream == newStream) continue; @@ -575,7 +575,7 @@ void DialogEditProfile::do_apply_to_group(const std::shared_ptr }; auto copyBean = [=](void *p) { - for (const auto &profile: group->Profiles()) { + for (const auto &profile: group->GetProfileEnts()) { if (profile == ent) continue; profile->bean->_setValue(ent->bean->_name(p), p); // qDebug() << profile->bean->ToJsonBytes();