mirror of
https://github.com/Qv2ray/Qv2ray.git
synced 2025-05-19 18:30:34 +08:00
[add] Several refactoring and prepare on #183
This commit is contained in:
parent
610e8e3043
commit
57c84cbdfb
@ -1 +1 @@
|
||||
1907
|
||||
1922
|
||||
|
@ -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 \
|
||||
|
@ -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
|
||||
{
|
||||
|
240
src/QvUtils.cpp
240
src/QvUtils.cpp
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
104
src/QvUtils.hpp
104
src/QvUtils.hpp
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
@ -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
248
src/utils/QvHelpers.cpp
Normal 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
100
src/utils/QvHelpers.hpp
Normal 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
|
Loading…
Reference in New Issue
Block a user