mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 02:40:20 +08:00
add: added copy existing config, link existing config, edit existing config
This commit is contained in:
parent
b26f455166
commit
cdc87d61d7
@ -1 +1 @@
|
||||
5820
|
||||
5821
|
||||
|
@ -107,6 +107,7 @@ namespace Qv2ray::base::objects::complex
|
||||
{
|
||||
OutboundObjectMeta meta;
|
||||
meta.metaType = METAOUTBOUND_ORIGINAL;
|
||||
meta.object.mode = MODE_CONNECTIONID;
|
||||
meta.object.connectionId = id;
|
||||
meta.object.displayName = tag;
|
||||
return meta;
|
||||
|
@ -71,7 +71,6 @@ void RouteEditor::SetupNodeWidget()
|
||||
nodeScene = new FlowScene(this);
|
||||
flowView = new FlowView(nodeScene, nodeGraphWidget);
|
||||
flowView->scaleDown();
|
||||
flowView->scaleDown();
|
||||
if (!nodeGraphWidget->layout())
|
||||
{
|
||||
// The QWidget will take ownership of layout.
|
||||
@ -416,79 +415,18 @@ void RouteEditor::on_delBtn_clicked()
|
||||
return;
|
||||
}
|
||||
|
||||
auto firstNode = nodeScene->selectedNodes()[0];
|
||||
auto isInbound = false; // inboundNodes.values().contains(firstNode->id());
|
||||
auto isOutbound = false; // outboundNodes.values().contains(firstNode->id());
|
||||
auto isRule = false; // ruleNodes.values().contains(firstNode->id());
|
||||
|
||||
// Get the tag first, and call inbounds/outbounds/rules container variable
|
||||
// remove() Remove the node last since some events may trigger. Then remove
|
||||
// the node container.
|
||||
if (isInbound)
|
||||
const auto selecteNodes = nodeScene->selectedNodes();
|
||||
if (selecteNodes.empty())
|
||||
{
|
||||
// currentInboundOutboundTag = GetFirstNodeData(firstNode->id(), InboundNode)->GetInbound();
|
||||
// nodeScene->removeNode(*nodeScene->node(inboundNodes[currentInboundOutboundTag]));
|
||||
// inboundNodes.remove(currentInboundOutboundTag);
|
||||
//
|
||||
// // Remove corresponded inbound tags from the rules.
|
||||
// for (auto k : rules.keys())
|
||||
// {
|
||||
// auto v = rules[k];
|
||||
// v.inboundTag.removeAll(currentInboundOutboundTag);
|
||||
// rules[k] = v;
|
||||
// }
|
||||
//
|
||||
// inbounds.remove(currentInboundOutboundTag);
|
||||
}
|
||||
else if (isOutbound)
|
||||
{
|
||||
// currentInboundOutboundTag = GetFirstNodeData(firstNode->id(), OutboundNode)->GetOutbound();
|
||||
// outbounds.remove(currentInboundOutboundTag);
|
||||
// ResolveDefaultOutboundTag(currentInboundOutboundTag, "");
|
||||
//
|
||||
//// Remove corresponded outbound tags from the rules.
|
||||
// for (auto k : rules.keys())
|
||||
//{
|
||||
// auto v = rules[k];
|
||||
//
|
||||
// if (v.outboundTag == currentInboundOutboundTag)
|
||||
// v.outboundTag.clear();
|
||||
//
|
||||
// rules[k] = v;
|
||||
//}
|
||||
//
|
||||
// nodeScene->removeNode(*nodeScene->node(outboundNodes[currentInboundOutboundTag]));
|
||||
// outboundNodes.remove(currentInboundOutboundTag);
|
||||
}
|
||||
else if (isRule)
|
||||
{
|
||||
// ruleEnableCB->setEnabled(false);
|
||||
// ruleTagLineEdit->setEnabled(false);
|
||||
// ruleRenameBtn->setEnabled(false);
|
||||
// auto RuleTag = GetFirstNodeData(firstNode->id(), RuleNode)->GetRuleTag();
|
||||
// currentRuleTag.clear();
|
||||
// routeRuleGroupBox->setEnabled(false);
|
||||
// routeEditGroupBox->setEnabled(false);
|
||||
// rules.remove(RuleTag);
|
||||
// nodeScene->removeNode(*nodeScene->node(ruleNodes[RuleTag]));
|
||||
// ruleNodes.remove(RuleTag);
|
||||
////
|
||||
//// Remove item from the rule order list widget.
|
||||
// ruleListWidget->takeItem(ruleListWidget->row(ruleListWidget->findItems(RuleTag, Qt::MatchExactly).first()));
|
||||
// CHECKEMPTYRULES
|
||||
//// currentRuleTag = rules.firstKey();
|
||||
// ShowCurrentRuleDetail();
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG(MODULE_UI, "Unknown node selected.")
|
||||
QvMessageBoxWarn(this, tr("Error"), tr("Qv2ray entered an unknown state."));
|
||||
QvMessageBoxWarn(this, tr("Deleting a node"), tr("You need to select a node first"));
|
||||
return;
|
||||
}
|
||||
nodeDispatcher->DeleteNode(selecteNodes.front()->id());
|
||||
}
|
||||
|
||||
void RouteEditor::on_addRouteBtn_clicked()
|
||||
{
|
||||
auto ruleName = nodeDispatcher->CreateRule({});
|
||||
Q_UNUSED(ruleName)
|
||||
const auto _ = nodeDispatcher->CreateRule({});
|
||||
}
|
||||
|
||||
void RouteEditor::on_domainStrategyCombo_currentIndexChanged(const QString &arg1)
|
||||
@ -540,3 +478,9 @@ void RouteEditor::on_debugPainterCB_clicked(bool checked)
|
||||
flowView->repaint();
|
||||
#endif
|
||||
}
|
||||
|
||||
void RouteEditor::on_linkExistingBtn_clicked()
|
||||
{
|
||||
const auto cid = ConnectionId{ importConnBtn->currentData(Qt::UserRole).toString() };
|
||||
auto _ = nodeDispatcher->CreateOutbound(make_outbound(cid, GetDisplayName(cid)));
|
||||
}
|
||||
|
@ -72,6 +72,8 @@ class RouteEditor
|
||||
|
||||
void on_debugPainterCB_clicked(bool checked);
|
||||
|
||||
void on_linkExistingBtn_clicked();
|
||||
|
||||
private:
|
||||
// NOTE: Self managed pointer.
|
||||
std::shared_ptr<NodeDispatcher> nodeDispatcher;
|
||||
|
@ -123,11 +123,11 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1,1,0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3" stretch="0,1,1,0,0">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="text">
|
||||
<string>Existed Connection</string>
|
||||
<string>Existing Connection</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@ -138,9 +138,16 @@
|
||||
<widget class="QComboBox" name="importConnBtn"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="importExistingBtn">
|
||||
<widget class="QPushButton" name="importExistingBtn">
|
||||
<property name="text">
|
||||
<string>OK</string>
|
||||
<string>Copy</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="linkExistingBtn">
|
||||
<property name="text">
|
||||
<string>Reference</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
@ -83,6 +83,38 @@ void NodeDispatcher::RestoreConnections()
|
||||
isConstructing = false;
|
||||
}
|
||||
|
||||
void NodeDispatcher::DeleteNode(const QUuid &nodeId)
|
||||
{
|
||||
bool isInbound = inboundNodes.values().contains(nodeId);
|
||||
bool isOutbound = outboundNodes.values().contains(nodeId);
|
||||
bool isRule = ruleNodes.values().contains(nodeId);
|
||||
// Lots of duplicated checks.
|
||||
{
|
||||
Q_ASSERT_X(isInbound && !isOutbound, "Delete Node", "Node type error.");
|
||||
Q_ASSERT_X(isInbound && !isRule, "Delete Node", "Node type error.");
|
||||
Q_ASSERT_X(isOutbound && !isInbound, "Delete Node", "Node type error.");
|
||||
Q_ASSERT_X(isOutbound && !isRule, "Delete Node", "Node type error.");
|
||||
Q_ASSERT_X(isRule && !isInbound, "Delete Node", "Node type error.");
|
||||
Q_ASSERT_X(isRule && !isOutbound, "Delete Node", "Node type error.");
|
||||
}
|
||||
|
||||
if (isInbound)
|
||||
{
|
||||
if (!inboundNodes.values().contains(nodeId))
|
||||
{
|
||||
LOG(MODULE_NODE, "Could not find a inbound with id: " + nodeId.toString())
|
||||
}
|
||||
}
|
||||
else if (isOutbound)
|
||||
{
|
||||
}
|
||||
else if (isRule)
|
||||
{
|
||||
}
|
||||
else
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
QString NodeDispatcher::CreateInbound(INBOUND in)
|
||||
{
|
||||
auto tag = getTag(in);
|
||||
|
@ -50,6 +50,9 @@ class NodeDispatcher
|
||||
return outbounds.count();
|
||||
}
|
||||
|
||||
public:
|
||||
void DeleteNode(const QUuid &nodeId);
|
||||
|
||||
signals:
|
||||
void OnInboundCreated(std::shared_ptr<INBOUND>, QtNodes::Node &);
|
||||
void OnOutboundCreated(std::shared_ptr<OutboundObjectMeta>, QtNodes::Node &);
|
||||
|
@ -2,6 +2,8 @@
|
||||
|
||||
#include "base/Qv2rayBase.hpp"
|
||||
#include "core/CoreUtils.hpp"
|
||||
#include "core/handler/ConfigHandler.hpp"
|
||||
#include "ui/common/UIBase.hpp"
|
||||
#include "ui/editors/w_InboundEditor.hpp"
|
||||
#include "ui/editors/w_JsonEditor.hpp"
|
||||
#include "ui/editors/w_OutboundEditor.hpp"
|
||||
@ -10,6 +12,8 @@ InboundOutboundWidget::InboundOutboundWidget(WidgetMode mode, std::shared_ptr<No
|
||||
{
|
||||
workingMode = mode;
|
||||
setupUi(this);
|
||||
editBtn->setIcon(QICON_R("edit"));
|
||||
editJsonBtn->setIcon(QICON_R("code"));
|
||||
}
|
||||
|
||||
void InboundOutboundWidget::setValue(std::shared_ptr<INBOUND> data)
|
||||
@ -23,7 +27,10 @@ void InboundOutboundWidget::setValue(std::shared_ptr<OutboundObjectMeta> data)
|
||||
{
|
||||
assert(workingMode == MODE_OUTBOUND);
|
||||
outboundObject = data;
|
||||
tagTxt->setText(getTag(outboundObject->realOutbound));
|
||||
tagTxt->setText(outboundObject->getTag());
|
||||
isExternalOutbound = outboundObject->object.mode == MODE_CONNECTIONID;
|
||||
statusLabel->setText(isExternalOutbound ? tr("External Config") : "");
|
||||
tagTxt->setEnabled(!isExternalOutbound);
|
||||
}
|
||||
|
||||
void InboundOutboundWidget::changeEvent(QEvent *e)
|
||||
@ -56,13 +63,37 @@ void InboundOutboundWidget::on_editBtn_clicked()
|
||||
}
|
||||
case MODE_OUTBOUND:
|
||||
{
|
||||
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;
|
||||
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 (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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -83,13 +114,33 @@ void InboundOutboundWidget::on_editJsonBtn_clicked()
|
||||
}
|
||||
case MODE_OUTBOUND:
|
||||
{
|
||||
JsonEditor editor{ outboundObject->realOutbound, parentWidget() };
|
||||
outboundObject->realOutbound = OUTBOUND{ editor.OpenEditor() };
|
||||
const auto newTag = getTag(outboundObject->realOutbound);
|
||||
// Set tag
|
||||
tagTxt->setText(newTag);
|
||||
outboundObject->realOutbound["tag"] = newTag;
|
||||
break;
|
||||
if (isExternalOutbound)
|
||||
{
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -33,4 +33,11 @@ class InboundOutboundWidget
|
||||
WidgetMode workingMode;
|
||||
std::shared_ptr<INBOUND> inboundObject;
|
||||
std::shared_ptr<OutboundObjectMeta> outboundObject;
|
||||
bool isExternalOutbound = false;
|
||||
|
||||
private:
|
||||
const QString editExternalMsg = tr("You are trying to edit an external connection config, is this what you want?");
|
||||
const QString editExternalComplexMsg = tr("You have selected an complex config as outbound.") + NEWLINE +
|
||||
tr("continuing editing this configuration will make you LOSS ALL INBOUND AND ROUTING settings.") +
|
||||
NEWLINE + tr("Is this what you want?");
|
||||
};
|
||||
|
@ -6,14 +6,14 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>152</width>
|
||||
<height>64</height>
|
||||
<width>181</width>
|
||||
<height>66</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Form</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@ -26,30 +26,41 @@
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="tagTxt"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QPushButton" name="editBtn">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources.new.qrc">
|
||||
<normaloff>:/assets/icons/ui_dark/edit.svg</normaloff>:/assets/icons/ui_dark/edit.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="editJsonBtn">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources.new.qrc">
|
||||
<normaloff>:/assets/icons/ui_dark/code.svg</normaloff>:/assets/icons/ui_dark/code.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,1">
|
||||
<item>
|
||||
<widget class="QPushButton" name="editBtn">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources.new.qrc">
|
||||
<normaloff>:/assets/icons/ui_light/edit.svg</normaloff>:/assets/icons/ui_light/edit.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="editJsonBtn">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../../../../resources.new.qrc">
|
||||
<normaloff>:/assets/icons/ui_light/code.svg</normaloff>:/assets/icons/ui_light/code.svg</iconset>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="statusLabel">
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
Loading…
Reference in New Issue
Block a user