update: use model/view for ConnectionList

This commit is contained in:
QxQ 2020-10-01 01:20:33 +08:00
parent 7def1c8854
commit b33c76a556
9 changed files with 414 additions and 361 deletions

View File

@ -68,6 +68,9 @@ set(_QV2RAY_UI_SOURCES
${QV2RAY_QWIDGETS_UI_BASEDIR}/styles/StyleManager.cpp ${QV2RAY_QWIDGETS_UI_BASEDIR}/styles/StyleManager.cpp
${QV2RAY_QWIDGETS_UI_BASEDIR}/styles/StyleManager.cpp ${QV2RAY_QWIDGETS_UI_BASEDIR}/styles/StyleManager.cpp
${QV2RAY_QWIDGETS_UI_BASEDIR}/styles/StyleManager.hpp ${QV2RAY_QWIDGETS_UI_BASEDIR}/styles/StyleManager.hpp
# Models
${QV2RAY_QWIDGETS_UI_BASEDIR}/models/ConnectionModelHelper.cpp
${QV2RAY_QWIDGETS_UI_BASEDIR}/models/ConnectionModelHelper.hpp
# UI Widgets # UI Widgets
${QV2RAY_QWIDGETS_UI_BASEDIR}/widgets/ConnectionInfoWidget.hpp ${QV2RAY_QWIDGETS_UI_BASEDIR}/widgets/ConnectionInfoWidget.hpp
${QV2RAY_QWIDGETS_UI_BASEDIR}/widgets/ConnectionInfoWidget.cpp ${QV2RAY_QWIDGETS_UI_BASEDIR}/widgets/ConnectionInfoWidget.cpp

View File

@ -1 +1 @@
5946 5947

View File

@ -35,12 +35,15 @@
#define VIEWABLE 120 #define VIEWABLE 120
// table of supposed nice steps for grid marks to get nice looking quarters of scale
const static double roundingTable[] = { 1.2, 1.6, 2, 2.4, 2.8, 3.2, 4, 6, 8 };
SpeedWidget::SpeedWidget(QWidget *parent) : QGraphicsView(parent) SpeedWidget::SpeedWidget(QWidget *parent) : QGraphicsView(parent)
{ {
UpdateSpeedPlotSettings(); UpdateSpeedPlotSettings();
} }
void SpeedWidget::AddPointData(QMap<SpeedWidget::GraphID, long> data) void SpeedWidget::AddPointData(QMap<SpeedWidget::GraphType, long> data)
{ {
SpeedWidget::PointData point; SpeedWidget::PointData point;
point.x = QDateTime::currentMSecsSinceEpoch() / 1000; point.x = QDateTime::currentMSecsSinceEpoch() / 1000;
@ -50,11 +53,11 @@ void SpeedWidget::AddPointData(QMap<SpeedWidget::GraphID, long> data)
point.y[id] = data; point.y[id] = data;
} }
m_datahalfMin.push_back(point); dataCollection.push_back(point);
while (m_datahalfMin.length() > VIEWABLE) while (dataCollection.length() > VIEWABLE)
{ {
m_datahalfMin.removeFirst(); dataCollection.removeFirst();
} }
replot(); replot();
} }
@ -93,12 +96,6 @@ int friendlyUnitPrecision(const SizeUnit unit)
default: return 3; default: return 3;
} }
} }
namespace
{
// table of supposed nice steps for grid marks to get nice looking quarters
// of scale
const static double roundingTable[] = { 1.2, 1.6, 2, 2.4, 2.8, 3.2, 4, 6, 8 };
struct SplittedValue struct SplittedValue
{ {
double arg; double arg;
@ -159,7 +156,6 @@ namespace
const int precision = (argValue < 10) ? friendlyUnitPrecision(unit) : 0; const int precision = (argValue < 10) ? friendlyUnitPrecision(unit) : 0;
return QLocale::system().toString(argValue, 'f', precision) + " " + unitString(unit, true); return QLocale::system().toString(argValue, 'f', precision) + " " + unitString(unit, true);
} }
} // namespace
void SpeedWidget::UpdateSpeedPlotSettings() void SpeedWidget::UpdateSpeedPlotSettings()
{ {
@ -168,9 +164,12 @@ void SpeedWidget::UpdateSpeedPlotSettings()
if (!Graph.colorConfig.contains(x)) \ if (!Graph.colorConfig.contains(x)) \
Graph.colorConfig[x] = y; Graph.colorConfig[x] = y;
_X_(API_INBOUND, (QvPair<QvGraphPenConfig>{ { 134, 196, 63, 1.5f, Qt::SolidLine }, { 50, 153, 255, 1.5f, Qt::SolidLine } })); const static QvPair<QvGraphPenConfig> defaultPen{ { 134, 196, 63, 1.5f, Qt::SolidLine }, { 50, 153, 255, 1.5f, Qt::SolidLine } };
const static QvPair<QvGraphPenConfig> directPen{ { 0, 210, 240, 1.5f, Qt::DotLine }, { 235, 220, 42, 1.5f, Qt::DotLine } };
_X_(API_INBOUND, defaultPen);
_X_(API_OUTBOUND_PROXY, Graph.colorConfig[API_INBOUND]); _X_(API_OUTBOUND_PROXY, Graph.colorConfig[API_INBOUND]);
_X_(API_OUTBOUND_DIRECT, (QvPair<QvGraphPenConfig>{ { 0, 210, 240, 1.5f, Qt::DotLine }, { 235, 220, 42, 1.5f, Qt::DotLine } })); _X_(API_OUTBOUND_DIRECT, directPen);
const auto getPen = [](const QvGraphPenConfig &conf) { const auto getPen = [](const QvGraphPenConfig &conf) {
QPen p{ { conf.R, conf.G, conf.B } }; QPen p{ { conf.R, conf.G, conf.B } };
@ -200,7 +199,7 @@ void SpeedWidget::UpdateSpeedPlotSettings()
void SpeedWidget::Clear() void SpeedWidget::Clear()
{ {
m_datahalfMin.clear(); dataCollection.clear();
m_properties.clear(); m_properties.clear();
UpdateSpeedPlotSettings(); UpdateSpeedPlotSettings();
replot(); replot();
@ -215,9 +214,9 @@ quint64 SpeedWidget::maxYValue()
quint64 maxYValue = 0; quint64 maxYValue = 0;
for (int id = 0; id < NB_GRAPHS; ++id) for (int id = 0; id < NB_GRAPHS; ++id)
for (int i = m_datahalfMin.size() - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j) for (int i = dataCollection.size() - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j)
if (m_datahalfMin[i].y[id] > maxYValue) if (dataCollection[i].y[id] > maxYValue)
maxYValue = m_datahalfMin[i].y[id]; maxYValue = dataCollection[i].y[id];
return maxYValue; return maxYValue;
} }
@ -288,10 +287,10 @@ void SpeedWidget::paintEvent(QPaintEvent *)
{ {
QVector<QPoint> points; QVector<QPoint> points;
for (int i = static_cast<int>(m_datahalfMin.size()) - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j) for (int i = static_cast<int>(dataCollection.size()) - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j)
{ {
const int newX = rect.right() - j * xTickSize; const int newX = rect.right() - j * xTickSize;
const int newY = rect.bottom() - m_datahalfMin[i].y[id] * yMultiplier; const int newY = rect.bottom() - dataCollection[i].y[id] * yMultiplier;
points.push_back({ newX, newY }); points.push_back({ newX, newY });
} }

View File

@ -35,7 +35,7 @@ class SpeedWidget : public QGraphicsView
{ {
Q_OBJECT Q_OBJECT
public: public:
enum GraphID enum GraphType
{ {
INBOUND_UP, INBOUND_UP,
INBOUND_DOWN, INBOUND_DOWN,
@ -59,7 +59,7 @@ class SpeedWidget : public QGraphicsView
explicit SpeedWidget(QWidget *parent = nullptr); explicit SpeedWidget(QWidget *parent = nullptr);
void UpdateSpeedPlotSettings(); void UpdateSpeedPlotSettings();
void AddPointData(QMap<SpeedWidget::GraphID, long> data); void AddPointData(QMap<SpeedWidget::GraphType, long> data);
void Clear(); void Clear();
void replot(); void replot();
@ -76,7 +76,7 @@ class SpeedWidget : public QGraphicsView
}; };
quint64 maxYValue(); quint64 maxYValue();
QList<PointData> m_datahalfMin; QList<PointData> dataCollection;
QMap<GraphID, GraphProperties> m_properties; QMap<GraphType, GraphProperties> m_properties;
}; };

View File

@ -0,0 +1,163 @@
#include "ConnectionModelHelper.hpp"
#include "core/handler/ConfigHandler.hpp"
#include "ui/widgets/widgets/ConnectionItemWidget.hpp"
#define NumericString(i) (QString("%1").arg(i, 30, 10, QLatin1Char('0')))
ConnectionListHelper::ConnectionListHelper(QTreeView *view, QObject *parent) : QObject(parent)
{
parentView = view;
model = new QStandardItemModel();
view->setModel(model);
for (const auto &group : ConnectionManager->AllGroups())
{
addGroupItem(group);
for (const auto &connection : ConnectionManager->Connections(group))
{
addConnectionItem({ connection, group });
}
}
const auto renamedLambda = [&](const ConnectionId &id, const QString &, const QString &newName) {
for (const auto &gid : ConnectionManager->GetGroupId(id))
{
ConnectionGroupPair pair{ id, gid };
if (pairs.contains(pair))
pairs[pair]->setData(newName, ROLE_DISPLAYNAME);
}
};
const auto latencyLambda = [&](const ConnectionId &id, const int avg) {
for (const auto &gid : ConnectionManager->GetGroupId(id))
{
ConnectionGroupPair pair{ id, gid };
if (pairs.contains(pair))
pairs[pair]->setData(NumericString(avg), ROLE_LATENCY);
}
};
const auto statsLambda = [&](const ConnectionGroupPair &id, const QMap<StatisticsType, QvStatsSpeedData> &data) {
if (connections.contains(id.connectionId))
{
for (const auto &index : connections[id.connectionId])
index->setData(NumericString(GetConnectionTotalData(id.connectionId)), ROLE_DATA_USAGE);
}
};
connect(ConnectionManager, &QvConfigHandler::OnConnectionRemovedFromGroup, this, &ConnectionListHelper::OnConnectionDeleted);
connect(ConnectionManager, &QvConfigHandler::OnConnectionCreated, this, &ConnectionListHelper::OnConnectionCreated);
connect(ConnectionManager, &QvConfigHandler::OnConnectionLinkedWithGroup, this, &ConnectionListHelper::OnConnectionLinkedWithGroup);
connect(ConnectionManager, &QvConfigHandler::OnGroupCreated, this, &ConnectionListHelper::OnGroupCreated);
connect(ConnectionManager, &QvConfigHandler::OnGroupDeleted, this, &ConnectionListHelper::OnGroupDeleted);
connect(ConnectionManager, &QvConfigHandler::OnConnectionRenamed, renamedLambda);
connect(ConnectionManager, &QvConfigHandler::OnLatencyTestFinished, latencyLambda);
connect(ConnectionManager, &QvConfigHandler::OnStatsAvailable, statsLambda);
}
ConnectionListHelper::~ConnectionListHelper()
{
delete model;
}
void ConnectionListHelper::Sort(ConnectionInfoRole role, Qt::SortOrder order)
{
model->setSortRole(role);
model->sort(0, order);
}
void ConnectionListHelper::Filter(const QString &key)
{
for (const auto &groupId : ConnectionManager->AllGroups())
{
const auto groupItem = model->indexFromItem(groups[groupId]);
bool isTotallyHide = true;
for (const auto &connectionId : ConnectionManager->Connections(groupId))
{
const auto connectionItem = model->indexFromItem(pairs[{ connectionId, groupId }]);
const auto willTotallyHide = static_cast<ConnectionItemWidget *>(parentView->indexWidget(connectionItem))->NameMatched(key);
parentView->setRowHidden(connectionItem.row(), connectionItem.parent(), !willTotallyHide);
isTotallyHide &= willTotallyHide;
}
parentView->indexWidget(groupItem)->setHidden(isTotallyHide);
if (!isTotallyHide)
parentView->expand(groupItem);
}
}
QStandardItem *ConnectionListHelper::addConnectionItem(const ConnectionGroupPair &id)
{
// Create Standard Item
auto connectionItem = new QStandardItem();
connectionItem->setData(GetDisplayName(id.connectionId), ConnectionInfoRole::ROLE_DISPLAYNAME);
connectionItem->setData(NumericString(GetConnectionLatency(id.connectionId)), ConnectionInfoRole::ROLE_LATENCY);
connectionItem->setData(NumericString(GetConnectionTotalData(id.connectionId)), ConnectionInfoRole::ROLE_DATA_USAGE);
//
// Find groups
const auto groupIndex = groups.contains(id.groupId) ? groups[id.groupId] : addGroupItem(id.groupId);
// Append into model
groupIndex->appendRow(connectionItem);
const auto connectionIndex = connectionItem->index();
//
auto widget = new ConnectionItemWidget(id, parentView);
connect(widget, &ConnectionItemWidget::RequestWidgetFocus, [widget, connectionIndex, this]() {
parentView->setCurrentIndex(connectionIndex);
parentView->scrollTo(connectionIndex);
});
//
parentView->setIndexWidget(connectionIndex, widget);
pairs[id] = connectionItem;
connections[id.connectionId].append(connectionItem);
return connectionItem;
}
QStandardItem *ConnectionListHelper::addGroupItem(const GroupId &groupId)
{
// Create Item
const auto item = new QStandardItem();
// Set item into model
model->appendRow(item);
// Get item index
const auto index = item->index();
parentView->setIndexWidget(index, new ConnectionItemWidget(groupId, parentView));
groups[groupId] = item;
return item;
}
void ConnectionListHelper::OnConnectionCreated(const ConnectionGroupPair &id, const QString &)
{
addConnectionItem(id);
}
void ConnectionListHelper::OnConnectionDeleted(const ConnectionGroupPair &id)
{
auto item = pairs.take(id);
const auto index = model->indexFromItem(item);
if (!index.isValid())
return;
model->removeRow(index.row(), index.parent());
connections[id.connectionId].removeAll(item);
}
void ConnectionListHelper::OnConnectionLinkedWithGroup(const ConnectionGroupPair &pairId)
{
addConnectionItem(pairId);
}
void ConnectionListHelper::OnGroupCreated(const GroupId &id, const QString &)
{
addGroupItem(id);
}
void ConnectionListHelper::OnGroupDeleted(const GroupId &id, const QList<ConnectionId> &connections)
{
for (const auto &conn : connections)
{
const ConnectionGroupPair pair{ conn, id };
OnConnectionDeleted(pair);
}
const auto item = groups.take(id);
const auto index = model->indexFromItem(item);
if (!index.isValid())
return;
model->removeRow(index.row(), index.parent());
}

View File

@ -0,0 +1,59 @@
#pragma once
#include "base/Qv2rayBase.hpp"
#include <QStandardItem>
#include <QStandardItemModel>
#include <QTreeView>
namespace Qv2ray::ui::widgets::models
{
enum ConnectionInfoRole
{
// 10 -> Magic value.
ROLE_DISPLAYNAME = Qt::UserRole + 10,
ROLE_LATENCY,
ROLE_IMPORTTIME,
ROLE_LAST_CONNECTED_TIME,
ROLE_DATA_USAGE
};
class ConnectionListHelper : public QObject
{
Q_OBJECT
public:
ConnectionListHelper(QTreeView *parentView, QObject *parent = nullptr);
~ConnectionListHelper();
void Sort(ConnectionInfoRole, Qt::SortOrder);
void Filter(const QString &);
inline QModelIndex GetConnectionPairIndex(const ConnectionGroupPair &id) const
{
return model->indexFromItem(pairs[id]);
}
inline QModelIndex GetGroupIndex(const GroupId &id) const
{
return model->indexFromItem(groups[id]);
}
private:
QStandardItem *addConnectionItem(const ConnectionGroupPair &id);
QStandardItem *addGroupItem(const GroupId &groupId);
void OnGroupCreated(const GroupId &id, const QString &displayName);
void OnGroupDeleted(const GroupId &id, const QList<ConnectionId> &connections);
void OnConnectionCreated(const ConnectionGroupPair &Id, const QString &displayName);
void OnConnectionDeleted(const ConnectionGroupPair &Id);
void OnConnectionLinkedWithGroup(const ConnectionGroupPair &id);
private:
QTreeView *parentView;
QStandardItemModel *model;
//
QHash<GroupId, QStandardItem *> groups;
QHash<ConnectionGroupPair, QStandardItem *> pairs;
QHash<ConnectionId, QList<QStandardItem *>> connections;
};
} // namespace Qv2ray::ui::widgets::models
using namespace Qv2ray::ui::widgets::models;

View File

@ -20,12 +20,13 @@
#include <QScrollBar> #include <QScrollBar>
#define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING #define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING
#define CheckCurrentWidget \ #define CheckCurrentWidget \
auto widget = GetItemWidget(connectionListWidget->currentItem()); \ auto widget = GetIndexWidget(connectionTreeView->currentIndex()); \
if (widget == nullptr) \ if (widget == nullptr) \
return; return;
#define GetItemWidget(item) (qobject_cast<ConnectionItemWidget *>(connectionListWidget->itemWidget(item, 0))) #define GetIndexWidget(item) (qobject_cast<ConnectionItemWidget *>(connectionTreeView->indexWidget(item)))
#define NumericString(i) (QString("%1").arg(i, 30, 10, QLatin1Char('0'))) #define NumericString(i) (QString("%1").arg(i, 30, 10, QLatin1Char('0')))
#define PLUGIN_BUTTON_PROPERTY_KEY "plugin_list_index" #define PLUGIN_BUTTON_PROPERTY_KEY "plugin_list_index"
@ -46,43 +47,9 @@ QvMessageBusSlotImpl(MainWindow)
} }
} }
void MainWindow::MWAddConnectionItem_p(const ConnectionGroupPair &id) void MainWindow::SortConnectionList(ConnectionInfoRole byCol, bool asending)
{ {
if (!groupNodes.contains(id.groupId)) modelHelper->Sort(byCol, asending ? Qt::AscendingOrder : Qt::DescendingOrder);
{
MWAddGroupItem_p(id.groupId);
}
auto groupItem = groupNodes.value(id.groupId);
auto connectionItem = std::make_shared<QTreeWidgetItem>(QStringList{
"", //
GetDisplayName(id.connectionId), //
NumericString(GetConnectionLatency(id.connectionId)), //
"IMPORTTIME_NOT_SUPPORTED", //
"LAST_CONNECTED_NOT_SUPPORTED", //
NumericString(GetConnectionTotalData(id.connectionId)) //
});
connectionNodes.insert(id, connectionItem);
groupItem->addChild(connectionItem.get());
auto widget = new ConnectionItemWidget(id, connectionListWidget);
connect(widget, &ConnectionItemWidget::RequestWidgetFocus, this, &MainWindow::OnConnectionWidgetFocusRequested);
connectionListWidget->setItemWidget(connectionItem.get(), 0, widget);
}
void MainWindow::MWAddGroupItem_p(const GroupId &groupId)
{
auto groupItem = std::make_shared<QTreeWidgetItem>(QStringList{ "", GetDisplayName(groupId) });
groupNodes.insert(groupId, groupItem);
connectionListWidget->addTopLevelItem(groupItem.get());
connectionListWidget->setItemWidget(groupItem.get(), 0, new ConnectionItemWidget(groupId, connectionListWidget));
}
void MainWindow::SortConnectionList(MW_ITEM_COL byCol, bool asending)
{
connectionListWidget->sortByColumn(MW_ITEM_COL_NAME, Qt::AscendingOrder);
for (auto i = 0; i < connectionListWidget->topLevelItemCount(); i++)
{
connectionListWidget->topLevelItem(i)->sortChildren(byCol, asending ? Qt::AscendingOrder : Qt::DescendingOrder);
}
on_locateBtn_clicked(); on_locateBtn_clicked();
} }
@ -108,8 +75,10 @@ void MainWindow::OnRecentConnectionsMenuReadyToShow()
for (const auto &conn : GlobalConfig.uiConfig.recentConnections) for (const auto &conn : GlobalConfig.uiConfig.recentConnections)
{ {
if (ConnectionManager->IsValidId(conn)) if (ConnectionManager->IsValidId(conn))
tray_RecentConnectionsMenu->addAction(GetDisplayName(conn.connectionId) + " (" + GetDisplayName(conn.groupId) + ")", {
[=]() { emit ConnectionManager->StartConnection(conn); }); const auto name = GetDisplayName(conn.connectionId) + " (" + GetDisplayName(conn.groupId) + ")";
tray_RecentConnectionsMenu->addAction(name, [=]() { emit ConnectionManager->StartConnection(conn); });
}
} }
} }
@ -127,6 +96,8 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
speedChartWidget = new SpeedWidget(this); speedChartWidget = new SpeedWidget(this);
speedChart->addWidget(speedChartWidget); speedChart->addWidget(speedChartWidget);
// //
modelHelper = new ConnectionListHelper(connectionTreeView);
//
this->setWindowIcon(QIcon(":/assets/icons/qv2ray.png")); this->setWindowIcon(QIcon(":/assets/icons/qv2ray.png"));
updateColorScheme(); updateColorScheme();
UpdateActionTranslations(); UpdateActionTranslations();
@ -144,34 +115,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
connect(ConnectionManager, &QvConfigHandler::OnStatsAvailable, this, &MainWindow::OnStatsAvailable); connect(ConnectionManager, &QvConfigHandler::OnStatsAvailable, this, &MainWindow::OnStatsAvailable);
connect(ConnectionManager, &QvConfigHandler::OnKernelLogAvailable, this, &MainWindow::OnVCoreLogAvailable); connect(ConnectionManager, &QvConfigHandler::OnKernelLogAvailable, this, &MainWindow::OnVCoreLogAvailable);
// //
connect(ConnectionManager, &QvConfigHandler::OnConnectionRemovedFromGroup, this, &MainWindow::OnConnectionDeleted);
connect(ConnectionManager, &QvConfigHandler::OnConnectionCreated, this, &MainWindow::OnConnectionCreated);
connect(ConnectionManager, &QvConfigHandler::OnConnectionLinkedWithGroup, this, &MainWindow::OnConnectionLinkedWithGroup);
//
connect(ConnectionManager, &QvConfigHandler::OnGroupCreated, this, &MainWindow::OnGroupCreated);
connect(ConnectionManager, &QvConfigHandler::OnGroupDeleted, this, &MainWindow::OnGroupDeleted);
//
connect(ConnectionManager, &QvConfigHandler::OnSubscriptionAsyncUpdateFinished, [](const GroupId &gid) { connect(ConnectionManager, &QvConfigHandler::OnSubscriptionAsyncUpdateFinished, [](const GroupId &gid) {
QvWidgetApplication->ShowTrayMessage(tr("Subscription \"%1\" has been updated").arg(GetDisplayName(gid))); // QvWidgetApplication->ShowTrayMessage(tr("Subscription \"%1\" has been updated").arg(GetDisplayName(gid))); //
}); });
// //
connect(ConnectionManager, &QvConfigHandler::OnConnectionRenamed, [this](const ConnectionId &id, const QString &, const QString &newName) {
for (const auto &gid : ConnectionManager->GetGroupId(id))
{
ConnectionGroupPair pair{ id, gid };
if (connectionNodes.contains(pair))
connectionNodes.value(pair)->setText(MW_ITEM_COL_NAME, newName);
}
});
connect(ConnectionManager, &QvConfigHandler::OnLatencyTestFinished, [this](const ConnectionId &id, const int avg) {
for (const auto &gid : ConnectionManager->GetGroupId(id))
{
ConnectionGroupPair pair{ id, gid };
if (connectionNodes.contains(pair))
connectionNodes.value(pair)->setText(MW_ITEM_COL_PING, NumericString(avg)); //
}
});
//
connect(infoWidget, &ConnectionInfoWidget::OnEditRequested, this, &MainWindow::OnEditRequested); connect(infoWidget, &ConnectionInfoWidget::OnEditRequested, this, &MainWindow::OnEditRequested);
connect(infoWidget, &ConnectionInfoWidget::OnJsonEditRequested, this, &MainWindow::OnEditJsonRequested); connect(infoWidget, &ConnectionInfoWidget::OnJsonEditRequested, this, &MainWindow::OnEditJsonRequested);
// //
@ -209,7 +156,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
// //
connect(tray_action_ToggleVisibility, &QAction::triggered, this, &MainWindow::MWToggleVisibility); connect(tray_action_ToggleVisibility, &QAction::triggered, this, &MainWindow::MWToggleVisibility);
connect(tray_action_Preferences, &QAction::triggered, this, &MainWindow::on_preferencesBtn_clicked); connect(tray_action_Preferences, &QAction::triggered, this, &MainWindow::on_preferencesBtn_clicked);
connect(tray_action_Start, &QAction::triggered, [this] { ConnectionManager->StartConnection(lastConnectedIdentifier); }); connect(tray_action_Start, &QAction::triggered, [this] { ConnectionManager->StartConnection(lastConnected); });
connect(tray_action_Stop, &QAction::triggered, ConnectionManager, &QvConfigHandler::StopConnection); connect(tray_action_Stop, &QAction::triggered, ConnectionManager, &QvConfigHandler::StopConnection);
connect(tray_action_Restart, &QAction::triggered, ConnectionManager, &QvConfigHandler::RestartConnection); connect(tray_action_Restart, &QAction::triggered, ConnectionManager, &QvConfigHandler::RestartConnection);
connect(tray_action_Quit, &QAction::triggered, this, &MainWindow::Action_Exit); connect(tray_action_Quit, &QAction::triggered, this, &MainWindow::Action_Exit);
@ -300,39 +247,38 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
sortMenu->addAction(sortAction_SortByPing_Asc); sortMenu->addAction(sortAction_SortByPing_Asc);
sortMenu->addAction(sortAction_SortByPing_Dsc); sortMenu->addAction(sortAction_SortByPing_Dsc);
// //
connect(sortAction_SortByName_Asc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_NAME, true); }); connect(sortAction_SortByName_Asc, &QAction::triggered, [this] { SortConnectionList(ROLE_DISPLAYNAME, true); });
connect(sortAction_SortByName_Dsc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_NAME, false); }); connect(sortAction_SortByName_Dsc, &QAction::triggered, [this] { SortConnectionList(ROLE_DISPLAYNAME, false); });
connect(sortAction_SortByData_Asc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_DATA, true); }); connect(sortAction_SortByData_Asc, &QAction::triggered, [this] { SortConnectionList(ROLE_DATA_USAGE, true); });
connect(sortAction_SortByData_Dsc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_DATA, false); }); connect(sortAction_SortByData_Dsc, &QAction::triggered, [this] { SortConnectionList(ROLE_DATA_USAGE, false); });
connect(sortAction_SortByPing_Asc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_PING, true); }); connect(sortAction_SortByPing_Asc, &QAction::triggered, [this] { SortConnectionList(ROLE_LATENCY, true); });
connect(sortAction_SortByPing_Dsc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_PING, false); }); connect(sortAction_SortByPing_Dsc, &QAction::triggered, [this] { SortConnectionList(ROLE_LATENCY, false); });
// //
sortBtn->setMenu(sortMenu); sortBtn->setMenu(sortMenu);
// //
graphWidgetMenu->addAction(action_RCM_CopyGraph); graphWidgetMenu->addAction(action_RCM_CopyGraph);
connect(action_RCM_CopyGraph, &QAction::triggered, this, &MainWindow::Action_CopyGraphAsImage); connect(action_RCM_CopyGraph, &QAction::triggered, this, &MainWindow::Action_CopyGraphAsImage);
// //
LOG(MODULE_UI, "Loading data...")
for (const auto &group : ConnectionManager->AllGroups())
{
MWAddGroupItem_p(group);
for (const auto &connection : ConnectionManager->Connections(group)) MWAddConnectionItem_p({ connection, group });
}
//
// Find and start if there is an auto-connection // Find and start if there is an auto-connection
const auto connectionStarted = StartAutoConnectionEntry(); const auto connectionStarted = StartAutoConnectionEntry();
if (!connectionStarted && connectionListWidget->topLevelItemCount() > 0)
if (!connectionStarted && !ConnectionManager->Connections().isEmpty())
{ {
ReloadRecentConnectionList();
// Select the first connection. // Select the first connection.
const auto &topLevelItem = connectionListWidget->topLevelItem(0); const auto groups = ConnectionManager->AllGroups();
const auto &item = (topLevelItem->childCount() > 0) ? topLevelItem->child(0) : topLevelItem; if (!groups.isEmpty())
connectionListWidget->setCurrentItem(item); {
on_connectionListWidget_itemClicked(item, 0); const auto connections = ConnectionManager->Connections(groups.first());
if (!connections.empty())
{
const auto index = modelHelper->GetConnectionPairIndex({ connections.first(), groups.first() });
on_connectionTreeView_clicked(index);
} }
}
}
ReloadRecentConnectionList();
// //
// //
tray_action_ToggleVisibility->setText(!connectionStarted ? tr("Hide") : tr("Show"));
if (!connectionStarted) if (!connectionStarted)
MWShowWindow(); MWShowWindow();
else else
@ -423,7 +369,7 @@ void MainWindow::timerEvent(QTimerEvent *event)
void MainWindow::keyPressEvent(QKeyEvent *e) void MainWindow::keyPressEvent(QKeyEvent *e)
{ {
if (focusWidget() == connectionListWidget) if (focusWidget() == connectionTreeView)
{ {
CheckCurrentWidget; CheckCurrentWidget;
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return) if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)
@ -435,7 +381,7 @@ void MainWindow::keyPressEvent(QKeyEvent *e)
} }
else else
{ {
connectionListWidget->expandItem(connectionListWidget->currentItem()); connectionTreeView->expand(connectionTreeView->currentIndex());
} }
} }
else if (e->key() == Qt::Key_F2) else if (e->key() == Qt::Key_F2)
@ -450,7 +396,7 @@ void MainWindow::keyPressEvent(QKeyEvent *e)
if (e->key() == Qt::Key_Escape) if (e->key() == Qt::Key_Escape)
{ {
auto widget = GetItemWidget(connectionListWidget->currentItem()); auto widget = GetIndexWidget(connectionTreeView->currentIndex());
// Check if this key was accpted by the ConnectionItemWidget // Check if this key was accpted by the ConnectionItemWidget
if (widget && widget->IsRenaming()) if (widget && widget->IsRenaming())
{ {
@ -481,10 +427,10 @@ void MainWindow::keyReleaseEvent(QKeyEvent *e)
// Workaround of QtWidget not grabbing KeyDown and KeyUp in keyPressEvent // Workaround of QtWidget not grabbing KeyDown and KeyUp in keyPressEvent
if (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down) if (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)
{ {
if (focusWidget() == connectionListWidget) if (focusWidget() == connectionTreeView)
{ {
CheckCurrentWidget; CheckCurrentWidget;
on_connectionListWidget_itemClicked(connectionListWidget->currentItem(), 0); on_connectionTreeView_clicked(connectionTreeView->currentIndex());
} }
} }
} }
@ -500,6 +446,7 @@ void MainWindow::Action_Start()
MainWindow::~MainWindow() MainWindow::~MainWindow()
{ {
delete modelHelper;
for (auto &widget : pluginWidgets) widget->accept(); for (auto &widget : pluginWidgets) widget->accept();
} }
@ -534,14 +481,14 @@ void MainWindow::on_clearlogButton_clicked()
{ {
masterLogBrowser->document()->clear(); masterLogBrowser->document()->clear();
} }
void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint &pos) void MainWindow::on_connectionTreeView_customContextMenuRequested(const QPoint &pos)
{ {
Q_UNUSED(pos) Q_UNUSED(pos)
auto _pos = QCursor::pos(); auto _pos = QCursor::pos();
auto item = connectionListWidget->itemAt(connectionListWidget->mapFromGlobal(_pos)); auto item = connectionTreeView->indexAt(connectionTreeView->mapFromGlobal(_pos));
if (item != nullptr) if (item.isValid())
{ {
bool isConnection = GetItemWidget(item)->IsConnection(); bool isConnection = GetIndexWidget(item)->IsConnection();
// Disable connection-specific settings. // Disable connection-specific settings.
action_RCM_Start->setEnabled(isConnection); action_RCM_Start->setEnabled(isConnection);
action_RCM_SetAutoConnection->setEnabled(isConnection); action_RCM_SetAutoConnection->setEnabled(isConnection);
@ -551,7 +498,7 @@ void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint
action_RCM_RenameConnection->setEnabled(isConnection); action_RCM_RenameConnection->setEnabled(isConnection);
action_RCM_DuplicateConnection->setEnabled(isConnection); action_RCM_DuplicateConnection->setEnabled(isConnection);
action_RCM_UpdateSubscription->setEnabled(!isConnection); action_RCM_UpdateSubscription->setEnabled(!isConnection);
action_RCM_RealLatencyTest->setEnabled(isConnection && ConnectionManager->IsConnected(GetItemWidget(item)->Identifier())); action_RCM_RealLatencyTest->setEnabled(isConnection && ConnectionManager->IsConnected(GetIndexWidget(item)->Identifier()));
connectionListRCM_Menu->popup(_pos); connectionListRCM_Menu->popup(_pos);
} }
} }
@ -560,9 +507,9 @@ void MainWindow::Action_DeleteConnections()
{ {
QList<ConnectionGroupPair> connlist; QList<ConnectionGroupPair> connlist;
for (const auto &item : connectionListWidget->selectedItems()) for (const auto &item : connectionTreeView->selectionModel()->selectedIndexes())
{ {
auto widget = GetItemWidget(item); auto widget = GetIndexWidget(item);
if (widget) if (widget)
{ {
const auto identifier = widget->Identifier(); const auto identifier = widget->Identifier();
@ -640,18 +587,6 @@ void MainWindow::on_subsButton_clicked()
GroupManager().exec(); GroupManager().exec();
} }
void MainWindow::on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column)
{
Q_UNUSED(column)
auto widget = GetItemWidget(item);
if (widget == nullptr)
return;
if (widget->IsConnection())
{
widget->BeginConnection();
}
}
void MainWindow::OnDisconnected(const ConnectionGroupPair &id) void MainWindow::OnDisconnected(const ConnectionGroupPair &id)
{ {
Q_UNUSED(id) Q_UNUSED(id)
@ -660,7 +595,7 @@ void MainWindow::OnDisconnected(const ConnectionGroupPair &id)
tray_action_Stop->setEnabled(false); tray_action_Stop->setEnabled(false);
tray_action_Restart->setEnabled(false); tray_action_Restart->setEnabled(false);
tray_SystemProxyMenu->setEnabled(false); tray_SystemProxyMenu->setEnabled(false);
lastConnectedIdentifier = id; lastConnected = id;
locateBtn->setEnabled(false); locateBtn->setEnabled(false);
if (!GlobalConfig.uiConfig.quietMode) if (!GlobalConfig.uiConfig.quietMode)
{ {
@ -684,7 +619,7 @@ void MainWindow::OnConnected(const ConnectionGroupPair &id)
tray_action_Stop->setEnabled(true); tray_action_Stop->setEnabled(true);
tray_action_Restart->setEnabled(true); tray_action_Restart->setEnabled(true);
tray_SystemProxyMenu->setEnabled(true); tray_SystemProxyMenu->setEnabled(true);
lastConnectedIdentifier = id; lastConnected = id;
locateBtn->setEnabled(true); locateBtn->setEnabled(true);
on_clearlogButton_clicked(); on_clearlogButton_clicked();
speedChartWidget->Clear(); speedChartWidget->Clear();
@ -710,68 +645,9 @@ void MainWindow::OnConnected(const ConnectionGroupPair &id)
} }
} }
void MainWindow::OnConnectionWidgetFocusRequested(const ConnectionItemWidget *_widget)
{
if (_widget == nullptr)
{
return;
}
for (auto _item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard | Qt::MatchRecursive))
{
if (GetItemWidget(_item_) == _widget)
{
LOG(MODULE_UI, "Setting current item.")
connectionListWidget->setCurrentItem(_item_);
connectionListWidget->scrollToItem(_item_);
// Click it to show details.
on_connectionListWidget_itemClicked(_item_, 0);
}
}
}
void MainWindow::on_connectionFilterTxt_textEdited(const QString &arg1) void MainWindow::on_connectionFilterTxt_textEdited(const QString &arg1)
{ {
// No recursive since we only need top level item modelHelper->Filter(arg1);
for (auto _top_item_ : connectionListWidget->findItems(QString("*"), Qt::MatchWrap | Qt::MatchWildcard))
{
// auto topWidget = GetItemWidget(_top_item_);
bool isTotallyHide = true;
for (auto i = 0; i < _top_item_->childCount(); i++)
{
auto _child_ = _top_item_->child(i);
if (GetItemWidget(_child_)->NameMatched(arg1))
{
LOG(MODULE_UI, "Setting current item.")
// Show the child
_child_->setHidden(false);
// If any one of the children matches, the parent should not be hidden.
isTotallyHide = false;
}
else
{
_child_->setHidden(true);
}
}
_top_item_->setHidden(isTotallyHide);
if (!isTotallyHide)
{
connectionListWidget->expandItem(_top_item_);
}
}
}
void MainWindow::on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column)
{
Q_UNUSED(column)
auto widget = GetItemWidget(item);
if (widget == nullptr)
return;
infoWidget->ShowDetails(widget->Identifier());
} }
void MainWindow::OnStatsAvailable(const ConnectionGroupPair &id, const QMap<StatisticsType, QvStatsSpeedData> &data) void MainWindow::OnStatsAvailable(const ConnectionGroupPair &id, const QMap<StatisticsType, QvStatsSpeedData> &data)
@ -781,13 +657,13 @@ void MainWindow::OnStatsAvailable(const ConnectionGroupPair &id, const QMap<Stat
// This may not be, or may not precisely be, speed per second if the backend // This may not be, or may not precisely be, speed per second if the backend
// has "any" latency. (Hope not...) // has "any" latency. (Hope not...)
// //
QMap<SpeedWidget::GraphID, long> pointData; QMap<SpeedWidget::GraphType, long> pointData;
bool isOutbound = GlobalConfig.uiConfig.graphConfig.useOutboundStats; bool isOutbound = GlobalConfig.uiConfig.graphConfig.useOutboundStats;
bool hasDirect = isOutbound && GlobalConfig.uiConfig.graphConfig.hasDirectStats; bool hasDirect = isOutbound && GlobalConfig.uiConfig.graphConfig.hasDirectStats;
for (const auto &type : data.keys()) for (const auto &[type, data] : data.toStdMap())
{ {
const auto upSpeed = data[type].first.first; const auto upSpeed = data.first.first;
const auto downSpeed = data[type].first.second; const auto downSpeed = data.first.second;
switch (type) switch (type)
{ {
case API_INBOUND: case API_INBOUND:
@ -829,12 +705,6 @@ void MainWindow::OnStatsAvailable(const ConnectionGroupPair &id, const QMap<Stat
// //
qvAppTrayIcon->setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE + tr("Connected: ") + GetDisplayName(id.connectionId) + // qvAppTrayIcon->setToolTip(TRAY_TOOLTIP_PREFIX NEWLINE + tr("Connected: ") + GetDisplayName(id.connectionId) + //
NEWLINE "Up: " + totalSpeedUp + " Down: " + totalSpeedDown); NEWLINE "Up: " + totalSpeedUp + " Down: " + totalSpeedDown);
//
// Set data accordingly
if (connectionNodes.contains(id))
{
connectionNodes.value(id)->setText(MW_ITEM_COL_DATA, NumericString(GetConnectionTotalData(id.connectionId)));
}
} }
void MainWindow::OnVCoreLogAvailable(const ConnectionGroupPair &id, const QString &log) void MainWindow::OnVCoreLogAvailable(const ConnectionGroupPair &id, const QString &log)
@ -903,34 +773,6 @@ void MainWindow::OnEditJsonRequested(const ConnectionId &id)
} }
} }
void MainWindow::OnConnectionCreated(const ConnectionGroupPair &id, const QString &displayName)
{
Q_UNUSED(displayName)
MWAddConnectionItem_p(id);
}
void MainWindow::OnConnectionDeleted(const ConnectionGroupPair &id)
{
auto child = connectionNodes.take(id);
groupNodes.value(id.groupId)->removeChild(child.get());
}
void MainWindow::OnConnectionLinkedWithGroup(const ConnectionGroupPair &pairId)
{
MWAddConnectionItem_p(pairId);
}
void MainWindow::OnGroupCreated(const GroupId &id, const QString &displayName)
{
Q_UNUSED(displayName)
MWAddGroupItem_p(id);
}
void MainWindow::OnGroupDeleted(const GroupId &id, const QList<ConnectionId> &connections)
{
for (const auto &conn : connections)
{
groupNodes.value(id)->removeChild(connectionNodes.value({ conn, id }).get());
}
groupNodes.remove(id);
}
void MainWindow::OnLogScrollbarValueChanged(int value) void MainWindow::OnLogScrollbarValueChanged(int value)
{ {
if (masterLogBrowser->verticalScrollBar()->maximum() == value) if (masterLogBrowser->verticalScrollBar()->maximum() == value)
@ -944,9 +786,10 @@ void MainWindow::on_locateBtn_clicked()
auto id = KernelInstance->CurrentConnection(); auto id = KernelInstance->CurrentConnection();
if (!id.isEmpty()) if (!id.isEmpty())
{ {
connectionListWidget->setCurrentItem(connectionNodes.value(id).get()); const auto index = modelHelper->GetConnectionPairIndex(id);
connectionListWidget->scrollToItem(connectionNodes.value(id).get()); connectionTreeView->setCurrentIndex(index);
on_connectionListWidget_itemClicked(connectionNodes.value(id).get(), 0); connectionTreeView->scrollTo(index);
on_connectionTreeView_clicked(index);
} }
} }
@ -960,9 +803,9 @@ void MainWindow::Action_DuplicateConnection()
{ {
QList<ConnectionGroupPair> connlist; QList<ConnectionGroupPair> connlist;
for (const auto &item : connectionListWidget->selectedItems()) for (const auto &item : connectionTreeView->selectionModel()->selectedIndexes())
{ {
auto widget = GetItemWidget(item); auto widget = GetIndexWidget(item);
if (widget->IsConnection()) if (widget->IsConnection())
{ {
connlist.append(widget->Identifier()); connlist.append(widget->Identifier());
@ -1012,14 +855,14 @@ void MainWindow::on_clearChartBtn_clicked()
speedChartWidget->Clear(); speedChartWidget->Clear();
} }
void MainWindow::on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) // void MainWindow::on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
{ //{
Q_UNUSED(previous) // Q_UNUSED(previous)
if (current != nullptr && !isExiting) // if (current != nullptr && !isExiting)
{ // {
on_connectionListWidget_itemClicked(current, 0); // on_connectionListWidget_itemClicked(current, 0);
} // }
} //}
void MainWindow::on_masterLogBrowser_textChanged() void MainWindow::on_masterLogBrowser_textChanged()
{ {
@ -1031,10 +874,10 @@ void MainWindow::on_masterLogBrowser_textChanged()
void MainWindow::Action_SetAutoConnection() void MainWindow::Action_SetAutoConnection()
{ {
auto current = connectionListWidget->currentItem(); auto current = connectionTreeView->currentIndex();
if (current != nullptr) if (current.isValid())
{ {
auto widget = GetItemWidget(current); auto widget = GetIndexWidget(current);
const auto identifier = widget->Identifier(); const auto identifier = widget->Identifier();
GlobalConfig.autoStartId = identifier; GlobalConfig.autoStartId = identifier;
GlobalConfig.autoStartBehavior = AUTO_CONNECTION_FIXED; GlobalConfig.autoStartBehavior = AUTO_CONNECTION_FIXED;
@ -1048,10 +891,10 @@ void MainWindow::Action_SetAutoConnection()
void MainWindow::Action_ResetStats() void MainWindow::Action_ResetStats()
{ {
auto current = connectionListWidget->currentItem(); auto current = connectionTreeView->currentIndex();
if (current != nullptr) if (current.isValid())
{ {
auto widget = GetItemWidget(current); auto widget = GetIndexWidget(current);
if (widget) if (widget)
{ {
if (widget->IsConnection()) if (widget->IsConnection())
@ -1064,10 +907,10 @@ void MainWindow::Action_ResetStats()
void MainWindow::Action_UpdateSubscription() void MainWindow::Action_UpdateSubscription()
{ {
auto current = connectionListWidget->currentItem(); auto current = connectionTreeView->currentIndex();
if (current != nullptr) if (current.isValid())
{ {
auto widget = GetItemWidget(current); auto widget = GetIndexWidget(current);
if (widget) if (widget)
{ {
if (widget->IsConnection()) if (widget->IsConnection())
@ -1083,11 +926,11 @@ void MainWindow::Action_UpdateSubscription()
void MainWindow::Action_TestLatency() void MainWindow::Action_TestLatency()
{ {
for (const auto &current : connectionListWidget->selectedItems()) for (const auto &current : connectionTreeView->selectionModel()->selectedIndexes())
{ {
if (!current) if (!current.isValid())
continue; continue;
const auto widget = GetItemWidget(current); const auto widget = GetIndexWidget(current);
if (!widget) if (!widget)
continue; continue;
if (widget->IsConnection()) if (widget->IsConnection())
@ -1099,11 +942,11 @@ void MainWindow::Action_TestLatency()
void MainWindow::Action_TestRealLatency() void MainWindow::Action_TestRealLatency()
{ {
for (const auto &current : connectionListWidget->selectedItems()) for (const auto &current : connectionTreeView->selectionModel()->selectedIndexes())
{ {
if (!current) if (!current.isValid())
continue; continue;
const auto widget = GetItemWidget(current); const auto widget = GetIndexWidget(current);
if (!widget) if (!widget)
continue; continue;
if (widget->IsConnection()) if (widget->IsConnection())
@ -1134,8 +977,8 @@ void MainWindow::on_newConnectionBtn_clicked()
outboundsList.push_back(outboundEntry); outboundsList.push_back(outboundEntry);
CONFIGROOT root; CONFIGROOT root;
root.insert("outbounds", outboundsList); root.insert("outbounds", outboundsList);
const auto item = connectionListWidget->currentItem(); const auto item = connectionTreeView->currentIndex();
const auto id = item ? DefaultGroupId : GetItemWidget(item)->Identifier().groupId; const auto id = item.isValid() ? DefaultGroupId : GetIndexWidget(item)->Identifier().groupId;
ConnectionManager->CreateConnection(root, alias, id); ConnectionManager->CreateConnection(root, alias, id);
} }
} }
@ -1147,15 +990,15 @@ void MainWindow::on_newComplexConnectionBtn_clicked()
bool isChanged = w.result() == QDialog::Accepted; bool isChanged = w.result() == QDialog::Accepted;
if (isChanged) if (isChanged)
{ {
const auto item = connectionListWidget->currentItem(); const auto item = connectionTreeView->currentIndex();
const auto id = item ? DefaultGroupId : GetItemWidget(item)->Identifier().groupId; const auto id = item.isValid() ? DefaultGroupId : GetIndexWidget(item)->Identifier().groupId;
ConnectionManager->CreateConnection(root, QJsonIO::GetValue(root, "outbounds", 0, "tag").toString(), id); ConnectionManager->CreateConnection(root, QJsonIO::GetValue(root, "outbounds", 0, "tag").toString(), id);
} }
} }
void MainWindow::on_collapseGroupsBtn_clicked() void MainWindow::on_collapseGroupsBtn_clicked()
{ {
connectionListWidget->collapseAll(); connectionTreeView->collapseAll();
} }
void MainWindow::Action_CopyRecentLogs() void MainWindow::Action_CopyRecentLogs()
@ -1174,3 +1017,20 @@ void MainWindow::Action_CopyRecentLogs()
} }
qApp->clipboard()->setText(result.join(NEWLINE)); qApp->clipboard()->setText(result.join(NEWLINE));
} }
void MainWindow::on_connectionTreeView_doubleClicked(const QModelIndex &index)
{
auto widget = GetIndexWidget(index);
if (widget == nullptr)
return;
if (widget->IsConnection())
widget->BeginConnection();
}
void MainWindow::on_connectionTreeView_clicked(const QModelIndex &index)
{
auto widget = GetIndexWidget(index);
if (widget == nullptr)
return;
infoWidget->ShowDetails(widget->Identifier());
}

View File

@ -3,6 +3,7 @@
#include "ui/common/QvMessageBus.hpp" #include "ui/common/QvMessageBus.hpp"
#include "ui/common/speedchart/speedwidget.hpp" #include "ui/common/speedchart/speedwidget.hpp"
#include "ui/widgets/common/WidgetUIBase.hpp" #include "ui/widgets/common/WidgetUIBase.hpp"
#include "ui/widgets/models/ConnectionModelHelper.hpp"
#include "ui/widgets/widgets/ConnectionInfoWidget.hpp" #include "ui/widgets/widgets/ConnectionInfoWidget.hpp"
#include "ui/widgets/widgets/ConnectionItemWidget.hpp" #include "ui/widgets/widgets/ConnectionItemWidget.hpp"
#include "ui_w_MainWindow.h" #include "ui_w_MainWindow.h"
@ -17,15 +18,6 @@ namespace Qv2rayPlugin
class QvPluginMainWindowWidget; class QvPluginMainWindowWidget;
} }
enum MW_ITEM_COL
{
MW_ITEM_COL_NAME = 1,
MW_ITEM_COL_PING = 2,
MW_ITEM_COL_IMPORTTIME = 3,
MW_ITEM_COL_LASTCONNETED = 4,
MW_ITEM_COL_DATA = 5
};
class MainWindow class MainWindow
: public QMainWindow : public QMainWindow
, Ui::MainWindow , Ui::MainWindow
@ -47,25 +39,29 @@ class MainWindow
void on_activatedTray(QSystemTrayIcon::ActivationReason reason); void on_activatedTray(QSystemTrayIcon::ActivationReason reason);
void on_preferencesBtn_clicked(); void on_preferencesBtn_clicked();
void on_clearlogButton_clicked(); void on_clearlogButton_clicked();
void on_connectionListWidget_customContextMenuRequested(const QPoint &pos); void on_connectionTreeView_customContextMenuRequested(const QPoint &pos);
void on_importConfigButton_clicked(); void on_importConfigButton_clicked();
void on_subsButton_clicked(); void on_subsButton_clicked();
// //
void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
void on_connectionFilterTxt_textEdited(const QString &arg1); void on_connectionFilterTxt_textEdited(const QString &arg1);
void on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column);
void on_locateBtn_clicked(); void on_locateBtn_clicked();
// //
void on_chartVisibilityBtn_clicked(); void on_chartVisibilityBtn_clicked();
void on_logVisibilityBtn_clicked(); void on_logVisibilityBtn_clicked();
void on_clearChartBtn_clicked(); void on_clearChartBtn_clicked();
void on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void on_masterLogBrowser_textChanged(); void on_masterLogBrowser_textChanged();
// //
void on_pluginsBtn_clicked(); void on_pluginsBtn_clicked();
void on_collapseGroupsBtn_clicked(); void on_collapseGroupsBtn_clicked();
void on_newConnectionBtn_clicked(); void on_newConnectionBtn_clicked();
void on_newComplexConnectionBtn_clicked(); void on_newComplexConnectionBtn_clicked();
//
// void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
// void on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column);
// void on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
void on_connectionTreeView_doubleClicked(const QModelIndex &index);
void on_connectionTreeView_clicked(const QModelIndex &index);
private: private:
// Do not declare as slots, we connect them manually. // Do not declare as slots, we connect them manually.
@ -86,8 +82,6 @@ class MainWindow
void Action_CopyGraphAsImage(); void Action_CopyGraphAsImage();
void Action_CopyRecentLogs(); void Action_CopyRecentLogs();
void OnConnectionWidgetFocusRequested(const ConnectionItemWidget *widget);
private: private:
void MWToggleVisibility(); void MWToggleVisibility();
void OnEditRequested(const ConnectionId &id); void OnEditRequested(const ConnectionId &id);
@ -98,14 +92,7 @@ class MainWindow
void OnStatsAvailable(const ConnectionGroupPair &id, const QMap<StatisticsType, QvStatsSpeedData> &data); void OnStatsAvailable(const ConnectionGroupPair &id, const QMap<StatisticsType, QvStatsSpeedData> &data);
void OnVCoreLogAvailable(const ConnectionGroupPair &id, const QString &log); void OnVCoreLogAvailable(const ConnectionGroupPair &id, const QString &log);
// //
void OnConnectionCreated(const ConnectionGroupPair &Id, const QString &displayName); void SortConnectionList(ConnectionInfoRole byCol, bool asending);
void OnConnectionDeleted(const ConnectionGroupPair &Id);
void OnConnectionLinkedWithGroup(const ConnectionGroupPair &id);
//
void OnGroupCreated(const GroupId &id, const QString &displayName);
void OnGroupDeleted(const GroupId &id, const QList<ConnectionId> &connections);
//
void SortConnectionList(MW_ITEM_COL byCol, bool asending);
// //
void ReloadRecentConnectionList(); void ReloadRecentConnectionList();
void OnRecentConnectionsMenuReadyToShow(); void OnRecentConnectionsMenuReadyToShow();
@ -122,8 +109,6 @@ class MainWindow
void closeEvent(QCloseEvent *) override; void closeEvent(QCloseEvent *) override;
private: private:
QHash<GroupId, std::shared_ptr<QTreeWidgetItem>> groupNodes;
QHash<ConnectionGroupPair, std::shared_ptr<QTreeWidgetItem>> connectionNodes;
// Charts // Charts
SpeedWidget *speedChartWidget; SpeedWidget *speedChartWidget;
SyntaxHighlighter *vCoreLogHighlighter; SyntaxHighlighter *vCoreLogHighlighter;
@ -179,7 +164,7 @@ class MainWindow
int qvLogTimerId = -1; int qvLogTimerId = -1;
bool qvLogAutoScoll = true; bool qvLogAutoScoll = true;
// //
ConnectionGroupPair lastConnectedIdentifier; ConnectionGroupPair lastConnected;
void MWSetSystemProxy(); void MWSetSystemProxy();
void MWClearSystemProxy(); void MWClearSystemProxy();
void MWShowWindow(); void MWShowWindow();
@ -189,8 +174,7 @@ class MainWindow
// //
void updateColorScheme(); void updateColorScheme();
// //
void MWAddConnectionItem_p(const ConnectionGroupPair &id);
void MWAddGroupItem_p(const GroupId &groupId);
//
QList<Qv2rayPlugin::QvPluginMainWindowWidget *> pluginWidgets; QList<Qv2rayPlugin::QvPluginMainWindowWidget *> pluginWidgets;
//
Qv2ray::ui::widgets::models::ConnectionListHelper *modelHelper;
}; };

View File

@ -135,7 +135,7 @@
</layout> </layout>
</item> </item>
<item> <item>
<widget class="QTreeWidget" name="connectionListWidget"> <widget class="QTreeView" name="connectionTreeView">
<property name="contextMenuPolicy"> <property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum> <enum>Qt::CustomContextMenu</enum>
</property> </property>
@ -154,26 +154,12 @@
<property name="sortingEnabled"> <property name="sortingEnabled">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="animated">
<bool>true</bool>
</property>
<property name="allColumnsShowFocus"> <property name="allColumnsShowFocus">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="headerHidden"> <property name="headerHidden">
<bool>true</bool> <bool>true</bool>
</property> </property>
<property name="expandsOnDoubleClick">
<bool>true</bool>
</property>
<attribute name="headerShowSortIndicator" stdset="0">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
</widget> </widget>
</item> </item>
<item> <item>
@ -568,7 +554,6 @@
</widget> </widget>
<layoutdefault spacing="6" margin="11"/> <layoutdefault spacing="6" margin="11"/>
<tabstops> <tabstops>
<tabstop>connectionListWidget</tabstop>
<tabstop>importConfigButton</tabstop> <tabstop>importConfigButton</tabstop>
</tabstops> </tabstops>
<resources> <resources>