[add] Several refactoring and prepare on #183

This commit is contained in:
Leroy.H.Y 2019-12-21 23:10:20 +08:00
parent 610e8e3043
commit 57c84cbdfb
No known key found for this signature in database
GPG Key ID: 6AC1673B587DC37D
9 changed files with 442 additions and 407 deletions

View File

@ -1 +1 @@
1907
1922

View File

@ -42,6 +42,7 @@ SOURCES += \
src/QvCoreConfigOperations_Generation.cpp \
src/QvUtils.cpp \
src/ui/w_PreferencesWindow.cpp \
src/utils/QvHelpers.cpp \
src/utils/QJsonModel.cpp \
src/ui/w_ExportConfig.cpp \
src/ui/w_InboundEditor.cpp \
@ -87,6 +88,7 @@ HEADERS += \
src/ui/w_RoutesEditor.hpp \
src/ui/w_SubscriptionEditor.hpp \
src/ui/w_ScreenShot_Core.hpp \
src/utils/QvHelpers.hpp \
src/utils/QvTinyLog.hpp \
src/utils/QJsonModel.hpp \
src/utils/QJsonObjectInsertMacros.h \

View File

@ -5,7 +5,7 @@
#include "QvUtils.hpp"
#define UPDATELOG(msg) LOG(MODULE_CONFIG, " [" + to_string(fromVersion) + "-" + to_string(fromVersion + 1) + "] --> " msg)
#define UPDATELOG(msg) LOG(MODULE_CONFIG, " [" + to_string(fromVersion) + "-" + to_string(fromVersion + 1) + "] --> " + msg)
namespace Qv2ray
{

View File

@ -1,25 +1,4 @@
#include "QvUtils.hpp"
#include <QQueue>
// Forwarded from QvTinyLog
static QQueue<QString> __loggerBuffer;
void _LOG(const std::string &module, const std::string &log)
{
string logString = "[" + module + "]: " + log;
cout << logString << endl;
__loggerBuffer.enqueue((logString + NEWLINE).c_str());
}
const QString readLastLog()
{
QString result;
while (!__loggerBuffer.isEmpty()) {
result += __loggerBuffer.dequeue();
}
return result;
}
namespace Qv2ray
{
@ -35,21 +14,6 @@ namespace Qv2ray
StringToFile(&str, &config);
}
const QString GenerateRandomString(int len)
{
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
QString randomString;
for (int i = 0; i < len; ++i) {
uint rand = QRandomGenerator::system()->generate();
uint max = static_cast<uint>(possibleCharacters.length());
QChar nextChar = possibleCharacters[rand % max];
randomString.append(nextChar);
}
return randomString;
}
Qv2rayConfig GetGlobalConfig()
{
return GlobalConfig;
@ -69,124 +33,6 @@ namespace Qv2ray
}
}
QString Stringify(list<string> list, QString saperator)
{
QString out;
for (auto item : list) {
out.append(QSTRING(item));
out.append(saperator);
}
if (out.length() >= 1)
out = out.remove(out.length() - 1, 1);
return out;
}
QString Stringify(QList<QString> list, QString saperator)
{
QString out;
for (auto item : list) {
out.append(item);
out.append(saperator);
}
if (out.length() >= 1)
out = out.remove(out.length() - 1, 1);
return out;
}
QString StringFromFile(QFile *source)
{
source->open(QFile::ReadOnly);
QTextStream stream(source);
QString str = stream.readAll();
source->close();
return str;
}
bool StringToFile(const QString *text, QFile *targetFile)
{
bool override = targetFile->exists();
targetFile->open(QFile::WriteOnly);
QTextStream stream(targetFile);
stream << *text << endl;
stream.flush();
targetFile->close();
return override;
}
QJsonObject JSONFromFile(QFile *sourceFile)
{
QString json = StringFromFile(sourceFile);
return JsonFromString(json);
}
QString JsonToString(QJsonObject json, QJsonDocument::JsonFormat format)
{
QJsonDocument doc;
doc.setObject(json);
return doc.toJson(format);
}
QString JsonToString(QJsonArray array, QJsonDocument::JsonFormat format)
{
QJsonDocument doc;
doc.setArray(array);
return doc.toJson(format);
}
QString VerifyJsonString(const QString &source)
{
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(source.toUtf8(), &error);
Q_UNUSED(doc)
if (error.error == QJsonParseError::NoError) {
return "";
} else {
LOG(MODULE_UI, "WARNING: Json parse returns: " + error.errorString().toStdString())
return error.errorString();
}
}
QJsonObject JsonFromString(QString string)
{
QJsonDocument doc = QJsonDocument::fromJson(string.toUtf8());
return doc.object();
}
QString Base64Encode(QString string)
{
QByteArray ba = string.toUtf8();
return ba.toBase64();
}
QString Base64Decode(QString string)
{
QByteArray ba = string.toUtf8();
return QString(QByteArray::fromBase64(ba));
}
QStringList SplitLines(const QString &_string)
{
return _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
}
list<string> SplitLines_std(const QString &_string)
{
list<string> list;
for (auto line : _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts)) {
list.push_back(line.toStdString());
}
return list;
}
void LoadGlobalConfig()
{
QFile file(QV2RAY_CONFIG_FILE);
@ -197,91 +43,5 @@ namespace Qv2ray
SetGlobalConfig(config);
file.close();
}
QStringList GetFileList(QDir dir)
{
return dir.entryList(QStringList() << "*" << "*.*", QDir::Hidden | QDir::Files);
}
bool CheckFile(QDir dir, QString fileName)
{
return GetFileList(dir).indexOf(fileName) >= 0;
}
void QvMessageBox(QWidget *parent, QString title, QString text)
{
QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
}
int QvMessageBoxAsk(QWidget *parent, QString title, QString text, QMessageBox::StandardButton extraButtons)
{
return QMessageBox::information(parent, title, text, QMessageBox::Yes | QMessageBox::No | extraButtons);
}
QString FormatBytes(long long bytes)
{
char str[64];
const char *sizes[5] = { "B", "KB", "MB", "GB", "TB" };
int i;
double dblByte = bytes;
for (i = 0; i < 5 && bytes >= 1024; i++, bytes /= 1024)
dblByte = bytes / 1024.0;
sprintf(str, "%.2f", dblByte);
return strcat(strcat(str, " "), sizes[i]);
}
QTranslator *getTranslator(const QString &lang)
{
QTranslator *translator = new QTranslator();
translator->load(lang + ".qm", ":/translations/");
return translator;
}
/// This returns a file name without extensions.
void DeducePossibleFileName(const QString &baseDir, QString *fileName, const QString &extension)
{
int i = 1;
if (!QDir(baseDir).exists()) {
QDir(baseDir).mkpath(baseDir);
LOG(MODULE_FILE, "Making path: " + baseDir.toStdString())
}
while (true) {
if (!QFile(baseDir + "/" + fileName + "_" + QString::number(i) + extension).exists()) {
*fileName = *fileName + "_" + QString::number(i);
return;
} else {
//LOG(MODULE_FILE, "File with name: " << (fileName + "_" + QString::number(i) + extension).toStdString() << " already exists")
}
i++;
}
}
void QFastAppendTextDocument(const QString &message, QTextDocument *doc)
{
QTextCursor cursor(doc);
cursor.movePosition(QTextCursor::End);
cursor.beginEditBlock();
cursor.insertBlock();
cursor.insertHtml(message);
cursor.endEditBlock();
}
QStringList ConvertQStringList(const QList<string> &stdListString)
{
QStringList listQt;
listQt.reserve(stdListString.size());
for (const std::string &s : stdListString) {
listQt.append(QString::fromStdString(s));
}
return listQt;
}
}
}

