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
};
enum TagNodeMode
{
NODE_INBOUND,
NODE_OUTBOUND,
NODE_RULE
};
struct OutboundObject
{
QString displayName;

View File

@ -28,9 +28,6 @@
using namespace QtNodes;
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 LOADINGCHECK \
if (isLoading) \
@ -38,32 +35,54 @@ constexpr auto GRAPH_GLOBAL_OFFSET_Y = -350;
#define LOAD_FLAG_BEGIN isLoading = true;
#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)
{
ConnectionStyle::setConnectionStyle(
R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,
"ConstructionLineWidth": 2.0,"PointDiameter": 10.0,"UseDataDefinedColors": true}})");
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,
"ConstructionLineWidth": 2.0,"PointDiameter": 10.0,"UseDataDefinedColors": true}})");
}
else
{
QtNodes::NodeStyle::setNodeStyle(
R"({"NodeStyle": {"NormalBoundaryColor": "darkgray","SelectedBoundaryColor": "deepskyblue",
"GradientColor0": "mintcream","GradientColor1": "mintcream","GradientColor2": "mintcream",
"GradientColor3": "mintcream","ShadowColor": [200, 200, 200],"FontColor": [10, 10, 10],
"FontColorFaded": [100, 100, 100],"ConnectionPointColor": "white","PenWidth": 2.0,"HoveredPenWidth": 2.5,
"ConnectionPointDiameter": 10.0,"Opacity": 1.0}})");
"GradientColor0": "mintcream","GradientColor1": "mintcream","GradientColor2": "mintcream",
"GradientColor3": "mintcream","ShadowColor": [200, 200, 200],"FontColor": [10, 10, 10],
"FontColorFaded": [100, 100, 100],"ConnectionPointColor": "white","PenWidth": 2.0,"HoveredPenWidth": 2.5,
"ConnectionPointDiameter": 10.0,"Opacity": 1.0}})");
QtNodes::FlowViewStyle::setStyle(
R"({"FlowViewStyle": {"BackgroundColor": [255, 255, 240],"FineGridColor": [245, 245, 230],"CoarseGridColor": [235, 235, 220]}})");
ConnectionStyle::setConnectionStyle(
R"({"ConnectionStyle": {"ConstructionColor": "gray","NormalColor": "black","SelectedColor": "gray",
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,"ConstructionLineWidth": 2.0,
"PointDiameter": 10.0,"UseDataDefinedColors": false}})");
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,"ConstructionLineWidth": 2.0,
"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);
//
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())
{
// The QWidget will take ownership of layout.
@ -74,8 +93,9 @@ void RouteEditor::SetupNodeWidget()
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
}
{
chainWidget = new ChainEditorWidget(chainEditorUIWidget);
chainWidget = new ChainEditorWidget(nodeDispatcher, chainEditorUIWidget);
if (!chainEditorUIWidget->layout())
{
// The QWidget will take ownership of layout.
@ -86,23 +106,6 @@ void RouteEditor::SetupNodeWidget()
l->setContentsMargins(0, 0, 0, 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();
domainStrategyCombo->setCurrentText(domainStrategy);
@ -148,27 +151,13 @@ void RouteEditor::OnDispatcherInboundOutboundHovered(const QString &tag, const P
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());
}
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);
}
@ -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()
{
auto result = this->exec();
@ -287,8 +301,9 @@ CONFIGROOT RouteEditor::OpenEditor()
RouteEditor::~RouteEditor()
{
nodeDispatcher.reset();
nodeDispatcher->LockOperation();
}
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)
{
LOADINGCHECK

View File

@ -42,43 +42,33 @@ class RouteEditor
void processCommands(QString, QStringList, QMap<QString, QString>) override{};
private:
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"));
}
void updateColorScheme() override;
QvMessageBusSlotDecl;
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_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_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();
private slots:
void OnDispatcherOutboundDeleted(const complex::OutboundObjectMeta &);
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 OnDispatcherInboundOutboundHovered(const QString &, const ProtocolSettingsInfoObject &);
void OnDispatcherObjectTagChanged(TagNodeMode, const QString, const QString);
private:
// NOTE: Self managed pointer.
std::shared_ptr<NodeDispatcher> nodeDispatcher;
ChainEditorWidget *chainWidget;
RoutingEditorWidget *ruleWidget;
@ -88,6 +78,4 @@ class RouteEditor
//
CONFIGROOT root;
CONFIGROOT original;
//
void SetupNodeWidget();
};

View File

@ -232,51 +232,7 @@
<attribute name="title">
<string>Route Editor</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,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>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1">
<item>
<widget class="QWidget" name="ruleEditorUIWidget" native="true">
<property name="minimumSize">

