refactor: refactored Complex Connection Editor - 2

This commit is contained in:
QwQ 2020-07-25 21:51:25 +08:00
parent f666b479c9
commit c1fde8b3a6
No known key found for this signature in database
GPG Key ID: E7FAEFAFCD031D4B
14 changed files with 309 additions and 219 deletions

View File

@ -1 +1 @@
5830 5831

View File

@ -47,6 +47,13 @@ namespace Qv2ray::base::objects::complex
MODE_CONNECTIONID MODE_CONNECTIONID
}; };
enum TagNodeMode
{
NODE_INBOUND,
NODE_OUTBOUND,
NODE_RULE
};
struct OutboundObject struct OutboundObject
{ {
QString displayName; QString displayName;

View File

@ -28,9 +28,6 @@
using namespace QtNodes; using namespace QtNodes;
using namespace Qv2ray::ui::nodemodels; using namespace Qv2ray::ui::nodemodels;
constexpr auto GRAPH_GLOBAL_OFFSET_X = -380;
constexpr auto GRAPH_GLOBAL_OFFSET_Y = -350;
//#define CurrentRule this->rules[this->currentRuleTag] //#define CurrentRule this->rules[this->currentRuleTag]
#define LOADINGCHECK \ #define LOADINGCHECK \
if (isLoading) \ if (isLoading) \
@ -38,32 +35,54 @@ constexpr auto GRAPH_GLOBAL_OFFSET_Y = -350;
#define LOAD_FLAG_BEGIN isLoading = true; #define LOAD_FLAG_BEGIN isLoading = true;
#define LOAD_FLAG_END isLoading = false; #define LOAD_FLAG_END isLoading = false;
void RouteEditor::SetupNodeWidget() void RouteEditor::updateColorScheme()
{ {
// Setup icons according to the theme settings.
addInboundBtn->setIcon(QICON_R("add"));
addOutboundBtn->setIcon(QICON_R("add"));
if (GlobalConfig.uiConfig.useDarkTheme) if (GlobalConfig.uiConfig.useDarkTheme)
{ {
ConnectionStyle::setConnectionStyle( ConnectionStyle::setConnectionStyle(
R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray", R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0, "SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,
"ConstructionLineWidth": 2.0,"PointDiameter": 10.0,"UseDataDefinedColors": true}})"); "ConstructionLineWidth": 2.0,"PointDiameter": 10.0,"UseDataDefinedColors": true}})");
} }
else else
{ {
QtNodes::NodeStyle::setNodeStyle( QtNodes::NodeStyle::setNodeStyle(
R"({"NodeStyle": {"NormalBoundaryColor": "darkgray","SelectedBoundaryColor": "deepskyblue", R"({"NodeStyle": {"NormalBoundaryColor": "darkgray","SelectedBoundaryColor": "deepskyblue",
"GradientColor0": "mintcream","GradientColor1": "mintcream","GradientColor2": "mintcream", "GradientColor0": "mintcream","GradientColor1": "mintcream","GradientColor2": "mintcream",
"GradientColor3": "mintcream","ShadowColor": [200, 200, 200],"FontColor": [10, 10, 10], "GradientColor3": "mintcream","ShadowColor": [200, 200, 200],"FontColor": [10, 10, 10],
"FontColorFaded": [100, 100, 100],"ConnectionPointColor": "white","PenWidth": 2.0,"HoveredPenWidth": 2.5, "FontColorFaded": [100, 100, 100],"ConnectionPointColor": "white","PenWidth": 2.0,"HoveredPenWidth": 2.5,
"ConnectionPointDiameter": 10.0,"Opacity": 1.0}})"); "ConnectionPointDiameter": 10.0,"Opacity": 1.0}})");
QtNodes::FlowViewStyle::setStyle( QtNodes::FlowViewStyle::setStyle(
R"({"FlowViewStyle": {"BackgroundColor": [255, 255, 240],"FineGridColor": [245, 245, 230],"CoarseGridColor": [235, 235, 220]}})"); R"({"FlowViewStyle": {"BackgroundColor": [255, 255, 240],"FineGridColor": [245, 245, 230],"CoarseGridColor": [235, 235, 220]}})");
ConnectionStyle::setConnectionStyle( ConnectionStyle::setConnectionStyle(
R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray", R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,"ConstructionLineWidth": 2.0, "SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,"ConstructionLineWidth": 2.0,
"PointDiameter": 10.0,"UseDataDefinedColors": false}})"); "PointDiameter": 10.0,"UseDataDefinedColors": false}})");
} }
}
RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QvDialog(parent), root(connection), original(connection)
{
setupUi(this);
QvMessageBusConnect(RouteEditor);
//
isLoading = true;
// ?
// setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint);
updateColorScheme();
//
{ {
ruleWidget = new RoutingEditorWidget(ruleEditorUIWidget); ruleWidget = new RoutingEditorWidget(ruleEditorUIWidget);
//
nodeDispatcher = ruleWidget->GetDispatcher();
connect(nodeDispatcher.get(), &NodeDispatcher::OnOutboundCreated, this, &RouteEditor::OnDispatcherOutboundCreated);
connect(nodeDispatcher.get(), &NodeDispatcher::OnOutboundDeleted, this, &RouteEditor::OnDispatcherOutboundDeleted);
connect(nodeDispatcher.get(), &NodeDispatcher::OnRuleCreated, this, &RouteEditor::OnDispatcherRuleCreated);
connect(nodeDispatcher.get(), &NodeDispatcher::OnInboundOutboundNodeHovered, this, &RouteEditor::OnDispatcherInboundOutboundHovered);
//
if (!ruleEditorUIWidget->layout()) if (!ruleEditorUIWidget->layout())
{ {
// The QWidget will take ownership of layout. // The QWidget will take ownership of layout.
@ -74,8 +93,9 @@ void RouteEditor::SetupNodeWidget()
l->setContentsMargins(0, 0, 0, 0); l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0); l->setSpacing(0);
} }
{ {
chainWidget = new ChainEditorWidget(chainEditorUIWidget); chainWidget = new ChainEditorWidget(nodeDispatcher, chainEditorUIWidget);
if (!chainEditorUIWidget->layout()) if (!chainEditorUIWidget->layout())
{ {
// The QWidget will take ownership of layout. // The QWidget will take ownership of layout.
@ -86,23 +106,6 @@ void RouteEditor::SetupNodeWidget()
l->setContentsMargins(0, 0, 0, 0); l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0); l->setSpacing(0);
} }
}
RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QvDialog(parent), root(connection), original(connection)
{
setupUi(this);
QvMessageBusConnect(RouteEditor);
//
isLoading = true;
setWindowFlags(windowFlags() | Qt::WindowMaximizeButtonHint);
SetupNodeWidget();
updateColorScheme();
//
nodeDispatcher = std::make_shared<NodeDispatcher>(ruleWidget->getScene());
connect(nodeDispatcher.get(), &NodeDispatcher::OnInboundCreated, this, &RouteEditor::OnDispatcherInboundCreated);
connect(nodeDispatcher.get(), &NodeDispatcher::OnOutboundCreated, this, &RouteEditor::OnDispatcherOutboundCreated);
connect(nodeDispatcher.get(), &NodeDispatcher::OnRuleCreated, this, &RouteEditor::OnDispatcherRuleCreated);
connect(nodeDispatcher.get(), &NodeDispatcher::OnInboundOutboundNodeHovered, this, &RouteEditor::OnDispatcherInboundOutboundHovered);
// //
domainStrategy = root["routing"].toObject()["domainStrategy"].toString(); domainStrategy = root["routing"].toObject()["domainStrategy"].toString();
domainStrategyCombo->setCurrentText(domainStrategy); domainStrategyCombo->setCurrentText(domainStrategy);
@ -148,27 +151,13 @@ void RouteEditor::OnDispatcherInboundOutboundHovered(const QString &tag, const P
protocolLabel->setText(info.protocol); protocolLabel->setText(info.protocol);
} }
void RouteEditor::OnDispatcherInboundCreated(std::shared_ptr<INBOUND>, QtNodes::Node &node) void RouteEditor::OnDispatcherOutboundCreated(std::shared_ptr<OutboundObjectMeta> out, QtNodes::Node &)
{ {
QPoint pos{ 0 + GRAPH_GLOBAL_OFFSET_X, nodeDispatcher->InboundsCount() * 130 + GRAPH_GLOBAL_OFFSET_Y };
ruleWidget->getScene()->setNodePosition(node, pos);
}
void RouteEditor::OnDispatcherOutboundCreated(std::shared_ptr<OutboundObjectMeta> out, QtNodes::Node &node)
{
auto pos = ruleWidget->pos();
pos.setX(pos.x() + 850 + GRAPH_GLOBAL_OFFSET_X);
pos.setY(pos.y() + nodeDispatcher->OutboundsCount() * 120 + GRAPH_GLOBAL_OFFSET_Y);
ruleWidget->getScene()->setNodePosition(node, pos);
defaultOutboundCombo->addItem(out->getTag()); defaultOutboundCombo->addItem(out->getTag());
} }
void RouteEditor::OnDispatcherRuleCreated(std::shared_ptr<RuleObject> rule, QtNodes::Node &node) void RouteEditor::OnDispatcherRuleCreated(std::shared_ptr<RuleObject> rule, QtNodes::Node &)
{ {
auto pos = ruleWidget->pos();
pos.setX(pos.x() + 350 + GRAPH_GLOBAL_OFFSET_X);
pos.setY(pos.y() + nodeDispatcher->RulesCount() * 120 + GRAPH_GLOBAL_OFFSET_Y);
ruleWidget->getScene()->setNodePosition(node, pos);
ruleListWidget->addItem(rule->QV2RAY_RULE_TAG); ruleListWidget->addItem(rule->QV2RAY_RULE_TAG);
} }
@ -181,6 +170,31 @@ void RouteEditor::OnDispatcherOutboundDeleted(const OutboundObjectMeta &data)
} }
} }
void RouteEditor::OnDispatcherObjectTagChanged(TagNodeMode t, const QString original, const QString current)
{
Q_UNUSED(original)
Q_UNUSED(current)
//
if (t == NODE_INBOUND)
{
// Pass
}
else if (t == NODE_RULE)
{
for (auto i = 0; i < ruleListWidget->count(); i++)
{
if (ruleListWidget->item(i)->text() == original)
ruleListWidget->item(i)->setText(current);
}
}
else if (t == NODE_OUTBOUND)
{
const auto id = defaultOutboundCombo->findText(original);
if (id > 0)
defaultOutboundCombo->setItemText(id, current);
}
}
CONFIGROOT RouteEditor::OpenEditor() CONFIGROOT RouteEditor::OpenEditor()
{ {
auto result = this->exec(); auto result = this->exec();
@ -287,8 +301,9 @@ CONFIGROOT RouteEditor::OpenEditor()
RouteEditor::~RouteEditor() RouteEditor::~RouteEditor()
{ {
nodeDispatcher.reset(); nodeDispatcher->LockOperation();
} }
void RouteEditor::on_buttonBox_accepted() void RouteEditor::on_buttonBox_accepted()
{ {
} }
@ -411,28 +426,6 @@ void RouteEditor::on_addOutboundBtn_clicked()
} }
} }
void RouteEditor::on_delBtn_clicked()
{
if (ruleWidget->getScene()->selectedNodes().empty())
{
QvMessageBoxWarn(this, tr("Remove Items"), tr("Please select a node from the graph to continue."));
return;
}
const auto selecteNodes = ruleWidget->getScene()->selectedNodes();
if (selecteNodes.empty())
{
QvMessageBoxWarn(this, tr("Deleting a node"), tr("You need to select a node first"));
return;
}
ruleWidget->getScene()->removeNode(*selecteNodes.front());
}
void RouteEditor::on_addRouteBtn_clicked()
{
const auto _ = nodeDispatcher->CreateRule({});
}
void RouteEditor::on_domainStrategyCombo_currentIndexChanged(const QString &arg1) void RouteEditor::on_domainStrategyCombo_currentIndexChanged(const QString &arg1)
{ {
LOADINGCHECK LOADINGCHECK

View File

@ -42,43 +42,33 @@ class RouteEditor
void processCommands(QString, QStringList, QMap<QString, QString>) override{}; void processCommands(QString, QStringList, QMap<QString, QString>) override{};
private: private:
void updateColorScheme() override void updateColorScheme() override;
{
// Setup icons according to the theme settings.
addInboundBtn->setIcon(QICON_R("add"));
addOutboundBtn->setIcon(QICON_R("add"));
addRouteBtn->setIcon(QICON_R("add"));
delBtn->setIcon(QICON_R("ashbin"));
}
QvMessageBusSlotDecl; QvMessageBusSlotDecl;
private slots: private slots:
void on_buttonBox_accepted();
void on_insertDirectBtn_clicked();
void on_addRouteBtn_clicked();
void on_addDefaultBtn_clicked();
void on_insertBlackBtn_clicked();
void on_addInboundBtn_clicked();
void on_addOutboundBtn_clicked();
void on_delBtn_clicked();
void on_domainStrategyCombo_currentIndexChanged(const QString &arg1);
void on_defaultOutboundCombo_currentTextChanged(const QString &arg1);
void on_importExistingBtn_clicked();
void on_importGroupBtn_currentIndexChanged(int index);
void on_addBalancerBtn_clicked(); void on_addBalancerBtn_clicked();
void on_addChainBtn_clicked(); void on_addChainBtn_clicked();
void on_addDefaultBtn_clicked();
void on_addInboundBtn_clicked();
void on_addOutboundBtn_clicked();
void on_buttonBox_accepted();
void on_debugPainterCB_clicked(bool checked); void on_debugPainterCB_clicked(bool checked);
void on_defaultOutboundCombo_currentTextChanged(const QString &arg1);
void on_domainStrategyCombo_currentIndexChanged(const QString &arg1);
void on_importExistingBtn_clicked();
void on_importGroupBtn_currentIndexChanged(int index);
void on_insertBlackBtn_clicked();
void on_insertDirectBtn_clicked();
void on_linkExistingBtn_clicked(); void on_linkExistingBtn_clicked();
private slots: private slots:
void OnDispatcherOutboundDeleted(const complex::OutboundObjectMeta &); void OnDispatcherOutboundDeleted(const complex::OutboundObjectMeta &);
void OnDispatcherInboundCreated(std::shared_ptr<INBOUND>, QtNodes::Node &);
void OnDispatcherOutboundCreated(std::shared_ptr<complex::OutboundObjectMeta>, QtNodes::Node &); void OnDispatcherOutboundCreated(std::shared_ptr<complex::OutboundObjectMeta>, QtNodes::Node &);
void OnDispatcherRuleCreated(std::shared_ptr<RuleObject>, QtNodes::Node &); void OnDispatcherRuleCreated(std::shared_ptr<RuleObject>, QtNodes::Node &);
void OnDispatcherInboundOutboundHovered(const QString &, const ProtocolSettingsInfoObject &); void OnDispatcherInboundOutboundHovered(const QString &, const ProtocolSettingsInfoObject &);
void OnDispatcherObjectTagChanged(TagNodeMode, const QString, const QString);
private: private:
// NOTE: Self managed pointer.
std::shared_ptr<NodeDispatcher> nodeDispatcher; std::shared_ptr<NodeDispatcher> nodeDispatcher;
ChainEditorWidget *chainWidget; ChainEditorWidget *chainWidget;
RoutingEditorWidget *ruleWidget; RoutingEditorWidget *ruleWidget;
@ -88,6 +78,4 @@ class RouteEditor
// //
CONFIGROOT root; CONFIGROOT root;
CONFIGROOT original; CONFIGROOT original;
//
void SetupNodeWidget();
}; };