View File

@ -2,25 +2,12 @@
#define UTILS_H
#include "Qv2rayBase.hpp"
#include <QMessageBox>
#include <QUuid>
#include "QvHelpers.hpp"
namespace Qv2ray
{
namespace Utils
{
QTranslator *getTranslator(const QString &lang);
QStringList GetFileList(QDir dir);
QString Base64Encode(QString string);
QString Base64Decode(QString string);
QStringList SplitLines(const QString &str);
list<string> SplitLines_std(const QString &_string);
bool CheckFile(QDir dir, QString fileName);
const QString GenerateRandomString(int len = 12);
void SetConfigDirPath(const QString *path);
QString GetConfigDirPath();
@ -29,95 +16,6 @@ namespace Qv2ray
Qv2rayConfig GetGlobalConfig();
void LoadGlobalConfig();
void QvMessageBox(QWidget *parent, QString title, QString text);
int QvMessageBoxAsk(QWidget *parent, QString title, QString text, QMessageBox::StandardButton extraButtons = QMessageBox::NoButton);
//
QString StringFromFile(QFile *source);
bool StringToFile(const QString *text, QFile *target);
//
QJsonObject JsonFromString(QString string);
QString JsonToString(QJsonObject json, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
QString JsonToString(QJsonArray array, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
//
QString VerifyJsonString(const QString &source);
//
QString Stringify(list<string> list, QString saperator = ";");
QString Stringify(QList<QString> list, QString saperator = ";");
//
//
template <typename TYPE>
QString StructToJsonString(const TYPE t)
{
return QString::fromStdString(X::tojson(t, "", 4, ' '));
}
//
//
template <typename TYPE>
TYPE StructFromJsonString(const QString &str)
{
TYPE v;
X::loadjson(str.toStdString(), v, false);
return v;
}
//
// Misc
template<typename T>
QJsonObject GetRootObject(const T &t)
{
auto json = StructToJsonString(t);
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(json.toStdString()));
return doc.object();
}
template QJsonObject GetRootObject<RuleObject>(const RuleObject &t);
template QJsonObject GetRootObject<StreamSettingsObject>(const StreamSettingsObject &t);
template QJsonObject GetRootObject<VMessServerObject>(const VMessServerObject &t);
//
//
template <typename T>
void RemoveItem(std::vector<T> &vec, size_t pos)
{
auto it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
QString FormatBytes(long long bytes);
void DeducePossibleFileName(const QString &baseDir, QString *fileName, const QString &extension);
//
//
QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString);
void QFastAppendTextDocument(const QString &message, QTextDocument *doc);
QStringList ConvertQStringList(const QList<string> &stdListString);
inline bool IsValidFileName(const QString &str)
{
// If no match, we are good.
return QRegExp(R"([\/\\\"?%*:|><]|(^\.{1,2}$))").indexIn(str) == -1;
}
// These functions a sugers to prevent warnings from deprecated Qt 5.14 functions.
template<typename TYPE>
std::list<TYPE> toStdList(QList<TYPE> list)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
std::list<TYPE> _list{list.begin(), list.end()};
return _list;
#else
return list.toStdList();
#endif
}
template<typename TYPE>
QList<TYPE> toQList(std::list<TYPE> list)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
QList<TYPE> _list{list.begin(), list.end()};
return _list;
#else
return QList<TYPE>::fromStdList(list);
#endif
}
}
}

