refactor: refactored Complex Connection Editor

This commit is contained in:
QwQ 2020-07-25 11:27:04 +08:00
parent 81df0e0f02
commit 51da85cfe1
No known key found for this signature in database
GPG Key ID: E7FAEFAFCD031D4B
10 changed files with 157 additions and 289 deletions

View File

@ -1 +1 @@
5828
5829

View File

@ -4,9 +4,12 @@
#include "core/connection/Generation.hpp"
#include "core/handler/ConfigHandler.hpp"
#include "ui/common/UIBase.hpp"
#include "ui/node/NodeBase.hpp"
#include "ui/node/models/InboundNodeModel.hpp"
#include "ui/node/models/OutboundNodeModel.hpp"
#include "ui/node/models/RuleNodeModel.hpp"
#include "ui/widgets/complex/ChainEditorWidget.hpp"
#include "ui/widgets/complex/RoutingEditorWidget.hpp"
#include "ui/windows/w_ImportConfig.hpp"
#include "w_InboundEditor.hpp"
#include "w_JsonEditor.hpp"
@ -59,18 +62,30 @@ void RouteEditor::SetupNodeWidget()
"SelectedHaloColor": "deepskyblue","HoveredColor": "deepskyblue","LineWidth": 3.0,"ConstructionLineWidth": 2.0,
"PointDiameter": 10.0,"UseDataDefinedColors": false}})");
}
ruleScene = new FlowScene(this);
ruleView = new FlowView(ruleScene, nodeGraphWidget);
ruleView->scaleDown();
if (!nodeGraphWidget->layout())
{
// The QWidget will take ownership of layout.
nodeGraphWidget->setLayout(new QVBoxLayout());
ruleWidget = new RoutingEditorWidget(this);
if (!ruleEditorUIWidget->layout())
{
// The QWidget will take ownership of layout.
ruleEditorUIWidget->setLayout(new QVBoxLayout());
}
auto l = ruleEditorUIWidget->layout();
l->addWidget(ruleWidget);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
}
{
chainWidget = new ChainEditorWidget(this);
if (!chainEditorUIWidget->layout())
{
// The QWidget will take ownership of layout.
chainEditorUIWidget->setLayout(new QVBoxLayout());
}
auto l = chainEditorUIWidget->layout();
l->addWidget(chainWidget);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
}
auto l = nodeGraphWidget->layout();
l->addWidget(ruleView);
l->setContentsMargins(0, 0, 0, 0);
l->setSpacing(0);
}
RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QvDialog(parent), root(connection), original(connection)
@ -83,7 +98,7 @@ RouteEditor::RouteEditor(QJsonObject connection, QWidget *parent) : QvDialog(par
SetupNodeWidget();
updateColorScheme();
//
nodeDispatcher = std::make_shared<NodeDispatcher>(ruleScene);
nodeDispatcher = std::make_shared<NodeDispatcher>(ruleWidget->scene());
connect(nodeDispatcher.get(), &NodeDispatcher::OnInboundCreated, this, &RouteEditor::OnDispatcherInboundCreated);
connect(nodeDispatcher.get(), &NodeDispatcher::OnOutboundCreated, this, &RouteEditor::OnDispatcherOutboundCreated);
connect(nodeDispatcher.get(), &NodeDispatcher::OnRuleCreated, this, &RouteEditor::OnDispatcherRuleCreated);
@ -136,24 +151,24 @@ void RouteEditor::OnDispatcherInboundOutboundHovered(const QString &tag, const P
void RouteEditor::OnDispatcherInboundCreated(std::shared_ptr<INBOUND>, QtNodes::Node &node)
{
QPoint pos{ 0 + GRAPH_GLOBAL_OFFSET_X, nodeDispatcher->InboundsCount() * 130 + GRAPH_GLOBAL_OFFSET_Y };
ruleScene->setNodePosition(node, pos);
ruleWidget->scene()->setNodePosition(node, pos);
}
void RouteEditor::OnDispatcherOutboundCreated(std::shared_ptr<OutboundObjectMeta> out, QtNodes::Node &node)
{
QPoint pos = nodeGraphWidget->pos();
auto pos = ruleWidget->pos();
pos.setX(pos.x() + 850 + GRAPH_GLOBAL_OFFSET_X);
pos.setY(pos.y() + nodeDispatcher->OutboundsCount() * 120 + GRAPH_GLOBAL_OFFSET_Y);
ruleScene->setNodePosition(node, pos);
ruleWidget->scene()->setNodePosition(node, pos);
defaultOutboundCombo->addItem(out->getTag());
}
void RouteEditor::OnDispatcherRuleCreated(std::shared_ptr<RuleObject> rule, QtNodes::Node &node)
{
auto pos = nodeGraphWidget->pos();
auto pos = ruleWidget->pos();
pos.setX(pos.x() + 350 + GRAPH_GLOBAL_OFFSET_X);
pos.setY(pos.y() + nodeDispatcher->RulesCount() * 120 + GRAPH_GLOBAL_OFFSET_Y);
ruleScene->setNodePosition(node, pos);
ruleWidget->scene()->setNodePosition(node, pos);
ruleListWidget->addItem(rule->QV2RAY_RULE_TAG);
}
@ -398,19 +413,19 @@ void RouteEditor::on_addOutboundBtn_clicked()
void RouteEditor::on_delBtn_clicked()
{
if (ruleScene->selectedNodes().empty())
if (ruleWidget->scene()->selectedNodes().empty())
{
QvMessageBoxWarn(this, tr("Remove Items"), tr("Please select a node from the graph to continue."));
return;
}
const auto selecteNodes = ruleScene->selectedNodes();
const auto selecteNodes = ruleWidget->scene()->selectedNodes();
if (selecteNodes.empty())
{
QvMessageBoxWarn(this, tr("Deleting a node"), tr("You need to select a node first"));
return;
}
ruleScene->removeNode(*selecteNodes.front());
ruleWidget->scene()->removeNode(*selecteNodes.front());
}
void RouteEditor::on_addRouteBtn_clicked()
@ -463,8 +478,7 @@ void RouteEditor::on_debugPainterCB_clicked(bool checked)
{
#ifdef QT_DEBUG
QtNodes::ConnectionPainter::IsDebuggingEnabled = checked;
ruleScene->update();
ruleView->repaint();
ruleWidget->repaint();
#endif
}

View File

@ -1,13 +1,12 @@
#pragma once
#include "base/Qv2rayBase.hpp"
#include "base/models/QvComplexConfigModels.hpp"
#include "common/QvHelpers.hpp"
#include "ui/common/QvDialog.hpp"
#include "ui/common/UIBase.hpp"
#include "ui/messaging/QvMessageBus.hpp"
#include "ui/node/NodeBase.hpp"
#include "ui_w_RoutesEditor.h"
enum ROUTE_EDIT_MODE
{
RENAME_INBOUND,
@ -15,6 +14,15 @@ enum ROUTE_EDIT_MODE
RENAME_RULE,
};
class NodeDispatcher;
class ChainEditorWidget;
class RoutingEditorWidget;
namespace QtNodes
{
class Node;
};
namespace QtNodes
{
class FlowView;
@ -63,26 +71,23 @@ class RouteEditor
void on_linkExistingBtn_clicked();
private slots:
void OnDispatcherOutboundDeleted(const OutboundObjectMeta &);
void OnDispatcherOutboundDeleted(const complex::OutboundObjectMeta &);
void OnDispatcherInboundCreated(std::shared_ptr<INBOUND>, QtNodes::Node &);
void OnDispatcherOutboundCreated(std::shared_ptr<OutboundObjectMeta>, 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 &);
private:
// NOTE: Self managed pointer.
std::shared_ptr<NodeDispatcher> nodeDispatcher;
ChainEditorWidget *chainWidget;
RoutingEditorWidget *ruleWidget;
//
bool isLoading = false;
void RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, QString *newTag);
//
QString domainStrategy;
//
CONFIGROOT root;
CONFIGROOT original;
//
void SetupNodeWidget();
//
QtNodes::FlowScene *ruleScene;
QtNodes::FlowView *ruleView;
};

View File

@ -278,7 +278,7 @@
</layout>
</item>
<item>
<widget class="QWidget" name="nodeGraphWidget" native="true">
<widget class="QWidget" name="ruleEditorUIWidget" native="true">
<property name="minimumSize">
<size>
<width>0</width>
@ -293,6 +293,11 @@
<attribute name="title">
<string>Chain Editor</string>
</attribute>
<layout class="QGridLayout" name="gridLayout_3">
<item row="0" column="0">
<widget class="QWidget" name="chainEditorUIWidget" native="true"/>
</item>
</layout>
</widget>
</widget>
</item>

View File

@ -5,155 +5,6 @@
#include "ui/node/models/RuleNodeModel.hpp"
#include "w_RoutesEditor.hpp"
#include <nodes/internal/FlowScene.hpp>
// Do not use reference here, we need deep copy of EVERY QString.
void RouteEditor::RenameItemTag(ROUTE_EDIT_MODE mode, const QString originalTag, QString *newTag)
{
/*
switch (mode)
{
case RENAME_RULE:
if (rules.contains(originalTag) && ruleNodes.contains(originalTag))
{
if (rules.contains(*newTag) && ruleNodes.contains(*newTag))
{
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
*newTag += "_" + GenerateRandomString(5);
}
const auto &nodeDataModel = (QvRuleNodeModel *) nodeScene->node(ruleNodes.value(originalTag))->nodeDataModel();
if (nodeDataModel == nullptr)
{
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
}
nodeDataModel->setData(*newTag);
//
auto rule = rules.take(originalTag);
rule.QV2RAY_RULE_TAG = *newTag;
rules.insert(*newTag, rule);
ruleNodes.insert(*newTag, ruleNodes.take(originalTag));
//
// No other operation needed, but need to rename the one in the
// ruleOrder list widget.
auto items = ruleListWidget->findItems(originalTag, Qt::MatchExactly);
if (items.isEmpty())
{
LOG(MODULE_UI, "Cannot find a node: " + originalTag)
}
else
{
items.first()->setText(*newTag);
}
abort();
// if (currentRuleTag == originalTag)
// {
// currentRuleTag = *newTag;
// }
}
else
{
LOG(MODULE_UI, "There's nothing match " + originalTag + " in the containers.")
}
break;
case RENAME_OUTBOUND:
if (outbounds.contains(originalTag) && outboundNodes.contains(originalTag))
{
if (outbounds.contains(*newTag) && outboundNodes.contains(*newTag))
{
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a random string to the tag."));
*newTag += "_" + GenerateRandomString(5);
}
auto out = outbounds.take(originalTag);
out["tag"] = *newTag;
outbounds.insert(*newTag, out);
outboundNodes.insert(*newTag, outboundNodes.take(originalTag));
const auto &node = (QvOutboundNodeModel *) nodeScene->node(outboundNodes.value(*newTag))->nodeDataModel();
if (node == nullptr)
{
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
}
node->setData(*newTag);
// Change outbound tag in rules accordingly.
for (const auto &k : rules.keys())
{
auto v = rules.value(k);
if (v.outboundTag == originalTag)
{
v.outboundTag = *newTag;
// Put this inside the if block since no need an extra
// operation if the condition is false.
rules.insert(k, v);
}
}
// Resolve default outbound.
ResolveDefaultOutboundTag(originalTag, *newTag);
}
else
{
LOG(MODULE_UI, "Failed to rename an outbound --> Item not found.")
}
break;
case RENAME_INBOUND:
if (inbounds.contains(originalTag) && inboundNodes.contains(originalTag))
{
if (inbounds.contains(*newTag) && inboundNodes.contains(*newTag))
{
QvMessageBoxWarn(this, tr("Rename tags"), tr("The new tag has been used, we appended a postfix."));
*newTag += "_" + GenerateRandomString(5);
}
auto in = inbounds.take(originalTag);
in["tag"] = *newTag;
inbounds.insert(*newTag, in);
inboundNodes.insert(*newTag, inboundNodes.take(originalTag));
const auto &node = (QvInboundNodeModel *) nodeScene->node(inboundNodes.value(*newTag))->nodeDataModel();
if (node == nullptr)
{
LOG(MODULE_GRAPH, "EMPTY NODE WARN")
}
node->setData(*newTag);
// Change inbound tag in rules accordingly.
// k -> rule tag
// v -> rule object
for (const auto &k : rules.keys())
{
auto v = rules.value(k);
if (v.inboundTag.contains(originalTag))
{
v.inboundTag.append(*newTag);
v.inboundTag.removeAll(originalTag);
// Put this inside the if block since no need an extra
// operation if the condition is false.
rules.insert(k, v);
}
}
}
else
{
LOG(MODULE_UI, "Failed to rename an outbound --> Item not found.")
}
break;
}*/
}
// Do not use const reference here.
// void RouteEditor::ResolveDefaultOutboundTag(const QString original, const QString newTag)
//{

View File

@ -49,127 +49,112 @@ void InboundOutboundWidget::changeEvent(QEvent *e)
void InboundOutboundWidget::on_editBtn_clicked()
{
switch (workingMode)
if (workingMode == NODE_INBOUND)
{
case NODE_INBOUND:
InboundEditor editor{ *inboundObject, parentWidget() };
*inboundObject = editor.OpenEditor();
// Set tag
const auto newTag = getTag(*inboundObject);
tagTxt->setText(newTag);
(*inboundObject)["tag"] = newTag;
}
else
{
if (isExternalOutbound)
{
InboundEditor editor{ *inboundObject, parentWidget() };
*inboundObject = editor.OpenEditor();
// Set tag
const auto newTag = getTag(*inboundObject);
tagTxt->setText(newTag);
(*inboundObject)["tag"] = newTag;
break;
}
case NODE_OUTBOUND:
{
if (isExternalOutbound)
if (QvMessageBoxAsk(parentWidget(), tr("Edit Outbound"), editExternalMsg) != QMessageBox::Yes)
{
if (QvMessageBoxAsk(parentWidget(), tr("Edit Outbound"), editExternalMsg) != QMessageBox::Yes)
return;
}
const auto externalId = outboundObject->object.connectionId;
const auto root = ConnectionManager->GetConnectionRoot(externalId);
if (IsComplexConfig(root))
{
if (QvMessageBoxAsk(parentWidget(), tr("Trying to edit an Complex Config"), editExternalComplexMsg) != QMessageBox::Yes)
{
return;
}
const auto externalId = outboundObject->object.connectionId;
const auto root = ConnectionManager->GetConnectionRoot(externalId);
if (IsComplexConfig(root))
{
if (QvMessageBoxAsk(parentWidget(), tr("Trying to edit an Complex Config"), editExternalComplexMsg) != QMessageBox::Yes)
{
return;
}
}
OUTBOUND outbound{ QJsonIO::GetValue(root, "outbounds", 0).toObject() };
OutboundEditor editor{ outbound, parentWidget() };
outbound = editor.OpenEditor();
//
ConnectionManager->UpdateConnection(externalId, CONFIGROOT{ QJsonObject{ { "outbounds", QJsonArray{ outbound } } } });
}
else
{
OutboundEditor editor{ outboundObject->realOutbound, parentWidget() };
outboundObject->realOutbound = editor.OpenEditor();
// Set tag
const auto newTag = getTag(outboundObject->realOutbound);
tagTxt->setText(newTag);
outboundObject->realOutbound["tag"] = newTag;
break;
}
OUTBOUND outbound{ QJsonIO::GetValue(root, "outbounds", 0).toObject() };
OutboundEditor editor{ outbound, parentWidget() };
outbound = editor.OpenEditor();
//
ConnectionManager->UpdateConnection(externalId, CONFIGROOT{ QJsonObject{ { "outbounds", QJsonArray{ outbound } } } });
}
else
{
OutboundEditor editor{ outboundObject->realOutbound, parentWidget() };
outboundObject->realOutbound = editor.OpenEditor();
// Set tag
const auto newTag = getTag(outboundObject->realOutbound);
tagTxt->setText(newTag);
outboundObject->realOutbound["tag"] = newTag;
}
}
}
void InboundOutboundWidget::on_editJsonBtn_clicked()
{
switch (workingMode)
if (workingMode == NODE_INBOUND)
{
case NODE_INBOUND:
JsonEditor editor{ *inboundObject, parentWidget() };
*inboundObject = INBOUND{ editor.OpenEditor() };
const auto newTag = getTag(*inboundObject);
// Set tag
tagTxt->setText(newTag);
(*inboundObject)["tag"] = newTag;
}
else
{
if (isExternalOutbound)
{
JsonEditor editor{ *inboundObject, parentWidget() };
*inboundObject = INBOUND{ editor.OpenEditor() };
const auto newTag = getTag(*inboundObject);
// Set tag
tagTxt->setText(newTag);
(*inboundObject)["tag"] = newTag;
break;
}
case NODE_OUTBOUND:
{
if (isExternalOutbound)
{
if (QvMessageBoxAsk(parentWidget(), tr("Edit Outbound"), editExternalMsg) != QMessageBox::Yes)
{
return;
}
const auto externalId = outboundObject->object.connectionId;
const auto root = ConnectionManager->GetConnectionRoot(externalId);
if (QvMessageBoxAsk(parentWidget(), tr("Edit Outbound"), editExternalMsg) != QMessageBox::Yes)
return;
const auto externalId = outboundObject->object.connectionId;
const auto root = ConnectionManager->GetConnectionRoot(externalId);
OUTBOUND outbound{ QJsonIO::GetValue(root, "outbounds", 0).toObject() };
JsonEditor editor{ outbound, parentWidget() };
outbound = OUTBOUND{ editor.OpenEditor() };
//
ConnectionManager->UpdateConnection(externalId, CONFIGROOT{ QJsonObject{ { "outbounds", QJsonArray{ outbound } } } });
}
else
{
// Open Editor
JsonEditor editor{ outboundObject->realOutbound, parentWidget() };
outboundObject->realOutbound = OUTBOUND{ editor.OpenEditor() };
//
// Set tag (only for local connections)
const auto newTag = getTag(outboundObject->realOutbound);
tagTxt->setText(newTag);
outboundObject->realOutbound["tag"] = newTag;
break;
}
OUTBOUND outbound{ QJsonIO::GetValue(root, "outbounds", 0).toObject() };
JsonEditor editor{ outbound, parentWidget() };
outbound = OUTBOUND{ editor.OpenEditor() };
//
ConnectionManager->UpdateConnection(externalId, CONFIGROOT{ QJsonObject{ { "outbounds", QJsonArray{ outbound } } } });
}
else
{
// Open Editor
JsonEditor editor{ outboundObject->realOutbound, parentWidget() };
outboundObject->realOutbound = OUTBOUND{ editor.OpenEditor() };
//
// Set tag (only for local connections)
const auto newTag = getTag(outboundObject->realOutbound);
tagTxt->setText(newTag);
outboundObject->realOutbound["tag"] = newTag;
}
}
}
void InboundOutboundWidget::on_tagTxt_textEdited(const QString &arg1)
{
switch (workingMode)
if (workingMode == NODE_INBOUND)
{
case NODE_INBOUND:
const auto originalTag = (*inboundObject)["tag"].toString();
if (originalTag == arg1 || dispatcher->RenameTag<NODE_INBOUND>(originalTag, arg1))
{
const auto originalTag = (*inboundObject)["tag"].toString();
if (originalTag == arg1 || dispatcher->RenameTag<NODE_INBOUND>(originalTag, arg1))
{
BLACK(tagTxt);
(*inboundObject)["tag"] = arg1;
break;
}
RED(tagTxt);
BLACK(tagTxt);
(*inboundObject)["tag"] = arg1;
return;
}
case NODE_OUTBOUND:
RED(tagTxt);
}
else
{
const auto originalTag = outboundObject->getTag();
if (originalTag == arg1 || dispatcher->RenameTag<NODE_OUTBOUND>(originalTag, arg1))
{
const auto originalTag = outboundObject->getTag();
if (originalTag == arg1 || dispatcher->RenameTag<NODE_OUTBOUND>(originalTag, arg1))
{
BLACK(tagTxt);
outboundObject->realOutbound["tag"] = arg1;
break;
}
RED(tagTxt);
BLACK(tagTxt);
outboundObject->realOutbound["tag"] = arg1;
return;
}
RED(tagTxt);
}
}

View File

@ -1,8 +1,9 @@
#include "ChainEditorWidget.hpp"
ChainEditorWidget::ChainEditorWidget(QWidget *parent) : QWidget(parent)
ChainEditorWidget::ChainEditorWidget(QWidget *parent) : QtNodes::FlowView(parent)
{
setupUi(this);
setScene(new QtNodes::FlowScene(this));
}
void ChainEditorWidget::changeEvent(QEvent *e)

View File

@ -3,25 +3,21 @@
#include "ui/node/NodeBase.hpp"
#include "ui_ChainEditorWidget.h"
namespace QtNodes
{
class FlowView;
}
#include <nodes/FlowView>
class ChainEditorWidget
: public QWidget
: public QtNodes::FlowView
, private Ui::ChainEditorWidget
{
Q_OBJECT
public:
explicit ChainEditorWidget(QWidget *parent = nullptr);
auto scene()
{
return QtNodes::FlowView::scene();
}
protected:
void changeEvent(QEvent *e);
private:
//
QtNodes::FlowScene *chainScene;
QtNodes::FlowView *chainView;
};

View File

@ -1,8 +1,13 @@
#include "RoutingEditorWidget.hpp"
RoutingEditorWidget::RoutingEditorWidget(QWidget *parent) : QWidget(parent)
#include <QVBoxLayout>
#include <nodes/FlowScene>
RoutingEditorWidget::RoutingEditorWidget(QWidget *parent) : QtNodes::FlowView(parent)
{
setupUi(this);
setScene(new QtNodes::FlowScene(this));
scaleDown();
}
void RoutingEditorWidget::changeEvent(QEvent *e)

View File

@ -2,14 +2,20 @@
#include "ui_RoutingEditorWidget.h"
#include <nodes/FlowView>
class RoutingEditorWidget
: public QWidget
: public QtNodes::FlowView
, private Ui::RoutingEditorWidget
{
Q_OBJECT
public:
explicit RoutingEditorWidget(QWidget *parent = nullptr);
auto scene()
{
return QtNodes::FlowView::scene();
}
protected:
void changeEvent(QEvent *e);