diff --git a/makespec/BUILDVERSION b/makespec/BUILDVERSION
index 87ca4f07..7174ebd1 100644
--- a/makespec/BUILDVERSION
+++ b/makespec/BUILDVERSION
@@ -1 +1 @@
-4284
+4326
diff --git a/src/core/kernel/APIBackend.cpp b/src/core/kernel/APIBackend.cpp
index bd7b403a..3f7b0823 100644
--- a/src/core/kernel/APIBackend.cpp
+++ b/src/core/kernel/APIBackend.cpp
@@ -13,6 +13,15 @@ namespace Qv2ray::core::kernel
{
// To all contributors:
//
+ // You may feel it difficult to understand this part of API backend.
+ // It's been expected that you will take hours to fully understand the tricks and hacks lying deeply in this class.
+ //
+ // The API Worker runs as a daemon together with Qv2ray, on a single thread.
+ // They use a flag, running, to indicate if the API worker should go and fetch the statistics from V2ray Core.
+ //
+ // The flag, running, will be set to true, immediately after the V2ray core reported that it's been started.
+ // and will be set to false right before we stopping V2ray Core.
+ //
// --- CONSTRUCTOR ---
APIWorker::APIWorker()
@@ -20,9 +29,9 @@ namespace Qv2ray::core::kernel
thread = new QThread();
this->moveToThread(thread);
DEBUG(MODULE_VCORE, "API Worker initialised.")
- connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
+ // connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), this, SLOT(process()));
- connect(thread, &QThread::finished, []() { LOG(MODULE_VCORE, "API thread stopped") });
+ connect(thread, &QThread::finished, [] { LOG(MODULE_VCORE, "API thread stopped") });
started = true;
thread->start();
DEBUG(MODULE_VCORE, "API Worker started.")
diff --git a/src/ui/w_MainWindow.cpp b/src/ui/w_MainWindow.cpp
index 9c1a9ed6..b633eb71 100644
--- a/src/ui/w_MainWindow.cpp
+++ b/src/ui/w_MainWindow.cpp
@@ -162,10 +162,12 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) //, vinstance(), h
// Actions for right click the connection list
//
QAction *action_RCM_StartThis = new QAction(tr("Connect to this"), this);
+ QAction *action_RCM_RenameThis = new QAction(tr("Rename"), this);
QAction *action_RCM_ConvToComplex = new QAction(QICON_R("edit.png"), tr("Edit as Complex Config"), this);
//
connect(action_RCM_StartThis, &QAction::triggered, this, &MainWindow::on_action_StartThis_triggered);
connect(action_RCM_ConvToComplex, &QAction::triggered, this, &MainWindow::on_action_RCM_ConvToComplex_triggered);
+ connect(action_RCM_RenameThis, &QAction::triggered, this, &MainWindow::on_action_RCM_RenameThis_triggered);
//
// Globally invokable signals.
connect(this, &MainWindow::Connect, [&] { ConnectionManager->StartConnection(lastConnectedId); });
@@ -177,6 +179,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) //, vinstance(), h
//
connectionListMenu = new QMenu(this);
connectionListMenu->addAction(action_RCM_StartThis);
+ connectionListMenu->addAction(action_RCM_RenameThis);
connectionListMenu->addAction(action_RCM_ConvToComplex);
//
LOG(MODULE_UI, "Loading data...")
@@ -189,7 +192,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) //, vinstance(), h
for (auto connection : connections)
{
- MWAddConnectionItem_p(connection, group); //
+ MWAddConnectionItem_p(connection, group);
}
}
//
@@ -368,6 +371,7 @@ void MainWindow::ToggleVisibility()
void MainWindow::on_actionExit_triggered()
{
+ ConnectionManager->StopConnection();
if (StartupOption.enableToolbarPlguin)
{
StopProcessingPlugins();
@@ -396,85 +400,6 @@ void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint
}
}
-void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
-{
- // DEBUG(UI, "A connection ListViewItem is changed. This should ONLY occur
- // when renaming an connection.")
- //
- // if (!isRenamingInProgress) {
- // return;
- //}
- //
- // isRenamingInProgress = false;
- //// In this case it's after we entered the name.
- //// and tell user you should not rename a config from subscription.
- // auto newIdentifier = renameOriginalIdentifier;
- // newIdentifier.connectionName = item->text(0);
- // LOG(CONNECTION, "RENAME: " + renameOriginalIdentifier.IdentifierString()
- // + " -> " + newIdentifier.IdentifierString())
- //
- //// If I really did some changes.
- // if (renameOriginalIdentifier != newIdentifier) {
- // bool canContinueRename = true;
- //
- // if (newIdentifier.connectionName.trimmed().isEmpty()) {
- // QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name
- // cannot be empty")); canContinueRename = false;
- // }
- //
- // QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
- // //if (GlobalConfig.configs.contains(newIdentifier.connectionName)) {
- // // QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name
- // has been used already, Please choose another."));
- // // canContinueRename = false;
- // //}
- //
- // if (!IsValidFileName(newIdentifier.connectionName +
- // QV2RAY_CONFIG_FILE_EXTENSION)) {
- // QvMessageBoxWarn(this, tr("Rename a Connection"), tr("The name you
- // suggested is not valid, please try another.")); canContinueRename
- // = false;
- // }
- //
- // if (!canContinueRename) {
- // // Set the item text back
- // assert(item != nullptr); // Let's say the item should not be null
- // item->setText(0, renameOriginalIdentifier.connectionName);
- // return;
- // }
- //
- // // Change auto start config.
- // // |--------------=== In case it's not in a subscription --|
- // if (GlobalConfig.autoStartConfig == renameOriginalIdentifier) {
- // GlobalConfig.autoStartConfig = newIdentifier;
- // }
- //
- // QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
- // //// Replace the items in the current loaded config list and settings.
- // //// Note: This original name should only be a reguular.
- // //GlobalConfig.configs.removeOne(renameOriginalIdentifier.connectionName);
- // //GlobalConfig.configs.push_back(newIdentifier.connectionName);
- // //
- // //connections[newIdentifier] =
- // connections.take(renameOriginalIdentifier);
- // //RenameConnection(renameOriginalIdentifier.connectionName,
- // newIdentifier.connectionName);
- // //LOG(UI, "Saving a global config")
- // //SaveGlobalConfig(GlobalConfig);
- // ////
- // //item->setData(0, Qt::UserRole, QVariant::fromValue(newIdentifier));
- // //
- // //if (CurrentConnectionIdentifier == renameOriginalIdentifier) {
- // // CurrentConnectionIdentifier = newIdentifier;
- // //
- // // if (vinstance->KernelStarted) {
- // // on_reconnectButton_clicked();
- // // }
- // //}
- // //OnConfigListChanged(CurrentConnectionIdentifier.connectionName ==
- // renameOriginalName);
- //}
-}
void MainWindow::on_removeConfigButton_clicked()
{
QvMessageBoxInfo(this, "NOT SUPPORTED", "WIP");
@@ -622,6 +547,10 @@ void MainWindow::on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item
void MainWindow::OnDisconnected(const ConnectionId &id)
{
Q_UNUSED(id)
+ action_Tray_Start->setEnabled(true);
+ action_Tray_Stop->setEnabled(false);
+ action_Tray_Reconnect->setEnabled(false);
+ tray_SystemProxyMenu->setEnabled(false);
lastConnectedId = id;
locateBtn->setEnabled(false);
this->hTray.showMessage("Qv2ray", tr("Disconnected from: ") + ConnectionManager->GetDisplayName(id), this->windowIcon());
@@ -642,6 +571,10 @@ void MainWindow::OnDisconnected(const ConnectionId &id)
void MainWindow::OnConnected(const ConnectionId &id)
{
Q_UNUSED(id)
+ action_Tray_Start->setEnabled(false);
+ action_Tray_Stop->setEnabled(true);
+ action_Tray_Reconnect->setEnabled(true);
+ tray_SystemProxyMenu->setEnabled(true);
lastConnectedId = id;
locateBtn->setEnabled(true);
on_clearlogButton_clicked();
@@ -907,5 +840,13 @@ void MainWindow::on_locateBtn_clicked()
if (id != NullConnectionId)
{
connectionListWidget->setCurrentItem(connectionNodes[id].get());
+ connectionListWidget->scrollToItem(connectionNodes[id].get());
+ on_connectionListWidget_itemClicked(connectionNodes[id].get(), 0);
}
}
+
+void MainWindow::on_action_RCM_RenameThis_triggered()
+{
+ CheckCurrentWidget;
+ widget->BeginRename();
+}
diff --git a/src/ui/w_MainWindow.hpp b/src/ui/w_MainWindow.hpp
index f10d9cce..90e46ed6 100644
--- a/src/ui/w_MainWindow.hpp
+++ b/src/ui/w_MainWindow.hpp
@@ -37,7 +37,6 @@ class MainWindow
void on_preferencesBtn_clicked();
void on_clearlogButton_clicked();
void on_connectionListWidget_customContextMenuRequested(const QPoint &pos);
- void on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int column);
void on_removeConfigButton_clicked();
void on_importConfigButton_clicked();
void on_subsButton_clicked();
@@ -77,6 +76,7 @@ class MainWindow
//
void on_action_StartThis_triggered();
void on_action_RCM_ConvToComplex_triggered();
+ void on_action_RCM_RenameThis_triggered();
//
void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
void on_connectionFilterTxt_textEdited(const QString &arg1);
diff --git a/src/ui/w_MainWindow.ui b/src/ui/w_MainWindow.ui
index f2a3cf76..c369cdaf 100644
--- a/src/ui/w_MainWindow.ui
+++ b/src/ui/w_MainWindow.ui
@@ -494,232 +494,6 @@
-
-
-
- #ManuallyCreateConnection
-
-
-
-
- #ImportConnection
-
-
-
-
- #Exit
-
-
-
-
- #Preferences
-
-
-
-
- #Start
-
-
-
-
- #Stop
-
-
-
-
- #Restart
-
-
-
-
- Import from vmess://
-
-
-
-
- Import from QRCode File
-
-
-
-
- Import from ScreenShot
-
-
-
-
- Open Configuration Folder
-
-
-
-
- Exit
-
-
-
-
- From File
-
-
-
-
- From Connection Link
-
-
-
-
- From QRCode File
-
-
-
-
- Take ScreenShot
-
-
-
-
- Open Connection Editor
-
-
-
-
- Manually Create Connection
-
-
-
-
- Manually Create Complex Connection
-
-
-
-
- Copy Connection Link
-
-
-
-
- Copy QRCode
-
-
-
-
- Save QRCode to File
-
-
-
-
- Open Subscription Manager
-
-
-
-
- Update All Subscriptions
-
-
-
-
- Update All Subscriptions with System Proxy
-
-
-
-
- Options
-
-
-
-
- About Qt
-
-
-
-
- About Qv2ray
-
-
-
-
- Help
-
-
-
-
- Save Qv2ray Log
-
-
-
-
- Json Editor
-
-
diff --git a/src/ui/w_PreferencesWindow.cpp b/src/ui/w_PreferencesWindow.cpp
index eca5af3b..4cc72f03 100644
--- a/src/ui/w_PreferencesWindow.cpp
+++ b/src/ui/w_PreferencesWindow.cpp
@@ -1,4 +1,5 @@
#include "w_PreferencesWindow.hpp"
+
#include "common/HTTPRequestHelper.hpp"
#include "common/QvHelpers.hpp"
#include "common/QvTranslator.hpp"
@@ -1029,7 +1030,11 @@ void PreferencesWindow::on_autoStartSubsCombo_currentIndexChanged(const QString
void PreferencesWindow::on_autoStartConnCombo_currentIndexChanged(const QString &arg1)
{
LOADINGCHECK
- CurrentConfig.autoStartId = ConnectionManager->GetConnectionIdByDisplayName(arg1).toString();
+ // Fully qualify the connection item.
+ // Will not work when duplicated names are in the same group.
+ CurrentConfig.autoStartId =
+ ConnectionManager->GetConnectionIdByDisplayName(arg1, ConnectionManager->GetGroupIdByDisplayName(autoStartSubsCombo->currentText()))
+ .toString();
}
void PreferencesWindow::on_startWithLoginCB_stateChanged(int arg1)
diff --git a/src/ui/w_SubscriptionManager.cpp b/src/ui/w_SubscriptionManager.cpp
index 20cc75bc..a1277a09 100644
--- a/src/ui/w_SubscriptionManager.cpp
+++ b/src/ui/w_SubscriptionManager.cpp
@@ -15,6 +15,10 @@ SubscribeEditor::SubscribeEditor(QWidget *parent) : QDialog(parent)
{
subscriptionList->addTopLevelItem(new QTreeWidgetItem(QStringList{ ConnectionManager->GetDisplayName(subs), subs.toString() }));
}
+ if (subscriptionList->topLevelItemCount() > 0)
+ {
+ subscriptionList->setCurrentItem(subscriptionList->topLevelItem(0));
+ }
}
QvMessageBusSlotImpl(SubscribeEditor)
diff --git a/src/ui/widgets/ConnectionInfoWidget.cpp b/src/ui/widgets/ConnectionInfoWidget.cpp
index aa4e3400..61245060 100644
--- a/src/ui/widgets/ConnectionInfoWidget.cpp
+++ b/src/ui/widgets/ConnectionInfoWidget.cpp
@@ -14,8 +14,6 @@ ConnectionInfoWidget::ConnectionInfoWidget(QWidget *parent) : QWidget(parent)
editJsonBtn->setIcon(QICON_R("json.png"));
//
shareLinkTxt->setAutoFillBackground(true);
- shareLinkTxt->setStyleSheet("border-bottom: 1px solid gray; border-radius: 0px; padding: 2px; background-color: " +
- this->palette().color(this->backgroundRole()).name(QColor::HexRgb));
shareLinkTxt->setCursor(QCursor(Qt::CursorShape::IBeamCursor));
shareLinkTxt->installEventFilter(this);
//
@@ -25,7 +23,10 @@ ConnectionInfoWidget::ConnectionInfoWidget(QWidget *parent) : QWidget(parent)
void ConnectionInfoWidget::ShowDetails(const tuple &_identifier)
{
- auto [groupId, connectionId] = _identifier;
+ shareLinkTxt->setStyleSheet("border-bottom: 1px solid gray; border-radius: 0px; padding: 2px; background-color: " +
+ this->palette().color(this->backgroundRole()).name(QColor::HexRgb));
+ this->groupId = get<0>(_identifier);
+ this->connectionId = get<1>(_identifier);
bool isConnection = connectionId != NullConnectionId;
//
editBtn->setEnabled(isConnection);
diff --git a/src/ui/widgets/ConnectionInfoWidget.ui b/src/ui/widgets/ConnectionInfoWidget.ui
index bc813740..6b5083f9 100644
--- a/src/ui/widgets/ConnectionInfoWidget.ui
+++ b/src/ui/widgets/ConnectionInfoWidget.ui
@@ -381,9 +381,15 @@
-
+
+ IBeamCursor
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse
+
-
@@ -395,9 +401,15 @@
-
+
+ IBeamCursor
+
+
+ Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse
+
-
diff --git a/src/ui/widgets/ConnectionItemWidget.cpp b/src/ui/widgets/ConnectionItemWidget.cpp
index afaf031b..71b30510 100644
--- a/src/ui/widgets/ConnectionItemWidget.cpp
+++ b/src/ui/widgets/ConnectionItemWidget.cpp
@@ -2,6 +2,8 @@
#include "common/QvHelpers.hpp"
+#include
+
ConnectionItemWidget::ConnectionItemWidget(QWidget *parent) : QWidget(parent), connectionId("null"), groupId("null")
{
setupUi(this);
@@ -16,7 +18,7 @@ ConnectionItemWidget::ConnectionItemWidget(const ConnectionId &id, QWidget *pare
{
connectionId = id;
groupId = ConnectionManager->GetConnectionGroupId(id);
- originalConnectionName = ConnectionManager->GetDisplayName(id);
+ originalItemName = ConnectionManager->GetDisplayName(id);
itemType = NODE_ITEM;
auto latency = ConnectionManager->GetConnectionLatency(id);
@@ -39,7 +41,7 @@ ConnectionItemWidget::ConnectionItemWidget(const ConnectionId &id, QWidget *pare
{
emit RequestWidgetFocus(this);
}
- OnConnectionItemRenamed(id, "", originalConnectionName);
+ OnConnectionItemRenamed(id, "", originalItemName);
connect(ConnectionManager, &QvConnectionHandler::OnConnectionRenamed, this, &ConnectionItemWidget::OnConnectionItemRenamed);
}
@@ -48,7 +50,7 @@ ConnectionItemWidget::ConnectionItemWidget(const GroupId &id, QWidget *parent) :
{
groupId = id;
itemType = GROUP_HEADER_ITEM;
- originalConnectionName = ConnectionManager->GetDisplayName(id);
+ originalItemName = ConnectionManager->GetDisplayName(id);
RecalculateConnectionsCount();
//
layout()->removeWidget(connTypeLabel);
@@ -60,7 +62,7 @@ ConnectionItemWidget::ConnectionItemWidget(const GroupId &id, QWidget *parent) :
font.setBold(true);
connNameLabel->setFont(font);
//
- OnGroupItemRenamed(id, "", originalConnectionName);
+ OnGroupItemRenamed(id, "", originalItemName);
connect(ConnectionManager, &QvConnectionHandler::OnConnectionCreated, this, &ConnectionItemWidget::RecalculateConnectionsCount);
connect(ConnectionManager, &QvConnectionHandler::OnConnectionDeleted, this, &ConnectionItemWidget::RecalculateConnectionsCount);
connect(ConnectionManager, &QvConnectionHandler::OnConnectionChanged, this, &ConnectionItemWidget::RecalculateConnectionsCount);
@@ -86,7 +88,7 @@ void ConnectionItemWidget::OnConnected(const ConnectionId &id)
{
if (id == connectionId)
{
- connNameLabel->setText("• " + originalConnectionName);
+ connNameLabel->setText("• " + originalItemName);
LOG(MODULE_UI, "OnConnected signal received for: " + id.toString())
emit RequestWidgetFocus(this);
}
@@ -96,7 +98,7 @@ void ConnectionItemWidget::OnDisConnected(const ConnectionId &id)
{
if (id == connectionId)
{
- connNameLabel->setText(originalConnectionName);
+ connNameLabel->setText(originalItemName);
}
}
@@ -126,17 +128,37 @@ void ConnectionItemWidget::OnLatencyTestFinished(const ConnectionId &id, const u
if (average == 0)
{
latencyLabel->setText(tr("Error"));
- RED(latencyLabel)
}
else
{
latencyLabel->setText(QSTRN(average) + tr("ms"));
- BLACK(latencyLabel)
}
}
}
+void ConnectionItemWidget::BeginRename()
+{
+ stackedWidget->setCurrentIndex(1);
+ renameTxt->setStyle(QStyleFactory::create("Fusion"));
+ renameTxt->setStyleSheet("background-color: " + this->palette().color(this->backgroundRole()).name(QColor::HexRgb));
+ renameTxt->setText(originalItemName);
+}
+
ConnectionItemWidget::~ConnectionItemWidget()
{
- //
+}
+
+void ConnectionItemWidget::on_doRenameBtn_clicked()
+{
+ if (renameTxt->text().isEmpty())
+ return;
+ if (connectionId == NullConnectionId)
+ {
+ ConnectionManager->RenameGroup(groupId, renameTxt->text());
+ }
+ else
+ {
+ ConnectionManager->RenameConnection(connectionId, renameTxt->text());
+ }
+ stackedWidget->setCurrentIndex(0);
}
diff --git a/src/ui/widgets/ConnectionItemWidget.hpp b/src/ui/widgets/ConnectionItemWidget.hpp
index 63f061f4..5267e82e 100644
--- a/src/ui/widgets/ConnectionItemWidget.hpp
+++ b/src/ui/widgets/ConnectionItemWidget.hpp
@@ -23,6 +23,7 @@ class ConnectionItemWidget
void BeginConnection();
~ConnectionItemWidget();
//
+ void BeginRename();
inline bool NameMatched(const QString &arg)
{
auto searchString = arg.toLower();
@@ -65,13 +66,13 @@ class ConnectionItemWidget
{
if (ConnectionManager->IsConnected(id))
{
- connNameLabel->setText("• " + originalConnectionName);
+ connNameLabel->setText("• " + newName);
}
else
{
connNameLabel->setText(newName);
}
- originalConnectionName = newName;
+ originalItemName = newName;
this->setToolTip(newName);
}
}
@@ -79,14 +80,16 @@ class ConnectionItemWidget
{
if (id == groupId)
{
- originalConnectionName = newName;
+ originalItemName = newName;
connNameLabel->setText(newName);
this->setToolTip(newName);
}
}
+ void on_doRenameBtn_clicked();
+
private:
- QString originalConnectionName;
+ QString originalItemName;
explicit ConnectionItemWidget(QWidget *parent = nullptr);
ITEM_TYPE itemType;
ConnectionId connectionId;
diff --git a/src/ui/widgets/ConnectionItemWidget.ui b/src/ui/widgets/ConnectionItemWidget.ui
index 2acc24d4..51f3a80d 100644
--- a/src/ui/widgets/ConnectionItemWidget.ui
+++ b/src/ui/widgets/ConnectionItemWidget.ui
@@ -6,14 +6,26 @@
0
0
- 277
- 66
+ 203
+ 58
Form
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
-
@@ -31,63 +43,124 @@
-
-
-
- 5
+
+
+ 0
-
-
-
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
-
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
+ 6
+
+
-
+
+
-
+
+
+
+ 11
+
+
+
+ Connection Name
+
+
+
+ -
+
+
+ 500ms
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+ -
+
+
-
+
+
+ Type: vmess + tls + ws
+
+
+
+ -
+
+
+
+ 8
+
+
+
+ 0KB / 0KB
+
+
+ Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
+
+ 0
+
-
-
-
-
- 11
-
-
-
- Connection Name
-
-
+
-
-
+
- 500ms
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
+ OK
-
- -
-
-
-
-
-
- Type: vmess + tls + ws
-
-
-
- -
-
-
-
- 8
-
-
-
- 0KB / 0KB
-
-
- Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter
-
-
-
-
-
-
+
+