View File

@ -103,31 +103,36 @@ MainWindow::MainWindow(QWidget *parent):
updownImageBox->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
updownImageBox_2->setStyleSheet("image: url(" + QV2RAY_UI_RESOURCES_ROOT + "netspeed_arrow.png)");
//
// Setup System tray icons and menus
//
hTray->setToolTip(TRAY_TOOLTIP_PREFIX);
// Basic actions
action_Tray_ShowHide = new QAction(this->windowIcon(), tr("Hide"), this);
action_Tray_Quit = new QAction(tr("Quit"), this);
action_Tray_Start = new QAction(tr("Connect"), this);
action_Tray_Reconnect = new QAction(tr("Reconnect"), this);
action_Tray_Stop = new QAction(tr("Disconnect"), this);
//
QAction *action_Tray_ShowHide = new QAction(this->windowIcon(), tr("Hide"), this);
QAction *action_Tray_Quit = new QAction(tr("Quit"), this);
QAction *action_Tray_Start = new QAction(tr("Connect"), this);
QAction *action_Tray_Reconnect = new QAction(tr("Reconnect"), this);
QAction *action_Tray_Stop = new QAction(tr("Disconnect"), this);
//
QAction *action_RCM_RenameConnection = new QAction(tr("Rename"), this);
QAction *action_RCM_StartThis = new QAction(tr("Connect to this"), this);
QAction *action_RCM_ConvToComplex = new QAction(tr("Edit as Complex Config"), this);
QAction *action_RCM_EditJson = new QAction(QICON_R("json.png"), tr("Edit as Json"), this);
QAction *action_RCM_ShareQR = new QAction(QICON_R("share.png"), tr("Share as QRCode/VMess URL"), this);
action_Tray_SetSystemProxy = new QAction(tr("Enable System Proxy"), this);
action_Tray_ClearSystemProxy = new QAction(tr("Disable System Proxy"), this);
//
action_Tray_Start->setEnabled(true);
action_Tray_Stop->setEnabled(false);
action_Tray_Reconnect->setEnabled(false);
//
trayMenu->addAction(action_Tray_ShowHide);
trayMenu->addSeparator();
trayMenu->addAction(action_Tray_Start);
trayMenu->addAction(action_Tray_Stop);
trayMenu->addAction(action_Tray_Reconnect);
trayMenu->addSeparator();
trayMenu->addAction(action_Tray_Quit);
tray_SystemProxyMenu->addAction(action_Tray_SetSystemProxy);
tray_SystemProxyMenu->addAction(action_Tray_ClearSystemProxy);
tray_SystemProxyMenu->setTitle(tr("System Proxy"));
//
tray_RootMenu->addAction(action_Tray_ShowHide);
tray_RootMenu->addSeparator();
tray_RootMenu->addMenu(tray_SystemProxyMenu);
tray_RootMenu->addSeparator();
tray_RootMenu->addAction(action_Tray_Start);
tray_RootMenu->addAction(action_Tray_Stop);
tray_RootMenu->addAction(action_Tray_Reconnect);
tray_RootMenu->addSeparator();
tray_RootMenu->addAction(action_Tray_Quit);
//
connect(action_Tray_ShowHide, &QAction::triggered, this, &MainWindow::ToggleVisibility);
connect(action_Tray_Start, &QAction::triggered, this, &MainWindow::on_startButton_clicked);
@ -135,6 +140,15 @@ MainWindow::MainWindow(QWidget *parent):
connect(action_Tray_Reconnect, &QAction::triggered, this, &MainWindow::on_reconnectButton_clicked);
connect(action_Tray_Quit, &QAction::triggered, this, &MainWindow::quit);
connect(hTray, &QSystemTrayIcon::activated, this, &MainWindow::on_activatedTray);
//
// Actions for right click the connection list
//
QAction *action_RCM_RenameConnection = new QAction(tr("Rename"), this);
QAction *action_RCM_StartThis = new QAction(tr("Connect to this"), this);
QAction *action_RCM_ConvToComplex = new QAction(tr("Edit as Complex Config"), this);
QAction *action_RCM_EditJson = new QAction(QICON_R("json.png"), tr("Edit as Json"), this);
QAction *action_RCM_ShareQR = new QAction(QICON_R("share.png"), tr("Share as QRCode/VMess URL"), this);
//
connect(action_RCM_RenameConnection, &QAction::triggered, this, &MainWindow::on_action_RCM_RenameConnection_triggered);
connect(action_RCM_StartThis, &QAction::triggered, this, &MainWindow::on_action_StartThis_triggered);
connect(action_RCM_EditJson, &QAction::triggered, this, &MainWindow::on_action_RCM_EditJson_triggered);
@ -147,15 +161,15 @@ MainWindow::MainWindow(QWidget *parent):
connect(this, &MainWindow::DisConnect, this, &MainWindow::on_stopButton_clicked);
connect(this, &MainWindow::ReConnect, this, &MainWindow::on_reconnectButton_clicked);
//
hTray->setContextMenu(trayMenu);
hTray->setContextMenu(tray_RootMenu);
hTray->show();
//
listMenu = new QMenu(this);
listMenu->addAction(action_RCM_RenameConnection);
listMenu->addAction(action_RCM_StartThis);
listMenu->addAction(action_RCM_ConvToComplex);
listMenu->addAction(action_RCM_EditJson);
listMenu->addAction(action_RCM_ShareQR);
connectionListMenu = new QMenu(this);
connectionListMenu->addAction(action_RCM_RenameConnection);
connectionListMenu->addAction(action_RCM_StartThis);
connectionListMenu->addAction(action_RCM_ConvToComplex);
connectionListMenu->addAction(action_RCM_EditJson);
connectionListMenu->addAction(action_RCM_ShareQR);
//
ReloadConnections();
//
@ -208,7 +222,7 @@ MainWindow::MainWindow(QWidget *parent):
connectionListWidget->setCurrentItem(item);
on_connectionListWidget_itemChanged(item, 0);
connectionListWidget->scrollToItem(item);
trayMenu->actions()[0]->setText(tr("Show"));
tray_RootMenu->actions()[0]->setText(tr("Show"));
on_startButton_clicked();
} else {
QvMessageBox(this, tr("Autostarting a config"), tr("Could not find a specified config named: ") + NEWLINE +
@ -222,7 +236,7 @@ MainWindow::MainWindow(QWidget *parent):
}
// If we are not connected to anything, show the MainWindow.
if(vinstance->ConnectionStatus != STARTED){
if (vinstance->ConnectionStatus != STARTED) {
this->show();
}
@ -315,6 +329,7 @@ void MainWindow::VersionUpdate(QByteArray &data)
void MainWindow::ReloadConnections()
{
LOG(MODULE_UI, "Loading new GlobalConfig")
SetEditWidgetEnable(false);
currentConfig = GetGlobalConfig();
//
// Store the latency test value.
@ -325,10 +340,10 @@ void MainWindow::ReloadConnections()
}
connections.clear();
SetEditWidgetEnable(false);
//
connectionListWidget->clear();
auto _regularConnections = GetRegularConnections(currentConfig.configs);
auto _subsConnections = GetSubscriptionConnections(toStdList(QMap<string, string>(currentConfig.subscribes).keys()));
for (auto i = 0; i < _regularConnections.count(); i++) {
ConnectionObject _o;
@ -342,8 +357,6 @@ void MainWindow::ReloadConnections()
connectionListWidget->addTopLevelItem(new QTreeWidgetItem(QStringList() << _o.connectionName));
}
auto _subsConnections = GetSubscriptionConnections(toStdList(QMap<string, string>(currentConfig.subscribes).keys()));
for (auto i = 0; i < _subsConnections.count(); i++) {
auto subName = _subsConnections.keys()[i];
auto subTopLevel = new QTreeWidgetItem(QStringList() << tr("Subscription:") + " " + subName);
@ -537,9 +550,9 @@ void MainWindow::on_startButton_clicked()
this->show();
}
trayMenu->actions()[2]->setEnabled(!startFlag);
trayMenu->actions()[3]->setEnabled(startFlag);
trayMenu->actions()[4]->setEnabled(startFlag);
action_Tray_Start->setEnabled(!startFlag);
action_Tray_Stop->setEnabled(startFlag);
action_Tray_Reconnect->setEnabled(startFlag);
//
startButton->setEnabled(!startFlag);
stopButton->setEnabled(startFlag);
@ -559,9 +572,9 @@ void MainWindow::on_stopButton_clicked()
QFile(QV2RAY_GENERATED_FILE_PATH).remove();
statusLabel->setText(tr("Disconnected"));
vCoreLogBrowser->clear();
trayMenu->actions()[2]->setEnabled(true);
trayMenu->actions()[3]->setEnabled(false);
trayMenu->actions()[4]->setEnabled(false);
action_Tray_Start->setEnabled(true);
action_Tray_Stop->setEnabled(false);
action_Tray_Reconnect->setEnabled(false);
//
startButton->setEnabled(true);
stopButton->setEnabled(false);
@ -587,7 +600,7 @@ void MainWindow::on_stopButton_clicked()
void MainWindow::closeEvent(QCloseEvent *event)
{
this->hide();
trayMenu->actions()[0]->setText(tr("Show"));
tray_RootMenu->actions()[0]->setText(tr("Show"));
event->ignore();
}
void MainWindow::on_activatedTray(QSystemTrayIcon::ActivationReason reason)
@ -631,10 +644,10 @@ void MainWindow::ToggleVisibility()
QThread::msleep(20);
SetWindowPos(HWND(this->winId()), HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_SHOWWINDOW);
#endif
trayMenu->actions()[0]->setText(tr("Hide"));
tray_RootMenu->actions()[0]->setText(tr("Hide"));
} else {
this->hide();
trayMenu->actions()[0]->setText(tr("Show"));
tray_RootMenu->actions()[0]->setText(tr("Show"));
}
}
void MainWindow::quit()
@ -655,7 +668,7 @@ void MainWindow::ShowAndSetConnection(QString guiConnectionName, bool SetConnect
SetEditWidgetEnable(true);
//
// --------- BRGIN Show Connection
currentGUIShownConnectionName = guiConnectionName;
currentSelectedName = guiConnectionName;
auto conf = connections[guiConnectionName];
auto root = conf.config;
//
@ -766,7 +779,7 @@ void MainWindow::on_connectionListWidget_customContextMenuRequested(const QPoint
auto item = connectionListWidget->itemAt(connectionListWidget->mapFromGlobal(_pos));
if (IsConnectableItem(item)) {
listMenu->popup(_pos);
connectionListMenu->popup(_pos);
}
}
void MainWindow::on_action_RCM_RenameConnection_triggered()
@ -775,7 +788,7 @@ void MainWindow::on_action_RCM_RenameConnection_triggered()
SUBSCRIPTION_CONFIG_MODIFY_DENY(item->text(0))
item->setFlags(item->flags() | Qt::ItemIsEditable);
connectionListWidget->editItem(item);
originalName = item->text(0);
renameOriginalName = item->text(0);
isRenamingInProgress = true;
}
void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
@ -785,11 +798,11 @@ void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
if (isRenamingInProgress) {
// Should not rename a config from subscription?
// In this case it's after we entered the name.
LOG(MODULE_CONNECTION, "RENAME: " + originalName.toStdString() + " -> " + item->text(0).toStdString())
LOG(MODULE_CONNECTION, "RENAME: " + renameOriginalName.toStdString() + " -> " + item->text(0).toStdString())
auto newName = item->text(0);
// If I really did some changes.
if (originalName != newName) {
if (renameOriginalName != newName) {
bool canGo = true;
if (newName.trimmed().isEmpty()) {
@ -808,25 +821,25 @@ void MainWindow::on_connectionListWidget_itemChanged(QTreeWidgetItem *item, int)
}
if (!canGo) {
item->setText(0, originalName);
item->setText(0, renameOriginalName);
return;
}
//
// Change auto start config.
if (originalName.toStdString() == currentConfig.autoStartConfig.connectionName && currentConfig.autoStartConfig.subscriptionName.empty()) {
if (renameOriginalName.toStdString() == currentConfig.autoStartConfig.connectionName && currentConfig.autoStartConfig.subscriptionName.empty()) {
currentConfig.autoStartConfig.connectionName = newName.toStdString();
}
//configList[configList.indexOf(originalName.toStdString())] = newName.toStdString();
currentConfig.configs.remove(originalName.toStdString());
currentConfig.configs.remove(renameOriginalName.toStdString());
currentConfig.configs.push_back(newName.toStdString());
//
RenameConnection(originalName, newName);
RenameConnection(renameOriginalName, newName);
//
LOG(MODULE_UI, "Saving a global config")
SetGlobalConfig(currentConfig);
bool running = CurrentConnectionName == originalName;
bool running = CurrentConnectionName == renameOriginalName;
if (running) CurrentConnectionName = newName;
@ -1185,7 +1198,7 @@ void MainWindow::onPingFinished(QvTCPingData data)
connections[data.connectionName].latency = data.avg;
if (data.connectionName == currentGUIShownConnectionName) {
ShowAndSetConnection(currentGUIShownConnectionName, false, false);
if (data.connectionName == currentSelectedName) {
ShowAndSetConnection(currentSelectedName, false, false);
}
}

View File

@ -104,8 +104,11 @@ class MainWindow : public QMainWindow, Ui::MainWindow
void on_connectionListWidget_itemSelectionChanged();
private:
//
void SetEditWidgetEnable(bool enabled);
void ShowAndSetConnection(QString currentText, bool SetConnection, bool Apply);
void ReloadConnections();
Qv2rayConfig currentConfig;
//
// Charts
QChartView *speedChartView;
QChart *speedChartObj;
@ -114,23 +117,20 @@ class MainWindow : public QMainWindow, Ui::MainWindow
QList<double> uploadList;
QList<double> downloadList;
//
//
QMenu *trayMenu = new QMenu(this);
QMenu *listMenu;
QMenu *connectionListMenu;
/// Key --> ListWidget.item.text
QMap<QString, ConnectionObject> connections;
//
QString originalName;
QString renameOriginalName;
bool isRenamingInProgress;
//
// ID for QTimers
//
int logTimerId;
int speedTimerId;
int pingTimerId;
//
void ShowAndSetConnection(QString currentText, bool SetConnection, bool Apply);
void ReloadConnections();
//
//
QvHttpRequestHelper *requestHelper;
QSystemTrayIcon *hTray;
@ -139,11 +139,25 @@ class MainWindow : public QMainWindow, Ui::MainWindow
SyntaxHighlighter *vCoreLogHighlighter;
SyntaxHighlighter *qvAppLogHighlighter;
//
Qv2rayConfig currentConfig;
QList<QTextBrowser *> logTextBrowsers;
int currentLogBrowserId = 0;
QString currentGUIShownConnectionName;
QString currentSelectedName;
//
// Actions in the system tray menu
//
QMenu *tray_RootMenu = new QMenu(this);
QAction *action_Tray_ShowHide;
QAction *action_Tray_Quit;
// --> Connectivities
QAction *action_Tray_Start;
QAction *action_Tray_Reconnect ;
QAction *action_Tray_Stop;
// --> System proxy settings
QMenu *tray_SystemProxyMenu = new QMenu(this);
QAction *action_Tray_SetSystemProxy;
QAction *action_Tray_ClearSystemProxy;
//
};
#endif // MAINWINDOW_H

248
src/utils/QvHelpers.cpp Normal file
View File

@ -0,0 +1,248 @@
#include "QvHelpers.hpp"
#include "QvUtils.hpp"
#include <QQueue>
// Forwarded from QvTinyLog
static QQueue<QString> __loggerBuffer;
void _LOG(const std::string &module, const std::string &log)
{
string logString = "[" + module + "]: " + log;
cout << logString << endl;
__loggerBuffer.enqueue((logString + NEWLINE).c_str());
}
const QString readLastLog()
{
QString result;
while (!__loggerBuffer.isEmpty()) {
result += __loggerBuffer.dequeue();
}
return result;
}
namespace Qv2ray
{
namespace Utils
{
const QString GenerateRandomString(int len)
{
const QString possibleCharacters("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
QString randomString;
for (int i = 0; i < len; ++i) {
uint rand = QRandomGenerator::system()->generate();
uint max = static_cast<uint>(possibleCharacters.length());
QChar nextChar = possibleCharacters[rand % max];
randomString.append(nextChar);
}
return randomString;
}
QString Stringify(list<string> list, QString saperator)
{
QString out;
for (auto item : list) {
out.append(QSTRING(item));
out.append(saperator);
}
if (out.length() >= 1)
out = out.remove(out.length() - 1, 1);
return out;
}
QString Stringify(QList<QString> list, QString saperator)
{
QString out;
for (auto item : list) {
out.append(item);
out.append(saperator);
}
if (out.length() >= 1)
out = out.remove(out.length() - 1, 1);
return out;
}
QString StringFromFile(QFile *source)
{
source->open(QFile::ReadOnly);
QTextStream stream(source);
QString str = stream.readAll();
source->close();
return str;
}
bool StringToFile(const QString *text, QFile *targetFile)
{
bool override = targetFile->exists();
targetFile->open(QFile::WriteOnly);
QTextStream stream(targetFile);
stream << *text << endl;
stream.flush();
targetFile->close();
return override;
}
QJsonObject JSONFromFile(QFile *sourceFile)
{
QString json = StringFromFile(sourceFile);
return JsonFromString(json);
}
QString JsonToString(QJsonObject json, QJsonDocument::JsonFormat format)
{
QJsonDocument doc;
doc.setObject(json);
return doc.toJson(format);
}
QString JsonToString(QJsonArray array, QJsonDocument::JsonFormat format)
{
QJsonDocument doc;
doc.setArray(array);
return doc.toJson(format);
}
QString VerifyJsonString(const QString &source)
{
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(source.toUtf8(), &error);
Q_UNUSED(doc)
if (error.error == QJsonParseError::NoError) {
return "";
} else {
LOG(MODULE_UI, "WARNING: Json parse returns: " + error.errorString().toStdString())
return error.errorString();
}
}
QJsonObject JsonFromString(QString string)
{
QJsonDocument doc = QJsonDocument::fromJson(string.toUtf8());
return doc.object();
}
QString Base64Encode(QString string)
{
QByteArray ba = string.toUtf8();
return ba.toBase64();
}
QString Base64Decode(QString string)
{
QByteArray ba = string.toUtf8();
return QString(QByteArray::fromBase64(ba));
}
QStringList SplitLines(const QString &_string)
{
return _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts);
}
list<string> SplitLines_std(const QString &_string)
{
list<string> list;
for (auto line : _string.split(QRegExp("[\r\n]"), QString::SkipEmptyParts)) {
list.push_back(line.toStdString());
}
return list;
}
QStringList GetFileList(QDir dir)
{
return dir.entryList(QStringList() << "*" << "*.*", QDir::Hidden | QDir::Files);
}
bool FileExistsIn(QDir dir, QString fileName)
{
return GetFileList(dir).contains(fileName);
}
void QvMessageBox(QWidget *parent, QString title, QString text)
{
QMessageBox::warning(parent, title, text, QMessageBox::Ok | QMessageBox::Default, 0);
}
int QvMessageBoxAsk(QWidget *parent, QString title, QString text, QMessageBox::StandardButton extraButtons)
{
return QMessageBox::information(parent, title, text, QMessageBox::Yes | QMessageBox::No | extraButtons);
}
QString FormatBytes(long long bytes)
{
char str[64];
const char *sizes[5] = { "B", "KB", "MB", "GB", "TB" };
int i;
double dblByte = bytes;
for (i = 0; i < 5 && bytes >= 1024; i++, bytes /= 1024)
dblByte = bytes / 1024.0;
sprintf(str, "%.2f", dblByte);
return strcat(strcat(str, " "), sizes[i]);
}
QTranslator *getTranslator(const QString &lang)
{
QTranslator *translator = new QTranslator();
translator->load(lang + ".qm", ":/translations/");
return translator;
}
/// This returns a file name without extensions.
void DeducePossibleFileName(const QString &baseDir, QString *fileName, const QString &extension)
{
int i = 1;
if (!QDir(baseDir).exists()) {
QDir(baseDir).mkpath(baseDir);
LOG(MODULE_FILE, "Making path: " + baseDir.toStdString())
}
while (true) {
if (!QFile(baseDir + "/" + fileName + "_" + QString::number(i) + extension).exists()) {
*fileName = *fileName + "_" + QString::number(i);
return;
} else {
DEBUG(MODULE_FILE, "File with name: " + fileName->toStdString() + "_" + to_string(i) + extension.toStdString() + " already exists")
}
i++;
}
}
void QFastAppendTextDocument(const QString &message, QTextDocument *doc)
{
QTextCursor cursor(doc);
cursor.movePosition(QTextCursor::End);
cursor.beginEditBlock();
cursor.insertBlock();
cursor.insertHtml(message);
cursor.endEditBlock();
}
QStringList ConvertQStringList(const QList<string> &stdListString)
{
QStringList listQt;
listQt.reserve(stdListString.size());
for (const std::string &s : stdListString) {
listQt.append(QString::fromStdString(s));
}
return listQt;
}
}
}

100
src/utils/QvHelpers.hpp Normal file
View File

@ -0,0 +1,100 @@
#ifndef QVHELPERS_H
#define QVHELPERS_H
#include "Qv2rayBase.hpp"
#include <QMessageBox>
#include <QUuid>
namespace Qv2ray
{
namespace Utils
{
QTranslator *getTranslator(const QString &lang);
QStringList GetFileList(QDir dir);
QString Base64Encode(QString string);
QString Base64Decode(QString string);
QStringList SplitLines(const QString &str);
list<string> SplitLines_std(const QString &_string);
bool FileExistsIn(QDir dir, QString fileName);
const QString GenerateRandomString(int len = 12);
void QvMessageBox(QWidget *parent, QString title, QString text);
int QvMessageBoxAsk(QWidget *parent, QString title, QString text, QMessageBox::StandardButton extraButtons = QMessageBox::NoButton);
QString StringFromFile(QFile *source);
bool StringToFile(const QString *text, QFile *target);
QJsonObject JsonFromString(QString string);
QString JsonToString(QJsonObject json, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
QString JsonToString(QJsonArray array, QJsonDocument::JsonFormat format = QJsonDocument::JsonFormat::Indented);
QString VerifyJsonString(const QString &source);
QString Stringify(list<string> list, QString saperator = ";");
QString Stringify(QList<QString> list, QString saperator = ";");
QString FormatBytes(long long bytes);
void DeducePossibleFileName(const QString &baseDir, QString *fileName, const QString &extension);
QString ConvertGFWToPAC(const QString &rawContent, const QString &customProxyString);
void QFastAppendTextDocument(const QString &message, QTextDocument *doc);
QStringList ConvertQStringList(const QList<string> &stdListString);
//
template <typename TYPE>
QString StructToJsonString(const TYPE t)
{
return QString::fromStdString(X::tojson(t, "", 4, ' '));
}
//
template <typename TYPE>
TYPE StructFromJsonString(const QString &str)
{
TYPE v;
X::loadjson(str.toStdString(), v, false);
return v;
}
// Misc
template<typename T>
QJsonObject GetRootObject(const T &t)
{
auto json = StructToJsonString(t);
QJsonDocument doc = QJsonDocument::fromJson(QByteArray::fromStdString(json.toStdString()));
return doc.object();
}
template QJsonObject GetRootObject<RuleObject>(const RuleObject &t);
template QJsonObject GetRootObject<StreamSettingsObject>(const StreamSettingsObject &t);
template QJsonObject GetRootObject<VMessServerObject>(const VMessServerObject &t);
//
template <typename T>
void RemoveItem(std::vector<T> &vec, size_t pos)
{
auto it = vec.begin();
std::advance(it, pos);
vec.erase(it);
}
inline bool IsValidFileName(const QString &str)
{
// If no match, we are good.
return QRegExp(R"([\/\\\"?%*:|><]|(^\.{1,2}$))").indexIn(str) == -1;
}
// These functions a sugers to prevent warnings from deprecated Qt 5.14 functions.
template<typename TYPE>
std::list<TYPE> toStdList(QList<TYPE> list)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
std::list<TYPE> _list {list.begin(), list.end()};
return _list;
#else
return list.toStdList();
#endif
}
template<typename TYPE>
QList<TYPE> toQList(std::list<TYPE> list)
{
#if QT_VERSION >= QT_VERSION_CHECK(5,14,0)
QList<TYPE> _list {list.begin(), list.end()};
return _list;
#else
return QList<TYPE>::fromStdList(list);
#endif
}
}
}
#endif // QVHELPERS_H