mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-20 02:40:20 +08:00
update: use model/view for ConnectionList
This commit is contained in:
parent
7def1c8854
commit
b33c76a556
@ -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.hpp
|
||||
# Models
|
||||
${QV2RAY_QWIDGETS_UI_BASEDIR}/models/ConnectionModelHelper.cpp
|
||||
${QV2RAY_QWIDGETS_UI_BASEDIR}/models/ConnectionModelHelper.hpp
|
||||
# UI Widgets
|
||||
${QV2RAY_QWIDGETS_UI_BASEDIR}/widgets/ConnectionInfoWidget.hpp
|
||||
${QV2RAY_QWIDGETS_UI_BASEDIR}/widgets/ConnectionInfoWidget.cpp
|
||||
|
@ -1 +1 @@
|
||||
5946
|
||||
5947
|
||||
|
@ -35,12 +35,15 @@
|
||||
|
||||
#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)
|
||||
{
|
||||
UpdateSpeedPlotSettings();
|
||||
}
|
||||
|
||||
void SpeedWidget::AddPointData(QMap<SpeedWidget::GraphID, long> data)
|
||||
void SpeedWidget::AddPointData(QMap<SpeedWidget::GraphType, long> data)
|
||||
{
|
||||
SpeedWidget::PointData point;
|
||||
point.x = QDateTime::currentMSecsSinceEpoch() / 1000;
|
||||
@ -50,11 +53,11 @@ void SpeedWidget::AddPointData(QMap<SpeedWidget::GraphID, long> 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();
|
||||
}
|
||||
@ -93,73 +96,66 @@ int friendlyUnitPrecision(const SizeUnit unit)
|
||||
default: return 3;
|
||||
}
|
||||
}
|
||||
|
||||
namespace
|
||||
struct SplittedValue
|
||||
{
|
||||
// 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
|
||||
double arg;
|
||||
SizeUnit unit;
|
||||
qint64 sizeInBytes() const
|
||||
{
|
||||
double arg;
|
||||
SizeUnit unit;
|
||||
qint64 sizeInBytes() const
|
||||
auto size = arg;
|
||||
for (int i = 0; i < static_cast<int>(unit); ++i)
|
||||
{
|
||||
auto size = arg;
|
||||
for (int i = 0; i < static_cast<int>(unit); ++i)
|
||||
{
|
||||
size *= 1024;
|
||||
}
|
||||
return size;
|
||||
size *= 1024;
|
||||
}
|
||||
};
|
||||
return size;
|
||||
}
|
||||
};
|
||||
|
||||
SplittedValue getRoundedYScale(double value)
|
||||
SplittedValue getRoundedYScale(double value)
|
||||
{
|
||||
if (value == 0.0)
|
||||
return { 0, SizeUnit::Byte };
|
||||
|
||||
if (value <= 12.0)
|
||||
return { 12, SizeUnit::Byte };
|
||||
|
||||
auto calculatedUnit = SizeUnit::Byte;
|
||||
|
||||
while (value > 1000)
|
||||
{
|
||||
if (value == 0.0)
|
||||
return { 0, SizeUnit::Byte };
|
||||
|
||||
if (value <= 12.0)
|
||||
return { 12, SizeUnit::Byte };
|
||||
|
||||
auto calculatedUnit = SizeUnit::Byte;
|
||||
|
||||
while (value > 1000)
|
||||
{
|
||||
value /= 1000;
|
||||
calculatedUnit = static_cast<SizeUnit>(static_cast<int>(calculatedUnit) + 1);
|
||||
}
|
||||
|
||||
if (value > 100.0)
|
||||
{
|
||||
int roundedValue = static_cast<int>(value / 40) * 40;
|
||||
while (roundedValue < value) roundedValue += 40;
|
||||
return { static_cast<double>(roundedValue), calculatedUnit };
|
||||
}
|
||||
|
||||
if (value > 10.0)
|
||||
{
|
||||
int roundedValue = static_cast<int>(value / 4) * 4;
|
||||
while (roundedValue < value) roundedValue += 4;
|
||||
return { static_cast<double>(roundedValue), calculatedUnit };
|
||||
}
|
||||
|
||||
for (const auto &roundedValue : roundingTable)
|
||||
{
|
||||
if (value <= roundedValue)
|
||||
return { roundedValue, calculatedUnit };
|
||||
}
|
||||
|
||||
return { 10.0, calculatedUnit };
|
||||
value /= 1000;
|
||||
calculatedUnit = static_cast<SizeUnit>(static_cast<int>(calculatedUnit) + 1);
|
||||
}
|
||||
|
||||
QString formatLabel(const double argValue, const SizeUnit unit)
|
||||
if (value > 100.0)
|
||||
{
|
||||
// check is there need for digits after decimal separator
|
||||
const int precision = (argValue < 10) ? friendlyUnitPrecision(unit) : 0;
|
||||
return QLocale::system().toString(argValue, 'f', precision) + " " + unitString(unit, true);
|
||||
int roundedValue = static_cast<int>(value / 40) * 40;
|
||||
while (roundedValue < value) roundedValue += 40;
|
||||
return { static_cast<double>(roundedValue), calculatedUnit };
|
||||
}
|
||||
} // namespace
|
||||
|
||||
if (value > 10.0)
|
||||
{
|
||||
int roundedValue = static_cast<int>(value / 4) * 4;
|
||||
while (roundedValue < value) roundedValue += 4;
|
||||
return { static_cast<double>(roundedValue), calculatedUnit };
|
||||
}
|
||||
|
||||
for (const auto &roundedValue : roundingTable)
|
||||
{
|
||||
if (value <= roundedValue)
|
||||
return { roundedValue, calculatedUnit };
|
||||
}
|
||||
|
||||
return { 10.0, calculatedUnit };
|
||||
}
|
||||
|
||||
QString formatLabel(const double argValue, const SizeUnit unit)
|
||||
{
|
||||
// check is there need for digits after decimal separator
|
||||
const int precision = (argValue < 10) ? friendlyUnitPrecision(unit) : 0;
|
||||
return QLocale::system().toString(argValue, 'f', precision) + " " + unitString(unit, true);
|
||||
}
|
||||
|
||||
void SpeedWidget::UpdateSpeedPlotSettings()
|
||||
{
|
||||
@ -168,9 +164,12 @@ void SpeedWidget::UpdateSpeedPlotSettings()
|
||||
if (!Graph.colorConfig.contains(x)) \
|
||||
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_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) {
|
||||
QPen p{ { conf.R, conf.G, conf.B } };
|
||||
@ -200,7 +199,7 @@ void SpeedWidget::UpdateSpeedPlotSettings()
|
||||
|
||||
void SpeedWidget::Clear()
|
||||
{
|
||||
m_datahalfMin.clear();
|
||||
dataCollection.clear();
|
||||
m_properties.clear();
|
||||
UpdateSpeedPlotSettings();
|
||||
replot();
|
||||
@ -215,9 +214,9 @@ quint64 SpeedWidget::maxYValue()
|
||||
quint64 maxYValue = 0;
|
||||
|
||||
for (int id = 0; id < NB_GRAPHS; ++id)
|
||||
for (int i = m_datahalfMin.size() - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j)
|
||||
if (m_datahalfMin[i].y[id] > maxYValue)
|
||||
maxYValue = m_datahalfMin[i].y[id];
|
||||
for (int i = dataCollection.size() - 1, j = 0; (i >= 0) && (j <= VIEWABLE); --i, ++j)
|
||||
if (dataCollection[i].y[id] > maxYValue)
|
||||
maxYValue = dataCollection[i].y[id];
|
||||
|
||||
return maxYValue;
|
||||
}
|
||||
@ -288,10 +287,10 @@ void SpeedWidget::paintEvent(QPaintEvent *)
|
||||
{
|
||||
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 newY = rect.bottom() - m_datahalfMin[i].y[id] * yMultiplier;
|
||||
const int newY = rect.bottom() - dataCollection[i].y[id] * yMultiplier;
|
||||
points.push_back({ newX, newY });
|
||||
}
|
||||
|
||||
|
@ -35,7 +35,7 @@ class SpeedWidget : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum GraphID
|
||||
enum GraphType
|
||||
{
|
||||
INBOUND_UP,
|
||||
INBOUND_DOWN,
|
||||
@ -59,7 +59,7 @@ class SpeedWidget : public QGraphicsView
|
||||
|
||||
explicit SpeedWidget(QWidget *parent = nullptr);
|
||||
void UpdateSpeedPlotSettings();
|
||||
void AddPointData(QMap<SpeedWidget::GraphID, long> data);
|
||||
void AddPointData(QMap<SpeedWidget::GraphType, long> data);
|
||||
void Clear();
|
||||
void replot();
|
||||
|
||||
@ -76,7 +76,7 @@ class SpeedWidget : public QGraphicsView
|
||||
};
|
||||
|
||||
quint64 maxYValue();
|
||||
QList<PointData> m_datahalfMin;
|
||||
QList<PointData> dataCollection;
|
||||
|
||||
QMap<GraphID, GraphProperties> m_properties;
|
||||
QMap<GraphType, GraphProperties> m_properties;
|
||||
};
|
||||
|
163
src/ui/widgets/models/ConnectionModelHelper.cpp
Normal file
163
src/ui/widgets/models/ConnectionModelHelper.cpp
Normal 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());
|
||||
}
|
59
src/ui/widgets/models/ConnectionModelHelper.hpp
Normal file
59
src/ui/widgets/models/ConnectionModelHelper.hpp
Normal 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;
|
@ -20,12 +20,13 @@
|
||||
#include <QScrollBar>
|
||||
|
||||
#define TRAY_TOOLTIP_PREFIX "Qv2ray " QV2RAY_VERSION_STRING
|
||||
|
||||
#define CheckCurrentWidget \
|
||||
auto widget = GetItemWidget(connectionListWidget->currentItem()); \
|
||||
auto widget = GetIndexWidget(connectionTreeView->currentIndex()); \
|
||||
if (widget == nullptr) \
|
||||
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 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))
|
||||
{
|
||||
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);
|
||||
}
|
||||
modelHelper->Sort(byCol, asending ? Qt::AscendingOrder : Qt::DescendingOrder);
|
||||
on_locateBtn_clicked();
|
||||
}
|
||||
|
||||
@ -108,8 +75,10 @@ void MainWindow::OnRecentConnectionsMenuReadyToShow()
|
||||
for (const auto &conn : GlobalConfig.uiConfig.recentConnections)
|
||||
{
|
||||
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);
|
||||
speedChart->addWidget(speedChartWidget);
|
||||
//
|
||||
modelHelper = new ConnectionListHelper(connectionTreeView);
|
||||
//
|
||||
this->setWindowIcon(QIcon(":/assets/icons/qv2ray.png"));
|
||||
updateColorScheme();
|
||||
UpdateActionTranslations();
|
||||
@ -144,34 +115,10 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
||||
connect(ConnectionManager, &QvConfigHandler::OnStatsAvailable, this, &MainWindow::OnStatsAvailable);
|
||||
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) {
|
||||
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::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_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_Restart, &QAction::triggered, ConnectionManager, &QvConfigHandler::RestartConnection);
|
||||
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_Dsc);
|
||||
//
|
||||
connect(sortAction_SortByName_Asc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_NAME, true); });
|
||||
connect(sortAction_SortByName_Dsc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_NAME, false); });
|
||||
connect(sortAction_SortByData_Asc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_DATA, true); });
|
||||
connect(sortAction_SortByData_Dsc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_DATA, false); });
|
||||
connect(sortAction_SortByPing_Asc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_PING, true); });
|
||||
connect(sortAction_SortByPing_Dsc, &QAction::triggered, [this] { SortConnectionList(MW_ITEM_COL_PING, false); });
|
||||
connect(sortAction_SortByName_Asc, &QAction::triggered, [this] { SortConnectionList(ROLE_DISPLAYNAME, true); });
|
||||
connect(sortAction_SortByName_Dsc, &QAction::triggered, [this] { SortConnectionList(ROLE_DISPLAYNAME, false); });
|
||||
connect(sortAction_SortByData_Asc, &QAction::triggered, [this] { SortConnectionList(ROLE_DATA_USAGE, true); });
|
||||
connect(sortAction_SortByData_Dsc, &QAction::triggered, [this] { SortConnectionList(ROLE_DATA_USAGE, false); });
|
||||
connect(sortAction_SortByPing_Asc, &QAction::triggered, [this] { SortConnectionList(ROLE_LATENCY, true); });
|
||||
connect(sortAction_SortByPing_Dsc, &QAction::triggered, [this] { SortConnectionList(ROLE_LATENCY, false); });
|
||||
//
|
||||
sortBtn->setMenu(sortMenu);
|
||||
//
|
||||
graphWidgetMenu->addAction(action_RCM_CopyGraph);
|
||||
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
|
||||
const auto connectionStarted = StartAutoConnectionEntry();
|
||||
if (!connectionStarted && connectionListWidget->topLevelItemCount() > 0)
|
||||
|
||||
if (!connectionStarted && !ConnectionManager->Connections().isEmpty())
|
||||
{
|
||||
ReloadRecentConnectionList();
|
||||
// Select the first connection.
|
||||
const auto &topLevelItem = connectionListWidget->topLevelItem(0);
|
||||
const auto &item = (topLevelItem->childCount() > 0) ? topLevelItem->child(0) : topLevelItem;
|
||||
connectionListWidget->setCurrentItem(item);
|
||||
on_connectionListWidget_itemClicked(item, 0);
|
||||
const auto groups = ConnectionManager->AllGroups();
|
||||
if (!groups.isEmpty())
|
||||
{
|
||||
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)
|
||||
MWShowWindow();
|
||||
else
|
||||
@ -423,7 +369,7 @@ void MainWindow::timerEvent(QTimerEvent *event)
|
||||
|
||||
void MainWindow::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
if (focusWidget() == connectionListWidget)
|
||||
if (focusWidget() == connectionTreeView)
|
||||
{
|
||||
CheckCurrentWidget;
|
||||
if (e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)
|
||||
@ -435,7 +381,7 @@ void MainWindow::keyPressEvent(QKeyEvent *e)
|
||||
}
|
||||
else
|
||||
{
|
||||
connectionListWidget->expandItem(connectionListWidget->currentItem());
|
||||
connectionTreeView->expand(connectionTreeView->currentIndex());
|
||||
}
|
||||
}
|
||||
else if (e->key() == Qt::Key_F2)
|
||||
@ -450,7 +396,7 @@ void MainWindow::keyPressEvent(QKeyEvent *e)
|
||||
|
||||
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
|
||||
if (widget && widget->IsRenaming())
|
||||
{
|
||||
@ -481,10 +427,10 @@ void MainWindow::keyReleaseEvent(QKeyEvent *e)
|
||||
// Workaround of QtWidget not grabbing KeyDown and KeyUp in keyPressEvent
|
||||
if (e->key() == Qt::Key_Up || e->key() == Qt::Key_Down)
|
||||
{
|
||||
if (focusWidget() == connectionListWidget)
|
||||
if (focusWidget() == connectionTreeView)
|
||||
{
|
||||
CheckCurrentWidget;
|
||||
on_connectionListWidget_itemClicked(connectionListWidget->currentItem(), 0);
|
||||
on_connectionTreeView_clicked(connectionTreeView->currentIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -500,6 +446,7 @@ void MainWindow::Action_Start()
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete modelHelper;
|
||||
for (auto &widget : pluginWidgets) widget->accept();
|
||||
}
|
||||
|
||||
@ -534,14 +481,14 @@ void MainWindow::on_clearlogButton_clicked()
|
||||
{
|
||||
masterLogBrowser->document()->clear();
|
||||
}
|
||||
void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint &pos)
|
||||
void MainWindow::on_connectionTreeView_customContextMenuRequested(const QPoint &pos)
|
||||
{
|
||||
Q_UNUSED(pos)
|
||||
auto _pos = QCursor::pos();
|
||||
auto item = connectionListWidget->itemAt(connectionListWidget->mapFromGlobal(_pos));
|
||||
if (item != nullptr)
|
||||
auto item = connectionTreeView->indexAt(connectionTreeView->mapFromGlobal(_pos));
|
||||
if (item.isValid())
|
||||
{
|
||||
bool isConnection = GetItemWidget(item)->IsConnection();
|
||||
bool isConnection = GetIndexWidget(item)->IsConnection();
|
||||
// Disable connection-specific settings.
|
||||
action_RCM_Start->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_DuplicateConnection->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);
|
||||
}
|
||||
}
|
||||
@ -560,9 +507,9 @@ void MainWindow::Action_DeleteConnections()
|
||||
{
|
||||
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)
|
||||
{
|
||||
const auto identifier = widget->Identifier();
|
||||
@ -640,18 +587,6 @@ void MainWindow::on_subsButton_clicked()
|
||||
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)
|
||||
{
|
||||
Q_UNUSED(id)
|
||||
@ -660,7 +595,7 @@ void MainWindow::OnDisconnected(const ConnectionGroupPair &id)
|
||||
tray_action_Stop->setEnabled(false);
|
||||
tray_action_Restart->setEnabled(false);
|
||||
tray_SystemProxyMenu->setEnabled(false);
|
||||
lastConnectedIdentifier = id;
|
||||
lastConnected = id;
|
||||
locateBtn->setEnabled(false);
|
||||
if (!GlobalConfig.uiConfig.quietMode)
|
||||
{
|
||||
@ -684,7 +619,7 @@ void MainWindow::OnConnected(const ConnectionGroupPair &id)
|
||||
tray_action_Stop->setEnabled(true);
|
||||
tray_action_Restart->setEnabled(true);
|
||||
tray_SystemProxyMenu->setEnabled(true);
|
||||
lastConnectedIdentifier = id;
|
||||
lastConnected = id;
|
||||
locateBtn->setEnabled(true);
|
||||
on_clearlogButton_clicked();
|
||||
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)
|
||||
{
|
||||
// No recursive since we only need top level item
|
||||
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());
|
||||
modelHelper->Filter(arg1);
|
||||
}
|
||||
|
||||
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
|
||||
// has "any" latency. (Hope not...)
|
||||
//
|
||||
QMap<SpeedWidget::GraphID, long> pointData;
|
||||
QMap<SpeedWidget::GraphType, long> pointData;
|
||||
bool isOutbound = GlobalConfig.uiConfig.graphConfig.useOutboundStats;
|
||||
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 downSpeed = data[type].first.second;
|
||||
const auto upSpeed = data.first.first;
|
||||
const auto downSpeed = data.first.second;
|
||||
switch (type)
|
||||
{
|
||||
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) + //
|
||||
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)
|
||||
@ -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)
|
||||
{
|
||||
if (masterLogBrowser->verticalScrollBar()->maximum() == value)
|
||||
@ -944,9 +786,10 @@ void MainWindow::on_locateBtn_clicked()
|
||||
auto id = KernelInstance->CurrentConnection();
|
||||
if (!id.isEmpty())
|
||||
{
|
||||
connectionListWidget->setCurrentItem(connectionNodes.value(id).get());
|
||||
connectionListWidget->scrollToItem(connectionNodes.value(id).get());
|
||||
on_connectionListWidget_itemClicked(connectionNodes.value(id).get(), 0);
|
||||
const auto index = modelHelper->GetConnectionPairIndex(id);
|
||||
connectionTreeView->setCurrentIndex(index);
|
||||
connectionTreeView->scrollTo(index);
|
||||
on_connectionTreeView_clicked(index);
|
||||
}
|
||||
}
|
||||
|
||||
@ -960,9 +803,9 @@ void MainWindow::Action_DuplicateConnection()
|
||||
{
|
||||
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())
|
||||
{
|
||||
connlist.append(widget->Identifier());
|
||||
@ -1012,14 +855,14 @@ void MainWindow::on_clearChartBtn_clicked()
|
||||
speedChartWidget->Clear();
|
||||
}
|
||||
|
||||
void MainWindow::on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
|
||||
{
|
||||
Q_UNUSED(previous)
|
||||
if (current != nullptr && !isExiting)
|
||||
{
|
||||
on_connectionListWidget_itemClicked(current, 0);
|
||||
}
|
||||
}
|
||||
// void MainWindow::on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous)
|
||||
//{
|
||||
// Q_UNUSED(previous)
|
||||
// if (current != nullptr && !isExiting)
|
||||
// {
|
||||
// on_connectionListWidget_itemClicked(current, 0);
|
||||
// }
|
||||
//}
|
||||
|
||||
void MainWindow::on_masterLogBrowser_textChanged()
|
||||
{
|
||||
@ -1031,10 +874,10 @@ void MainWindow::on_masterLogBrowser_textChanged()
|
||||
|
||||
void MainWindow::Action_SetAutoConnection()
|
||||
{
|
||||
auto current = connectionListWidget->currentItem();
|
||||
if (current != nullptr)
|
||||
auto current = connectionTreeView->currentIndex();
|
||||
if (current.isValid())
|
||||
{
|
||||
auto widget = GetItemWidget(current);
|
||||
auto widget = GetIndexWidget(current);
|
||||
const auto identifier = widget->Identifier();
|
||||
GlobalConfig.autoStartId = identifier;
|
||||
GlobalConfig.autoStartBehavior = AUTO_CONNECTION_FIXED;
|
||||
@ -1048,10 +891,10 @@ void MainWindow::Action_SetAutoConnection()
|
||||
|
||||
void MainWindow::Action_ResetStats()
|
||||
{
|
||||
auto current = connectionListWidget->currentItem();
|
||||
if (current != nullptr)
|
||||
auto current = connectionTreeView->currentIndex();
|
||||
if (current.isValid())
|
||||
{
|
||||
auto widget = GetItemWidget(current);
|
||||
auto widget = GetIndexWidget(current);
|
||||
if (widget)
|
||||
{
|
||||
if (widget->IsConnection())
|
||||
@ -1064,10 +907,10 @@ void MainWindow::Action_ResetStats()
|
||||
|
||||
void MainWindow::Action_UpdateSubscription()
|
||||
{
|
||||
auto current = connectionListWidget->currentItem();
|
||||
if (current != nullptr)
|
||||
auto current = connectionTreeView->currentIndex();
|
||||
if (current.isValid())
|
||||
{
|
||||
auto widget = GetItemWidget(current);
|
||||
auto widget = GetIndexWidget(current);
|
||||
if (widget)
|
||||
{
|
||||
if (widget->IsConnection())
|
||||
@ -1083,11 +926,11 @@ void MainWindow::Action_UpdateSubscription()
|
||||
|
||||
void MainWindow::Action_TestLatency()
|
||||
{
|
||||
for (const auto ¤t : connectionListWidget->selectedItems())
|
||||
for (const auto ¤t : connectionTreeView->selectionModel()->selectedIndexes())
|
||||
{
|
||||
if (!current)
|
||||
if (!current.isValid())
|
||||
continue;
|
||||
const auto widget = GetItemWidget(current);
|
||||
const auto widget = GetIndexWidget(current);
|
||||
if (!widget)
|
||||
continue;
|
||||
if (widget->IsConnection())
|
||||
@ -1099,11 +942,11 @@ void MainWindow::Action_TestLatency()
|
||||
|
||||
void MainWindow::Action_TestRealLatency()
|
||||
{
|
||||
for (const auto ¤t : connectionListWidget->selectedItems())
|
||||
for (const auto ¤t : connectionTreeView->selectionModel()->selectedIndexes())
|
||||
{
|
||||
if (!current)
|
||||
if (!current.isValid())
|
||||
continue;
|
||||
const auto widget = GetItemWidget(current);
|
||||
const auto widget = GetIndexWidget(current);
|
||||
if (!widget)
|
||||
continue;
|
||||
if (widget->IsConnection())
|
||||
@ -1134,8 +977,8 @@ void MainWindow::on_newConnectionBtn_clicked()
|
||||
outboundsList.push_back(outboundEntry);
|
||||
CONFIGROOT root;
|
||||
root.insert("outbounds", outboundsList);
|
||||
const auto item = connectionListWidget->currentItem();
|
||||
const auto id = item ? DefaultGroupId : GetItemWidget(item)->Identifier().groupId;
|
||||
const auto item = connectionTreeView->currentIndex();
|
||||
const auto id = item.isValid() ? DefaultGroupId : GetIndexWidget(item)->Identifier().groupId;
|
||||
ConnectionManager->CreateConnection(root, alias, id);
|
||||
}
|
||||
}
|
||||
@ -1147,15 +990,15 @@ void MainWindow::on_newComplexConnectionBtn_clicked()
|
||||
bool isChanged = w.result() == QDialog::Accepted;
|
||||
if (isChanged)
|
||||
{
|
||||
const auto item = connectionListWidget->currentItem();
|
||||
const auto id = item ? DefaultGroupId : GetItemWidget(item)->Identifier().groupId;
|
||||
const auto item = connectionTreeView->currentIndex();
|
||||
const auto id = item.isValid() ? DefaultGroupId : GetIndexWidget(item)->Identifier().groupId;
|
||||
ConnectionManager->CreateConnection(root, QJsonIO::GetValue(root, "outbounds", 0, "tag").toString(), id);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::on_collapseGroupsBtn_clicked()
|
||||
{
|
||||
connectionListWidget->collapseAll();
|
||||
connectionTreeView->collapseAll();
|
||||
}
|
||||
|
||||
void MainWindow::Action_CopyRecentLogs()
|
||||
@ -1174,3 +1017,20 @@ void MainWindow::Action_CopyRecentLogs()
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include "ui/common/QvMessageBus.hpp"
|
||||
#include "ui/common/speedchart/speedwidget.hpp"
|
||||
#include "ui/widgets/common/WidgetUIBase.hpp"
|
||||
#include "ui/widgets/models/ConnectionModelHelper.hpp"
|
||||
#include "ui/widgets/widgets/ConnectionInfoWidget.hpp"
|
||||
#include "ui/widgets/widgets/ConnectionItemWidget.hpp"
|
||||
#include "ui_w_MainWindow.h"
|
||||
@ -17,15 +18,6 @@ namespace Qv2rayPlugin
|
||||
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
|
||||
: public QMainWindow
|
||||
, Ui::MainWindow
|
||||
@ -47,25 +39,29 @@ class MainWindow
|
||||
void on_activatedTray(QSystemTrayIcon::ActivationReason reason);
|
||||
void on_preferencesBtn_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_subsButton_clicked();
|
||||
//
|
||||
void on_connectionListWidget_itemDoubleClicked(QTreeWidgetItem *item, int column);
|
||||
void on_connectionFilterTxt_textEdited(const QString &arg1);
|
||||
void on_connectionListWidget_itemClicked(QTreeWidgetItem *item, int column);
|
||||
void on_locateBtn_clicked();
|
||||
//
|
||||
void on_chartVisibilityBtn_clicked();
|
||||
void on_logVisibilityBtn_clicked();
|
||||
void on_clearChartBtn_clicked();
|
||||
void on_connectionListWidget_currentItemChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous);
|
||||
void on_masterLogBrowser_textChanged();
|
||||
//
|
||||
void on_pluginsBtn_clicked();
|
||||
void on_collapseGroupsBtn_clicked();
|
||||
void on_newConnectionBtn_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:
|
||||
// Do not declare as slots, we connect them manually.
|
||||
@ -86,8 +82,6 @@ class MainWindow
|
||||
void Action_CopyGraphAsImage();
|
||||
void Action_CopyRecentLogs();
|
||||
|
||||
void OnConnectionWidgetFocusRequested(const ConnectionItemWidget *widget);
|
||||
|
||||
private:
|
||||
void MWToggleVisibility();
|
||||
void OnEditRequested(const ConnectionId &id);
|
||||
@ -98,14 +92,7 @@ class MainWindow
|
||||
void OnStatsAvailable(const ConnectionGroupPair &id, const QMap<StatisticsType, QvStatsSpeedData> &data);
|
||||
void OnVCoreLogAvailable(const ConnectionGroupPair &id, const QString &log);
|
||||
//
|
||||
void OnConnectionCreated(const ConnectionGroupPair &Id, const QString &displayName);
|
||||
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 SortConnectionList(ConnectionInfoRole byCol, bool asending);
|
||||
//
|
||||
void ReloadRecentConnectionList();
|
||||
void OnRecentConnectionsMenuReadyToShow();
|
||||
@ -122,8 +109,6 @@ class MainWindow
|
||||
void closeEvent(QCloseEvent *) override;
|
||||
|
||||
private:
|
||||
QHash<GroupId, std::shared_ptr<QTreeWidgetItem>> groupNodes;
|
||||
QHash<ConnectionGroupPair, std::shared_ptr<QTreeWidgetItem>> connectionNodes;
|
||||
// Charts
|
||||
SpeedWidget *speedChartWidget;
|
||||
SyntaxHighlighter *vCoreLogHighlighter;
|
||||
@ -179,7 +164,7 @@ class MainWindow
|
||||
int qvLogTimerId = -1;
|
||||
bool qvLogAutoScoll = true;
|
||||
//
|
||||
ConnectionGroupPair lastConnectedIdentifier;
|
||||
ConnectionGroupPair lastConnected;
|
||||
void MWSetSystemProxy();
|
||||
void MWClearSystemProxy();
|
||||
void MWShowWindow();
|
||||
@ -189,8 +174,7 @@ class MainWindow
|
||||
//
|
||||
void updateColorScheme();
|
||||
//
|
||||
void MWAddConnectionItem_p(const ConnectionGroupPair &id);
|
||||
void MWAddGroupItem_p(const GroupId &groupId);
|
||||
//
|
||||
QList<Qv2rayPlugin::QvPluginMainWindowWidget *> pluginWidgets;
|
||||
//
|
||||
Qv2ray::ui::widgets::models::ConnectionListHelper *modelHelper;
|
||||
};
|
||||
|
@ -135,7 +135,7 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="connectionListWidget">
|
||||
<widget class="QTreeView" name="connectionTreeView">
|
||||
<property name="contextMenuPolicy">
|
||||
<enum>Qt::CustomContextMenu</enum>
|
||||
</property>
|
||||
@ -154,26 +154,12 @@
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="animated">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="allColumnsShowFocus">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="headerHidden">
|
||||
<bool>true</bool>
|
||||
</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>
|
||||
</item>
|
||||
<item>
|
||||
@ -568,7 +554,6 @@
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<tabstops>
|
||||
<tabstop>connectionListWidget</tabstop>
|
||||
<tabstop>importConfigButton</tabstop>
|
||||
</tabstops>
|
||||
<resources>
|
||||
|
Loading…
Reference in New Issue
Block a user