View File

@ -232,51 +232,7 @@
<attribute name="title"> <attribute name="title">
<string>Route Editor</string> <string>Route Editor</string>
</attribute> </attribute>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1"> <layout class="QVBoxLayout" name="verticalLayout" stretch="1">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>A rule with no inbound connected means there's no inbound restriction.</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="addRouteBtn">
<property name="toolTip">
<string>Add new route</string>
</property>
<property name="text">
<string>Add Rule</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="delBtn">
<property name="toolTip">
<string>Delete outbound</string>
</property>
<property name="text">
<string>Delete Selection</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QWidget" name="ruleEditorUIWidget" native="true"> <widget class="QWidget" name="ruleEditorUIWidget" native="true">
<property name="minimumSize"> <property name="minimumSize">

View File

@ -47,7 +47,7 @@ void NodeDispatcher::LoadFullConfig(const CONFIGROOT &root)
void NodeDispatcher::RestoreConnections() void NodeDispatcher::RestoreConnections()
{ {
isConstructing = true; isOperationLocked = true;
for (const auto &rule : rules) for (const auto &rule : rules)
{ {
if (!ruleNodes.contains(rule->QV2RAY_RULE_TAG)) if (!ruleNodes.contains(rule->QV2RAY_RULE_TAG))
@ -81,11 +81,13 @@ void NodeDispatcher::RestoreConnections()
LOG(MODULE_NODE, "Could not find outbound: " + outboundTag) LOG(MODULE_NODE, "Could not find outbound: " + outboundTag)
} }
} }
isConstructing = false; isOperationLocked = false;
} }
void NodeDispatcher::DeleteNode(const QtNodes::Node &node) void NodeDispatcher::DeleteNode(const QtNodes::Node &node)
{ {
if (isOperationLocked)
return;
const auto nodeId = node.id(); const auto nodeId = node.id();
bool isInbound = inboundNodes.values().contains(nodeId); bool isInbound = inboundNodes.values().contains(nodeId);
bool isOutbound = outboundNodes.values().contains(nodeId); bool isOutbound = outboundNodes.values().contains(nodeId);

View File

@ -4,12 +4,6 @@
#include <nodes/FlowScene> #include <nodes/FlowScene>
enum TagNodeMode
{
NODE_INBOUND,
NODE_OUTBOUND
};
class NodeDispatcher class NodeDispatcher
: public QObject : public QObject
, public std::enable_shared_from_this<NodeDispatcher> , public std::enable_shared_from_this<NodeDispatcher>
@ -27,7 +21,11 @@ class NodeDispatcher
[[nodiscard]] QString CreateRule(RuleObject); [[nodiscard]] QString CreateRule(RuleObject);
bool IsNodeConstructing() const bool IsNodeConstructing() const
{ {
return isConstructing; return isOperationLocked;
}
void LockOperation()
{
isOperationLocked = true;
} }
public: public:
@ -60,7 +58,7 @@ class NodeDispatcher
void DeleteNode(const QtNodes::Node &node); void DeleteNode(const QtNodes::Node &node);
template<TagNodeMode t> template<TagNodeMode t>
inline bool RenameTag(const QString &originalTag, const QString &newTag) inline bool RenameTag(const QString originalTag, const QString newTag)
{ {
if constexpr (t == NODE_INBOUND) if constexpr (t == NODE_INBOUND)
{ {
@ -78,6 +76,15 @@ class NodeDispatcher
outbounds[newTag] = outbounds.take(originalTag); outbounds[newTag] = outbounds.take(originalTag);
outboundNodes[newTag] = outboundNodes.take(originalTag); outboundNodes[newTag] = outboundNodes.take(originalTag);
} }
else if constexpr (t == NODE_RULE)
{
bool hasExisting = rules.contains(newTag);
if (hasExisting)
return false;
rules[newTag] = rules.take(originalTag);
ruleNodes[newTag] = ruleNodes.take(originalTag);
}
emit OnObjectTagChanged(t, originalTag, newTag);
return true; return true;
} }
@ -87,6 +94,8 @@ class NodeDispatcher
void OnInboundCreated(std::shared_ptr<INBOUND>, QtNodes::Node &); void OnInboundCreated(std::shared_ptr<INBOUND>, QtNodes::Node &);
void OnOutboundCreated(std::shared_ptr<OutboundObjectMeta>, QtNodes::Node &); void OnOutboundCreated(std::shared_ptr<OutboundObjectMeta>, QtNodes::Node &);
void OnRuleCreated(std::shared_ptr<RuleObject>, QtNodes::Node &); void OnRuleCreated(std::shared_ptr<RuleObject>, QtNodes::Node &);
//
void OnObjectTagChanged(TagNodeMode, const QString originalTag, const QString newTag);
signals: signals:
void OnInboundOutboundNodeHovered(const QString &tag, const ProtocolSettingsInfoObject &); void OnInboundOutboundNodeHovered(const QString &tag, const ProtocolSettingsInfoObject &);
@ -101,7 +110,7 @@ class NodeDispatcher
QMap<QString, QUuid> ruleNodes; QMap<QString, QUuid> ruleNodes;
// //
QtNodes::FlowScene *scene; QtNodes::FlowScene *scene;
bool isConstructing; bool isOperationLocked;
QMap<QString, std::shared_ptr<INBOUND>> inbounds; QMap<QString, std::shared_ptr<INBOUND>> inbounds;
QMap<QString, std::shared_ptr<RuleObject>> rules; QMap<QString, std::shared_ptr<RuleObject>> rules;
QMap<QString, std::shared_ptr<OutboundObjectMeta>> outbounds; QMap<QString, std::shared_ptr<OutboundObjectMeta>> outbounds;

View File

@ -95,26 +95,31 @@ void QvNodeRuleWidget::on_routeProtocolHTTPCB_stateChanged(int)
LOADINGCHECK LOADINGCHECK
SetProtocolProperty(); SetProtocolProperty();
} }
void QvNodeRuleWidget::on_routeProtocolTLSCB_stateChanged(int) void QvNodeRuleWidget::on_routeProtocolTLSCB_stateChanged(int)
{ {
LOADINGCHECK LOADINGCHECK
SetProtocolProperty(); SetProtocolProperty();
} }
void QvNodeRuleWidget::on_routeProtocolBTCB_stateChanged(int) void QvNodeRuleWidget::on_routeProtocolBTCB_stateChanged(int)
{ {
LOADINGCHECK LOADINGCHECK
SetProtocolProperty(); SetProtocolProperty();
} }
void QvNodeRuleWidget::on_hostList_textChanged() void QvNodeRuleWidget::on_hostList_textChanged()
{ {
LOADINGCHECK LOADINGCHECK
rule.domain = SplitLines(hostList->toPlainText()); rule.domain = SplitLines(hostList->toPlainText());
} }
void QvNodeRuleWidget::on_ipList_textChanged() void QvNodeRuleWidget::on_ipList_textChanged()
{ {
LOADINGCHECK LOADINGCHECK
rule.ip = SplitLines(ipList->toPlainText()); rule.ip = SplitLines(ipList->toPlainText());
} }
void QvNodeRuleWidget::on_routePortTxt_textEdited(const QString &arg1) void QvNodeRuleWidget::on_routePortTxt_textEdited(const QString &arg1)
{ {
LOADINGCHECK LOADINGCHECK
@ -125,81 +130,61 @@ void QvNodeRuleWidget::on_routeUserTxt_textEdited(const QString &arg1)
LOADINGCHECK LOADINGCHECK
rule.user = SplitLines(arg1); rule.user = SplitLines(arg1);
} }
void QvNodeRuleWidget::on_netUDPRB_clicked() void QvNodeRuleWidget::on_netUDPRB_clicked()
{ {
LOADINGCHECK LOADINGCHECK
SetNetworkProperty(); SetNetworkProperty();
} }
void QvNodeRuleWidget::on_netTCPRB_clicked() void QvNodeRuleWidget::on_netTCPRB_clicked()
{ {
LOADINGCHECK LOADINGCHECK
SetNetworkProperty(); SetNetworkProperty();
} }
void QvNodeRuleWidget::on_sourceIPList_textChanged() void QvNodeRuleWidget::on_sourceIPList_textChanged()
{ {
LOADINGCHECK LOADINGCHECK
rule.source = SplitLines(sourceIPList->toPlainText()); rule.source = SplitLines(sourceIPList->toPlainText());
} }
void QvNodeRuleWidget::on_enableBalancerCB_stateChanged(int arg1)
{
// LOADINGCHECK
// auto useBalancer = arg1 == Qt::Checked;
// CurrentRule.QV2RAY_RULE_USE_BALANCER = useBalancer;
// // balancersWidget->setEnabled(useBalancer);
// // if (CurrentRule.balancerTag.isEmpty()) // void QvNodeRuleWidget::on_enableBalancerCB_stateChanged(int arg1)
// // { //{
// // LOG(MODULE_UI, "Creating a new balancer tag.") // // LOADINGCHECK
// // CurrentRule.balancerTag = GenerateRandomString(6); // // auto useBalancer = arg1 == Qt::Checked;
// // balancers[CurrentRule.balancerTag] = QStringList(); // // CurrentRule.QV2RAY_RULE_USE_BALANCER = useBalancer;
// // } // // // balancersWidget->setEnabled(useBalancer);
//
// // // if (CurrentRule.balancerTag.isEmpty())
// // // {
// // // LOG(MODULE_UI, "Creating a new balancer tag.")
// // // CurrentRule.balancerTag = GenerateRandomString(6);
// // // balancers[CurrentRule.balancerTag] = QStringList();
// // // }
//
// // DEBUG(MODULE_UI, "Balancer: " + CurrentRule.balancerTag)
//
// // if (useBalancer)
// // {
// // LOG(MODULE_UI, "A rule has been set to use balancer, disconnect it to any outbound.")
// // auto ruleNode = ruleNodes[currentRuleTag];
// // for (auto &&[_, conn] : nodeScene->connections())
// // {
// // if (conn->getNode(PortType::Out)->id() == ruleNode)
// // {
// // nodeScene->deleteConnection(*conn);
// // // Since there should be only one connection from this rule node.
// // break;
// // }
// // }
// // }
// // else
// // {
// // QvMessageBoxWarn(this, tr("Route Editor"), tr("To make this rule ready to use, you need to connect it to an outbound node."));
// // }
//}
// DEBUG(MODULE_UI, "Balancer: " + CurrentRule.balancerTag)
// if (useBalancer)
// {
// LOG(MODULE_UI, "A rule has been set to use balancer, disconnect it to any outbound.")
// auto ruleNode = ruleNodes[currentRuleTag];
// for (auto &&[_, conn] : nodeScene->connections())
// {
// if (conn->getNode(PortType::Out)->id() == ruleNode)
// {
// nodeScene->deleteConnection(*conn);
// // Since there should be only one connection from this rule node.
// break;
// }
// }
// }
// else
// {
// QvMessageBoxWarn(this, tr("Route Editor"), tr("To make this rule ready to use, you need to connect it to an outbound node."));
// }
}
void QvNodeRuleWidget::on_ruleRenameBtn_clicked()
{
abort();
// auto newTag = ruleTagLineEdit->text();
//
// if (newTag.isEmpty())
//{
// LOG(MODULE_UI, "Tag is empty, this is ILLEGAL!")
// QvMessageBoxWarn(this, tr("Renaming a tag"), tr("New tag is empty, please try another."));
//}
// else if (newTag == rule.QV2RAY_RULE_TAG)
//{
// LOG(MODULE_UI, "No tag changed, returning.")
// QvMessageBoxInfo(this, tr("Renaming a tag"), tr("New tag is the same as the original one."));
//}
// else if (rules.contains(newTag))
//{
// LOG(MODULE_UI, "Tag duplicate detected.")
// QvMessageBoxWarn(this, tr("Renaming a tag"), tr("Duplicate rule tag detected, please try another."));
//}
// else
//{
// RenameItemTag(RENAME_RULE, rule.QV2RAY_RULE_TAG, &newTag);
//}
}
void QvNodeRuleWidget::on_ruleEnableCB_stateChanged(int arg1) void QvNodeRuleWidget::on_ruleEnableCB_stateChanged(int arg1)
{ {
bool _isEnabled = arg1 == Qt::Checked; bool _isEnabled = arg1 == Qt::Checked;
@ -213,3 +198,15 @@ void QvNodeRuleWidget::on_toolButton_clicked()
adjustSize(); adjustSize();
emit OnSizeUpdated(); emit OnSizeUpdated();
} }
void QvNodeRuleWidget::on_ruleTagLineEdit_textEdited(const QString &arg1)
{
const auto originalTag = rule.QV2RAY_RULE_TAG;
if (originalTag == arg1 || dispatcher->RenameTag<NODE_RULE>(originalTag, arg1))
{
BLACK(ruleTagLineEdit);
rule.QV2RAY_RULE_TAG = arg1;
return;
}
RED(ruleTagLineEdit);
}