View File

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

View File

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

View File

@ -95,26 +95,31 @@ void QvNodeRuleWidget::on_routeProtocolHTTPCB_stateChanged(int)
LOADINGCHECK
SetProtocolProperty();
}
void QvNodeRuleWidget::on_routeProtocolTLSCB_stateChanged(int)
{
LOADINGCHECK
SetProtocolProperty();
}
void QvNodeRuleWidget::on_routeProtocolBTCB_stateChanged(int)
{
LOADINGCHECK
SetProtocolProperty();
}
void QvNodeRuleWidget::on_hostList_textChanged()
{
LOADINGCHECK
rule.domain = SplitLines(hostList->toPlainText());
}
void QvNodeRuleWidget::on_ipList_textChanged()
{
LOADINGCHECK
rule.ip = SplitLines(ipList->toPlainText());
}
void QvNodeRuleWidget::on_routePortTxt_textEdited(const QString &arg1)
{
LOADINGCHECK
@ -125,81 +130,61 @@ void QvNodeRuleWidget::on_routeUserTxt_textEdited(const QString &arg1)
LOADINGCHECK
rule.user = SplitLines(arg1);
}
void QvNodeRuleWidget::on_netUDPRB_clicked()
{
LOADINGCHECK
SetNetworkProperty();
}
void QvNodeRuleWidget::on_netTCPRB_clicked()
{
LOADINGCHECK
SetNetworkProperty();
}
void QvNodeRuleWidget::on_sourceIPList_textChanged()
{
LOADINGCHECK
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())
// // {
// // LOG(MODULE_UI, "Creating a new balancer tag.")
// // CurrentRule.balancerTag = GenerateRandomString(6);
// // balancers[CurrentRule.balancerTag] = QStringList();
// // }
// 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())
// // // {
// // // 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)
{
bool _isEnabled = arg1 == Qt::Checked;
@ -213,3 +198,15 @@ void QvNodeRuleWidget::on_toolButton_clicked()
adjustSize();
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_netTCPRB_clicked();
void on_sourceIPList_textChanged();
void on_enableBalancerCB_stateChanged(int arg1);
void on_ruleRenameBtn_clicked();
void on_ruleEnableCB_stateChanged(int arg1);
void on_ruleTagLineEdit_textEdited(const QString &arg1);
// void on_enableBalancerCB_stateChanged(int arg1);
protected:
void changeEvent(QEvent *e) override;

View File

@ -1,11 +1,15 @@
#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);
QvMessageBusConnect(ChainEditorWidget);
scene = new QtNodes::FlowScene(this);
view = new QtNodes::FlowView(scene, this);
view->scaleDown();
if (!viewWidget->layout())
{
// The QWidget will take ownership of layout.

View File

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

View File

@ -1,12 +1,22 @@
#include "RoutingEditorWidget.hpp"
#include <QVBoxLayout>
#include <nodes/FlowScene>
#include "ui/common/UIBase.hpp"
#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)
{
setupUi(this);
QvMessageBusConnect(RoutingEditorWidget);
//
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->scaleDown();
@ -21,6 +31,22 @@ RoutingEditorWidget::RoutingEditorWidget(QWidget *parent) : QWidget(parent)
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)
{
QWidget::changeEvent(e);
@ -30,3 +56,46 @@ void RoutingEditorWidget::changeEvent(QEvent *e)
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
#include "base/Qv2rayBase.hpp"
#include "ui/common/UIBase.hpp"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui/node/NodeBase.hpp"
#include "ui_RoutingEditorWidget.h"
#include <nodes/FlowScene>
#include <nodes/FlowView>
class NodeDispatcher;
class RoutingEditorWidget
: public QWidget
, private Ui::RoutingEditorWidget
@ -19,14 +22,29 @@ class RoutingEditorWidget
{
return scene;
}
std::shared_ptr<NodeDispatcher> GetDispatcher() const
{
return dispatcher;
}
protected:
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:
void updateColorScheme(){};
void updateColorScheme();
QvMessageBusSlotDecl;
private:
QtNodes::FlowScene *scene;
QtNodes::FlowView *view;
std::shared_ptr<NodeDispatcher> dispatcher;
};

View File

@ -7,13 +7,13 @@
<x>0</x>
<y>0</y>
<width>926</width>
<height>594</height>
<height>568</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout" stretch="1">
<layout class="QVBoxLayout" name="verticalLayout" stretch="0,1">
<property name="leftMargin">
<number>0</number>
</property>
@ -26,6 +26,50 @@
<property name="bottomMargin">
<number>0</number>
</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>
<widget class="QWidget" name="viewWidget" native="true"/>
</item>