View File

@ -31,9 +31,10 @@ class QvNodeRuleWidget
void on_netUDPRB_clicked(); void on_netUDPRB_clicked();
void on_netTCPRB_clicked(); void on_netTCPRB_clicked();
void on_sourceIPList_textChanged(); void on_sourceIPList_textChanged();
void on_enableBalancerCB_stateChanged(int arg1);
void on_ruleRenameBtn_clicked();
void on_ruleEnableCB_stateChanged(int arg1); void on_ruleEnableCB_stateChanged(int arg1);
void on_ruleTagLineEdit_textEdited(const QString &arg1);
// void on_enableBalancerCB_stateChanged(int arg1);
protected: protected:
void changeEvent(QEvent *e) override; void changeEvent(QEvent *e) override;

View File

@ -1,11 +1,15 @@
#include "ChainEditorWidget.hpp" #include "ChainEditorWidget.hpp"
ChainEditorWidget::ChainEditorWidget(QWidget *parent) : QWidget(parent) #include "ui/node/NodeBase.hpp"
ChainEditorWidget::ChainEditorWidget(std::shared_ptr<NodeDispatcher> dispatcher, QWidget *parent) : QWidget(parent), dispatcher(dispatcher)
{ {
setupUi(this); setupUi(this);
QvMessageBusConnect(ChainEditorWidget); QvMessageBusConnect(ChainEditorWidget);
scene = new QtNodes::FlowScene(this); scene = new QtNodes::FlowScene(this);
view = new QtNodes::FlowView(scene, this); view = new QtNodes::FlowView(scene, this);
view->scaleDown();
if (!viewWidget->layout()) if (!viewWidget->layout())
{ {
// The QWidget will take ownership of layout. // The QWidget will take ownership of layout.

View File

@ -1,12 +1,13 @@
#pragma once #pragma once
#include "ui/messaging/QvMessageBus.hpp" #include "ui/messaging/QvMessageBus.hpp"
#include "ui/node/NodeBase.hpp"
#include "ui_ChainEditorWidget.h" #include "ui_ChainEditorWidget.h"
#include <nodes/FlowScene> #include <nodes/FlowScene>
#include <nodes/FlowView> #include <nodes/FlowView>
class NodeDispatcher;
class ChainEditorWidget class ChainEditorWidget
: public QWidget : public QWidget
, private Ui::ChainEditorWidget , private Ui::ChainEditorWidget
@ -14,7 +15,7 @@ class ChainEditorWidget
Q_OBJECT Q_OBJECT
public: public:
explicit ChainEditorWidget(QWidget *parent = nullptr); explicit ChainEditorWidget(std::shared_ptr<NodeDispatcher> dispatcher, QWidget *parent = nullptr);
auto getScene() auto getScene()
{ {
return scene; return scene;
@ -30,4 +31,5 @@ class ChainEditorWidget
private: private:
QtNodes::FlowScene *scene; QtNodes::FlowScene *scene;
QtNodes::FlowView *view; QtNodes::FlowView *view;
std::shared_ptr<NodeDispatcher> dispatcher;
}; };

View File

@ -1,12 +1,22 @@
#include "RoutingEditorWidget.hpp" #include "RoutingEditorWidget.hpp"
#include <QVBoxLayout> #include "ui/common/UIBase.hpp"
#include <nodes/FlowScene> #include "ui/node/NodeBase.hpp"
constexpr auto GRAPH_GLOBAL_OFFSET_X = -380;
constexpr auto GRAPH_GLOBAL_OFFSET_Y = -350;
RoutingEditorWidget::RoutingEditorWidget(QWidget *parent) : QWidget(parent) RoutingEditorWidget::RoutingEditorWidget(QWidget *parent) : QWidget(parent)
{ {
setupUi(this); setupUi(this);
QvMessageBusConnect(RoutingEditorWidget);
//
scene = new QtNodes::FlowScene(this); scene = new QtNodes::FlowScene(this);
dispatcher = std::make_shared<NodeDispatcher>(scene, this);
connect(dispatcher.get(), &NodeDispatcher::OnInboundCreated, this, &RoutingEditorWidget::OnDispatcherInboundCreated);
connect(dispatcher.get(), &NodeDispatcher::OnOutboundCreated, this, &RoutingEditorWidget::OnDispatcherOutboundCreated);
connect(dispatcher.get(), &NodeDispatcher::OnRuleCreated, this, &RoutingEditorWidget::OnDispatcherRuleCreated);
//
view = new QtNodes::FlowView(scene, this); view = new QtNodes::FlowView(scene, this);
view->scaleDown(); view->scaleDown();
@ -21,6 +31,22 @@ RoutingEditorWidget::RoutingEditorWidget(QWidget *parent) : QWidget(parent)
l->setSpacing(0); l->setSpacing(0);
} }
void RoutingEditorWidget::updateColorScheme()
{
addRouteBtn->setIcon(QICON_R("add"));
delBtn->setIcon(QICON_R("ashbin"));
}
QvMessageBusSlotImpl(RoutingEditorWidget)
{
switch (msg)
{
MBRetranslateDefaultImpl;
MBUpdateColorSchemeDefaultImpl;
default: break;
}
}
void RoutingEditorWidget::changeEvent(QEvent *e) void RoutingEditorWidget::changeEvent(QEvent *e)
{ {
QWidget::changeEvent(e); QWidget::changeEvent(e);
@ -30,3 +56,46 @@ void RoutingEditorWidget::changeEvent(QEvent *e)
default: break; default: break;
} }
} }
void RoutingEditorWidget::OnDispatcherInboundCreated(std::shared_ptr<INBOUND>, QtNodes::Node &node)
{
QPoint pos{ 0 + GRAPH_GLOBAL_OFFSET_X, dispatcher->InboundsCount() * 130 + GRAPH_GLOBAL_OFFSET_Y };
scene->setNodePosition(node, pos);
}
void RoutingEditorWidget::OnDispatcherOutboundCreated(std::shared_ptr<OutboundObjectMeta>, QtNodes::Node &node)
{
auto pos = this->pos();
pos.setX(pos.x() + 850 + GRAPH_GLOBAL_OFFSET_X);
pos.setY(pos.y() + dispatcher->OutboundsCount() * 120 + GRAPH_GLOBAL_OFFSET_Y);
scene->setNodePosition(node, pos);
}
void RoutingEditorWidget::OnDispatcherRuleCreated(std::shared_ptr<RuleObject>, QtNodes::Node &node)
{
auto pos = this->pos();
pos.setX(pos.x() + 350 + GRAPH_GLOBAL_OFFSET_X);
pos.setY(pos.y() + dispatcher->RulesCount() * 120 + GRAPH_GLOBAL_OFFSET_Y);
scene->setNodePosition(node, pos);
}
void RoutingEditorWidget::on_addRouteBtn_clicked()
{
const auto _ = dispatcher->CreateRule({});
}
void RoutingEditorWidget::on_delBtn_clicked()
{
if (scene->selectedNodes().empty())
{
QvMessageBoxWarn(this, tr("Remove Items"), tr("Please select a node from the graph to continue."));
return;
}
const auto selecteNodes = scene->selectedNodes();
if (selecteNodes.empty())
{
QvMessageBoxWarn(this, tr("Deleting a node"), tr("You need to select a node first"));
return;
}
scene->removeNode(*selecteNodes.front());
}

View File

@ -1,12 +1,15 @@
#pragma once #pragma once
#include "base/Qv2rayBase.hpp" #include "base/Qv2rayBase.hpp"
#include "ui/common/UIBase.hpp" #include "ui/messaging/QvMessageBus.hpp"
#include "ui/node/NodeBase.hpp"
#include "ui_RoutingEditorWidget.h" #include "ui_RoutingEditorWidget.h"
#include <nodes/FlowScene> #include <nodes/FlowScene>
#include <nodes/FlowView> #include <nodes/FlowView>
class NodeDispatcher;
class RoutingEditorWidget class RoutingEditorWidget
: public QWidget : public QWidget
, private Ui::RoutingEditorWidget , private Ui::RoutingEditorWidget
@ -19,14 +22,29 @@ class RoutingEditorWidget
{ {
return scene; return scene;
} }
std::shared_ptr<NodeDispatcher> GetDispatcher() const
{
return dispatcher;
}
protected: protected:
void changeEvent(QEvent *e); void changeEvent(QEvent *e);
private slots:
void OnDispatcherInboundCreated(std::shared_ptr<INBOUND>, QtNodes::Node &);
void OnDispatcherOutboundCreated(std::shared_ptr<complex::OutboundObjectMeta>, QtNodes::Node &);
void OnDispatcherRuleCreated(std::shared_ptr<RuleObject>, QtNodes::Node &);
void on_addRouteBtn_clicked();
void on_delBtn_clicked();
private: private:
void updateColorScheme(){}; void updateColorScheme();
QvMessageBusSlotDecl;
private: private:
QtNodes::FlowScene *scene; QtNodes::FlowScene *scene;
QtNodes::FlowView *view; QtNodes::FlowView *view;
std::shared_ptr<NodeDispatcher> dispatcher;
}; };

View File

@ -7,13 +7,13 @@
<x>0</x> <x>0</x>
<y>0</y> <y>0</y>
<width>926</width> <width>926</width>
<height>594</height> <height>568</height>
</rect> </rect>
</property> </property>
<property name="windowTitle"> <property name="windowTitle">
<string>Form</string> <string>Form</string>
</property> </property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1"> <layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
<property name="leftMargin"> <property name="leftMargin">
<number>0</number> <number>0</number>
</property> </property>
@ -26,6 +26,50 @@
<property name="bottomMargin"> <property name="bottomMargin">
<number>0</number> <number>0</number>
</property> </property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QLabel" name="label_7">
<property name="text">
<string>A rule with no inbound connected means there's no inbound restriction.</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="addRouteBtn">
<property name="toolTip">
<string>Add new route</string>
</property>
<property name="text">
<string>Add Rule</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="delBtn">
<property name="toolTip">
<string>Delete outbound</string>
</property>
<property name="text">
<string>Delete Selection</string>
</property>
</widget>
</item>
</layout>
</item>
<item> <item>
<widget class="QWidget" name="viewWidget" native="true"/> <widget class="QWidget" name="viewWidget" native="true"/>
</item> </item>