!27 新增VPN功能代码,重新提交PR

Merge pull request !27 from chenxuechao/openkylin/upstream-dev-fork-new
This commit is contained in:
zhaoshixu 2023-04-10 08:22:18 +00:00 committed by Gitee
commit 82d8bfc6e2
No known key found for this signature in database
GPG Key ID: 173E9B9CA92EEF8F
49 changed files with 7919 additions and 61 deletions

View File

@ -1,11 +1,13 @@
TEMPLATE = subdirs TEMPLATE = subdirs
CONFIG += ordered \ CONFIG += \
ordered \
qt qt
SUBDIRS = \ SUBDIRS = \
plugins/plugin.pro \ plugins/plugin.pro \
src \ src-vpn/src-vpn.pro \
src
TRANSLATIONS += \ TRANSLATIONS += \
translations/kylin-nm_zh_CN.ts \ translations/kylin-nm_zh_CN.ts \

View File

@ -3,4 +3,5 @@ SUBDIRS = \
netconnect \ netconnect \
wlanconnect \ wlanconnect \
mobilehotspot \ mobilehotspot \
proxy proxy \
vpn

63
plugins/vpn/itemframe.cpp Normal file
View File

@ -0,0 +1,63 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "itemframe.h"
#include <QPainter>
#define LAYOUT_MARGINS 0,0,0,0
#define MAIN_LAYOUT_MARGINS 0,0,0,0
ItemFrame::ItemFrame(QWidget *parent)
:QFrame(parent)
{
m_mainVLayout = new QVBoxLayout(this);
m_mainVLayout->setContentsMargins(MAIN_LAYOUT_MARGINS);
m_vpnFrame = new QFrame(this);
m_vpnFrame->setFrameShape(QFrame::Shape::NoFrame);
m_vpnFrame->setContentsMargins(LAYOUT_MARGINS);
m_vpnVLayout = new QVBoxLayout(this);
m_vpnVLayout->setContentsMargins(LAYOUT_MARGINS);
m_vpnVLayout->setSpacing(1);
m_addVpnWidget = new AddNetBtn(false, this);
m_addVpnWidget->setTextLabel(tr("Add Vpn"));
m_mainVLayout->setSpacing(1);
setLayout(m_mainVLayout);
m_vpnFrame->setLayout(m_vpnVLayout);
m_mainVLayout->addWidget(m_vpnFrame);
m_mainVLayout->addWidget(m_addVpnWidget);
}
void ItemFrame::filletStyleChange()
{
if (m_vpnVLayout->isEmpty()) {
return;
}
for (int i = 0; i < m_vpnVLayout->count(); ++i) {
QLayoutItem *it = m_vpnVLayout->itemAt(i);
VpnItem *itemFrame = (VpnItem*)(it->widget());
if (i != m_vpnVLayout->count()-1) {
itemFrame->setHalfFillet(false);
} else {
itemFrame->setHalfFillet(true);
}
}
}

47
plugins/vpn/itemframe.h Normal file
View File

@ -0,0 +1,47 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef ITEMFRAME_H
#define ITEMFRAME_H
#include <QFrame>
#include <QVBoxLayout>
#include "../component/AddBtn/addnetbtn.h"
#include "vpnitem.h"
class ItemFrame : public QFrame
{
Q_OBJECT
public:
ItemFrame(QWidget *parent = nullptr);
//VPN整体layout
QVBoxLayout * m_mainVLayout = nullptr;
//vpn列表Frame
QFrame * m_vpnFrame = nullptr;
//单设备列表layout
QVBoxLayout * m_vpnVLayout = nullptr;
//item列表
QMap<QString, VpnItem *> m_itemMap;
// //已激活uuid
// QString uuid = "";
//新建无线连接
AddNetBtn * m_addVpnWidget = nullptr;
void filletStyleChange();
};
#endif // ITEMFRAME_H

View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN" sourcelanguage="en">
<context>
<name>AddNetBtn</name>
<message>
<location filename="../../component/AddBtn/addnetbtn.cpp" line="47"/>
<source>Add Others</source>
<translation></translation>
</message>
<message>
<location filename="../../component/AddBtn/addnetbtn.cpp" line="51"/>
<source>Add WiredNetork</source>
<translation></translation>
</message>
</context>
<context>
<name>ItemFrame</name>
<message>
<location filename="../itemframe.cpp" line="38"/>
<source>Add Vpn</source>
<translation>VPN</translation>
</message>
</context>
<context>
<name>Vpn</name>
<message>
<location filename="../vpn.ui" line="53"/>
<source>VPN</source>
<translation></translation>
</message>
<message>
<location filename="../vpn.ui" line="68"/>
<source>import</source>
<translation></translation>
</message>
<message>
<location filename="../vpn.cpp" line="68"/>
<source>Vpn</source>
<translation></translation>
</message>
<message>
<location filename="../vpn.cpp" line="151"/>
<source>Show on Taskbar</source>
<translation></translation>
</message>
<message>
<location filename="../vpn.cpp" line="347"/>
<location filename="../vpn.cpp" line="454"/>
<source>connected</source>
<translation></translation>
</message>
<message>
<location filename="../vpn.cpp" line="349"/>
<location filename="../vpn.cpp" line="464"/>
<source>not connected</source>
<translation></translation>
</message>
</context>
<context>
<name>VpnItem</name>
<message>
<location filename="../vpnitem.cpp" line="58"/>
<source>Delete</source>
<translation></translation>
</message>
<message>
<location filename="../vpnitem.cpp" line="111"/>
<location filename="../vpnitem.cpp" line="124"/>
<source>Disconnect</source>
<translation></translation>
</message>
<message>
<location filename="../vpnitem.cpp" line="113"/>
<location filename="../vpnitem.cpp" line="122"/>
<source>Connect</source>
<translation></translation>
</message>
</context>
</TS>

502
plugins/vpn/vpn.cpp Normal file
View File

@ -0,0 +1,502 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "vpn.h"
#include "ui_vpn.h"
#include <QProcess>
#include <QMouseEvent>
#include <QDebug>
#include <QtDBus>
#include <QDBusArgument>
#define ACTIVATING 1
#define ACTIVATED 2
#define DEACTIVATING 3
#define DEACTIVATED 4
#define LABEL_RECT 17, 0, 105, 23
#define CONTENTS_MARGINS 0, 0, 0, 0
#define ITEM_MARGINS 16, 0, 16, 0
#define FRAME_MIN_SIZE 550, 60
#define FRAME_MAX_SIZE 16777215, 16777215
#define CONTECT_FRAME_MAX_SIZE 16777215, 60
#define HINT_TEXT_MARGINS 8, 0, 0, 0
#define FRAME_MIN_SIZE 550, 60
#define LABLE_MIN_WIDTH 188
#define COMBOBOX_MIN_WIDTH 200
#define LINE_MAX_SIZE 16777215, 1
#define LINE_MIN_SIZE 0, 1
#define ICON_SIZE 24,24
#define PASSWORD_FRAME_MIN_HIGHT 60
#define PASSWORD_FRAME_FIX_HIGHT 80
#define PASSWORD_FRAME_MIN_SIZE 550, 60
#define PASSWORD_FRAME_MAX_SIZE 16777215, 86
#define PASSWORD_ITEM_MARGINS 16, 12, 16, 14
#define KVpnSymbolic "ukui-vpn-symbolic"
#define KYLIN_APP_MANAGER_NAME "com.kylin.AppManager"
#define KYLIN_APP_MANAGER_PATH "/com/kylin/AppManager"
#define KYLIN_APP_MANAGER_INTERFACE "com.kylin.AppManager"
const QString VISIBLE = "visible";
const QByteArray GSETTINGS_SCHEMA = "org.ukui.kylin-nm.vpnicon";
Vpn::Vpn() : m_firstLoad(true)
{
QTranslator* translator = new QTranslator(this);
translator->load("/usr/share/kylin-nm/vpn/" + QLocale::system().name());
QApplication::installTranslator(translator);
m_pluginName = tr("Vpn");
m_pluginType = NETWORK;
}
Vpn::~Vpn()
{
if (!m_firstLoad) {
delete ui;
ui = nullptr;
delete m_interface;
delete m_switchGsettings;
}
}
QString Vpn::plugini18nName(){
return m_pluginName;
}
int Vpn::pluginTypes(){
return m_pluginType;
}
QWidget *Vpn::pluginUi(){
if (m_firstLoad) {
m_firstLoad = false;
ui = new Ui::Vpn;
m_pluginWidget = new QWidget;
m_pluginWidget->setAttribute(Qt::WA_DeleteOnClose);
ui->setupUi(m_pluginWidget);
qDBusRegisterMetaType<QVector<QStringList>>();
m_interface = new QDBusInterface("com.kylin.kylinvpn",
"/com/kylin/kylinvpn",
"com.kylin.kylinvpn",
QDBusConnection::sessionBus());
if(!m_interface->isValid()) {
qWarning() << qPrintable(QDBusConnection::sessionBus().lastError().message());
}
initComponent();
initConnect();
initNet();
}
return m_pluginWidget;
}
const QString Vpn::name() const {
return QStringLiteral("Vpn");
}
bool Vpn::isShowOnHomePage() const
{
return true;
}
QIcon Vpn::icon() const
{
return QIcon::fromTheme("ukui-vpn-symbolic");
}
bool Vpn::isEnable() const
{
return true;
}
void Vpn::initComponent(){
//在任务栏上显示图标
//显示已连接时间
m_topFrame = new QFrame(m_pluginWidget);
m_topFrame->setMinimumSize(FRAME_MIN_SIZE);
m_topFrame->setMaximumSize(FRAME_MAX_SIZE);
m_topFrame->setFrameShape(QFrame::Box);
QVBoxLayout *hotspotLyt = new QVBoxLayout(m_pluginWidget);
hotspotLyt->setContentsMargins(0, 0, 0, 0);
m_topFrame->setLayout(hotspotLyt);
m_showFrame = new QFrame(m_topFrame);
m_showFrame->setFrameShape(QFrame::Shape::NoFrame);
m_showFrame->setMinimumSize(FRAME_MIN_SIZE);
m_showFrame->setMaximumSize(CONTECT_FRAME_MAX_SIZE);
QHBoxLayout *showLayout = new QHBoxLayout(m_showFrame);
m_showLabel = new QLabel(tr("Show on Taskbar"), m_showFrame);
m_showLabel->setMinimumWidth(LABLE_MIN_WIDTH);
m_showBtn = new KSwitchButton(m_showFrame);
showLayout->setContentsMargins(ITEM_MARGINS);
showLayout->addWidget(m_showLabel);
showLayout->addStretch();
showLayout->addWidget(m_showBtn);
m_showFrame->setLayout(showLayout);
// m_Line = myLine();
// m_timeFrame = new QFrame(m_topFrame);
// m_timeFrame->setFrameShape(QFrame::Shape::NoFrame);
// m_timeFrame->setMinimumSize(FRAME_MIN_SIZE);
// m_timeFrame->setMaximumSize(CONTECT_FRAME_MAX_SIZE);
// QHBoxLayout *timeLayout = new QHBoxLayout(m_timeFrame);
// m_timeLabel = new QLabel(tr("Open"), m_timeFrame);
// m_timeLabel->setMinimumWidth(LABLE_MIN_WIDTH);
// m_timeBtn = new KSwitchButton(m_timeFrame);
// timeLayout->setContentsMargins(ITEM_MARGINS);
// timeLayout->addWidget(m_timeLabel);
// timeLayout->addStretch();
// timeLayout->addWidget(m_timeBtn);
// m_timeFrame->setLayout(timeLayout);
hotspotLyt->addWidget(m_showFrame);
// hotspotLyt->addWidget(m_Line);
// hotspotLyt->addWidget(m_timeFrame);
hotspotLyt->setSpacing(0);
//列表
m_listFrame = new ItemFrame(m_pluginWidget);
ui->verticalLayout_4->addWidget(m_topFrame);
ui->verticalLayout_3->addWidget(m_listFrame);
connect(m_listFrame->m_addVpnWidget, &AddNetBtn::clicked, this, [=]() {
runExternalApp();
});
if (QGSettings::isSchemaInstalled(GSETTINGS_SCHEMA)) {
m_switchGsettings = new QGSettings(GSETTINGS_SCHEMA);
setShowSwitchStatus();
connect(m_switchGsettings, &QGSettings::changed, this, [=] (const QString &key) {
if (key == VISIBLE) {
setShowSwitchStatus();
}
});
} else {
m_showBtn->setChecked(false);
m_showBtn->setCheckable(false);
qDebug()<<"[Vpn] org.ukui.kylin-nm.visible is not installed!";
}
connect(m_showBtn, &KSwitchButton::stateChanged, this, [=](bool state){
if (m_switchGsettings != nullptr) {
m_switchGsettings->set(VISIBLE, state);
}
});
// connect(m_timeBtn, &KSwitchButton::stateChanged, this, [=](bool state){
// if (m_switchGsettings != nullptr) {
// m_switchGsettings->set(VISIBLE, state);
// }
// });
ui->pushButton->hide();
}
void Vpn::initConnect()
{
connect(m_interface, SIGNAL(vpnAdd(QStringList)), this, SLOT(onVpnAdd(QStringList)));
connect(m_interface, SIGNAL(vpnRemove(QString)), this, SLOT(onVpnRemove(QString)));
connect(m_interface, SIGNAL(vpnUpdate(QStringList)), this, SLOT(onVpnUpdate(QStringList)));
connect(m_interface, SIGNAL(vpnActiveConnectionStateChanged(QString, int)),
this, SLOT(onVpnActiveConnectionStateChanged(QString, int)));
}
//初始化列表
void Vpn::initNet()
{
qDebug() << "[Vpn]initNet";
if (!m_interface->isValid()) {
return;
}
QDBusMessage result = m_interface->call(QStringLiteral("getVirtualList"));
if(result.type() == QDBusMessage::ErrorMessage)
{
qWarning() << "getVirtualList error:" << result.errorMessage();
return;
}
auto dbusArg = result.arguments().at(0).value<QDBusArgument>();
QVector<QStringList> variantList;
dbusArg >> variantList;
if (variantList.size() == 0) {
qDebug() << "[Vpn]initNet list empty";
return;
}
for (int i = 0; i < variantList.size(); ++i) {
QStringList vpnInfo = variantList.at(i);
addOneVirtualItem(vpnInfo);
}
return;
}
void Vpn::setShowSwitchStatus()
{
if (QGSettings::isSchemaInstalled(GSETTINGS_SCHEMA)) {
bool status = m_switchGsettings->get(VISIBLE).toBool();
m_showBtn->setChecked(status);
} else {
qDebug()<<"[Vpn] org.ukui.kylin-nm.switch is not installed!";
}
}
void Vpn::runExternalApp(){
// QString cmd = "nm-connection-editor";
// QProcess process(this);
// process.startDetached(cmd);
if (m_interface->isValid()) {
m_interface->call(QStringLiteral("showVpnAddWidget"));
}
}
QFrame* Vpn::myLine()
{
QFrame *line = new QFrame(m_pluginWidget);
line->setMinimumSize(QSize(LINE_MIN_SIZE));
line->setMaximumSize(QSize(LINE_MAX_SIZE));
line->setLineWidth(0);
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
return line;
}
//刪除
void Vpn::deleteVpn(QString uuid)
{
m_interface->call(QStringLiteral("deleteVpn"), uuid);
}
//激活
void Vpn::activeConnect(QString uuid) {
m_interface->call(QStringLiteral("activateVpn"), uuid);
}
//详情页
void Vpn::showDetailPage(QString uuid) {
m_interface->call(QStringLiteral("showDetailPage"), uuid);
}
//断开
void Vpn::deActiveConnect(QString uuid) {
m_interface->call(QStringLiteral("deactivateVpn"), uuid);
}
//增加一项
void Vpn::addOneVirtualItem(QStringList infoList)
{
if (infoList.size() < 4) {
qDebug() << "[Vpn]QStringList size less";
return;
}
if (m_listFrame->m_itemMap.contains(infoList.at(1))) {
qDebug() << "[Vpn]Already exist a virtual " << infoList.at(1);
return;
}
qDebug() << "[Vpn]addOneVitualItem" << infoList.at(0) << infoList.at(3) ;
QString connName = infoList.at(0);
QString connUuid = infoList.at(1);
QString connDbusPath = infoList.at(2);
int status = infoList.at(3).toInt(); //1-连接中 2-已连接 3-断开中 4-已断开
VpnItem * item = new VpnItem(m_pluginWidget);
QIcon searchIcon = QIcon::fromTheme(KVpnSymbolic);
item->m_iconLabel->setPixmap(searchIcon.pixmap(searchIcon.actualSize(QSize(ICON_SIZE))));
item->m_titileLabel->setText(connName);
item->m_uuid = connUuid;
item->m_dbusPath = connDbusPath;
if (status == 1 || status == 3) {
item->startLoading();
}
connect(item->m_infoLabel, &GrayInfoButton::clicked, this, [=]{
showDetailPage(item->m_uuid);
});
item->m_isAcitve = (status == 2);
item->setConnectActionText(item->m_isAcitve);
if (item->m_isAcitve) {
item->m_statusLabel->setText(tr("connected"));
} else {
item->m_statusLabel->setText(tr("not connected"));
}
connect(item, &QPushButton::clicked, this, [=] {
if (item->m_isAcitve || item->m_loading) {
deActiveConnect(item->m_uuid);
} else {
activeConnect(item->m_uuid);
}
});
connect(item, &VpnItem::connectActionTriggered, this, [=] {
activeConnect(item->m_uuid);
});
connect(item, &VpnItem::disconnectActionTriggered, this, [=] {
deActiveConnect(item->m_uuid);
});
connect(item, &VpnItem::deleteActionTriggered, this, [=] {
deleteVpn(item->m_uuid);
});
//记录到deviceFrame的m_itemMap中
m_listFrame->m_itemMap.insert(connUuid, item);
int index = getInsertPos(connName);
qDebug()<<"[Vpn]addOneVirtualItem " << connName << " at pos:" << index;
m_listFrame->m_vpnVLayout->insertWidget(index, item);
}
void Vpn::removeOneVirtualItem(QString dbusPath)
{
qDebug()<<"[Vpn]vpn remove dbus path:" << dbusPath;
QMap<QString, VpnItem *>::iterator itemIter;
for (itemIter = m_listFrame->m_itemMap.begin(); itemIter != m_listFrame->m_itemMap.end(); itemIter++) {
if (itemIter.value()->m_dbusPath == dbusPath) {
qDebug()<<"[Vpn]vpn remove " << dbusPath << " find in " << itemIter.value()->m_titileLabel->text();
QString key = itemIter.key();
m_listFrame->m_vpnVLayout->removeWidget(itemIter.value());
delete itemIter.value();
m_listFrame->m_itemMap.remove(key);
break;
}
}
}
//增加
void Vpn::onVpnAdd(QStringList infoList)
{
addOneVirtualItem(infoList);
}
//移出
void Vpn::onVpnRemove(QString path)
{
removeOneVirtualItem(path);
}
//名称变化
void Vpn::onVpnUpdate(QStringList info)
{
if (m_listFrame->m_itemMap.contains(info.at(1))) {
qDebug() << "[Vpn]" << m_listFrame->m_itemMap[info.at(1)]->m_titileLabel->text() << "change to" << info.at(0);
if (m_listFrame->m_itemMap[info.at(1)]->m_titileLabel->text() != info.at(0)) {
m_listFrame->m_itemMap[info.at(1)]->m_titileLabel->setText(info.at(0));
}
}
}
void Vpn::onVpnActiveConnectionStateChanged(QString uuid, int status)
{
if (uuid.isEmpty()) {
qDebug() << "[Vpn]onActiveConnectionChanged but uuid is empty";
return;
}
qDebug() << "[Vpn]onActiveConnectionChanged " << uuid << status;
VpnItem * item= nullptr;
if (m_listFrame->m_itemMap.contains(uuid)) {
item = m_listFrame->m_itemMap[uuid];
if (status == ACTIVATED) {
//为已连接则放到第一个
m_listFrame->m_vpnVLayout->removeWidget(item);
m_listFrame->m_vpnVLayout->insertWidget(0,item);
} else if (status == DEACTIVATED) {
//为断开则重新插入
int index = getInsertPos(item->m_titileLabel->text());
qDebug() << "[Vpn]reinsert" << item->m_titileLabel->text() << "pos" << index << "because status changes to deactive";
m_listFrame->m_vpnVLayout->removeWidget(item);
m_listFrame->m_vpnVLayout->insertWidget(index,item);
}
itemActiveConnectionStatusChanged(item, status);
}
}
void Vpn::itemActiveConnectionStatusChanged(VpnItem *item, int status)
{
// QString iconPath = NoNetSymbolic;
if (status == ACTIVATING) {
item->startLoading();
} else if (status == ACTIVATED) {
item->stopLoading();
// iconPath = KLanSymbolic;
item->m_statusLabel->clear();
item->m_statusLabel->setMinimumSize(36,36);
item->m_statusLabel->setMaximumSize(16777215,16777215);
item->m_statusLabel->setText(tr("connected"));
item->m_isAcitve = true;
} else if (status == DEACTIVATING) {
item->startLoading();
} else {
item->stopLoading();
item->m_statusLabel->setMinimumSize(36,36);
item->m_statusLabel->setMaximumSize(16777215,16777215);
item->m_statusLabel->clear();
item->m_isAcitve = false;
item->m_statusLabel->setText(tr("not connected"));
}
item->setConnectActionText(item->m_isAcitve);
}
int Vpn::getInsertPos(QString connName)
{
qDebug() << "[Vpn]getInsertPos" << connName;
int index = 0;
if(!m_interface->isValid()) {
index = 0;
} else {
QDBusMessage result = m_interface->call(QStringLiteral("getVirtualList"));
if(result.type() == QDBusMessage::ErrorMessage)
{
qWarning() << "getVirtualList error:" << result.errorMessage();
return 0;
}
auto dbusArg = result.arguments().at(0).value<QDBusArgument>();
QVector<QStringList> variantList;
dbusArg >> variantList;
for (int i = 0; i < variantList.size(); ++i ) {
if (variantList.at(i).at(0) == connName) {
qDebug() << "pos in kylin-nm is " << i;
index = i;
break;
}
}
if (variantList.at(0).size() == 1) {
index--;
}
}
return index;
}

120
plugins/vpn/vpn.h Normal file
View File

@ -0,0 +1,120 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2019 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef VPN_H
#define VPN_H
#include <QObject>
#include <QtPlugin>
#include <QtDBus/QDBusInterface>
#include <QFrame>
#include <QLabel>
#include "interface.h"
#include "addbtn.h"
#include "imageutil.h"
#include "kwidget.h"
#include "kswitchbutton.h"
#include "itemframe.h"
using namespace kdk;
namespace Ui {
class Vpn;
}
class Vpn : public QObject, CommonInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.ukcc.CommonInterface")
Q_INTERFACES(CommonInterface)
public:
Vpn();
~Vpn();
QString plugini18nName() Q_DECL_OVERRIDE;
int pluginTypes() Q_DECL_OVERRIDE;
QWidget * pluginUi() Q_DECL_OVERRIDE;
const QString name() const Q_DECL_OVERRIDE;
bool isShowOnHomePage() const Q_DECL_OVERRIDE;
QIcon icon() const Q_DECL_OVERRIDE;
bool isEnable() const Q_DECL_OVERRIDE;
public:
void initComponent();
void initConnect();
void runExternalApp();
protected:
// bool eventFilter(QObject *watched, QEvent *event);
private:
Ui::Vpn *ui;
QString m_pluginName;
int m_pluginType;
QWidget * m_pluginWidget;
QDBusInterface *m_interface = nullptr;
QFrame *m_topFrame;
QFrame *m_showFrame;
QLabel *m_showLabel;
KSwitchButton *m_showBtn;
QFrame *m_Line;
QFrame *m_timeFrame;
QLabel *m_timeLabel;
KSwitchButton *m_timeBtn;
ItemFrame *m_listFrame;
bool m_firstLoad;
QGSettings *m_switchGsettings;
QFrame* myLine();
int getInsertPos(QString connName);
void deleteVpn(QString uuid);
void activeConnect(QString uuid);
void deActiveConnect(QString uuid);
void showDetailPage(QString uuid);
//获取设备列表
void initNet();
//增加一项
void addOneVirtualItem(QStringList infoList);
//减少一项
void removeOneVirtualItem(QString uuid);
//单个lan连接状态变化
void itemActiveConnectionStatusChanged(VpnItem *item, int status);
void setShowSwitchStatus();
private slots:
void onVpnAdd(QStringList);
void onVpnRemove(QString);
void onVpnUpdate(QStringList);
void onVpnActiveConnectionStateChanged(QString, int);
};
#endif // VPN_H

50
plugins/vpn/vpn.pro Normal file
View File

@ -0,0 +1,50 @@
#-------------------------------------------------
#
# Project created by QtCreator 2019-06-29T13:53:10
#
#-------------------------------------------------
QT += widgets dbus
TEMPLATE = lib
CONFIG += plugin \
c++11 \
link_pkgconfig
include(../component/addbtn.pri)
PKGCONFIG += gsettings-qt \
kysdk-qtwidgets \
TARGET = $$qtLibraryTarget(vpn)
DESTDIR = ../..
target.path = $$[QT_INSTALL_LIBS]/ukui-control-center
trans.files = translations/*
trans.path = /usr/share/kylin-nm/vpn/
INCLUDEPATH += \
$$PROJECT_COMPONENTSOURCE \
$$PROJECT_ROOTDIR \
/usr/include/ukcc/interface \
/usr/include/ukcc/widgets
LIBS += -L$$[QT_INSTALL_LIBS] -lukcc
SOURCES += \
vpn.cpp \
itemframe.cpp \
vpnitem.cpp
HEADERS += \
vpn.h \
itemframe.h \
vpnitem.h
FORMS += \
vpn.ui
INSTALLS += target \
trans
TRANSLATIONS += \
translations/zh_CN.ts

112
plugins/vpn/vpn.ui Normal file
View File

@ -0,0 +1,112 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Vpn</class>
<widget class="QWidget" name="Vpn">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>800</width>
<height>710</height>
</rect>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="windowTitle">
<string notr="true">Vpn</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<property name="spacing">
<number>8</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item>
<widget class="TitleLabel" name="titleLabel">
<property name="sizePolicy">
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text">
<string>VPN</string>
</property>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_4"/>
</item>
<item>
<layout class="QVBoxLayout" name="verticalLayout_3"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pushButton">
<property name="text">
<string>import</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
<customwidgets>
<customwidget>
<class>TitleLabel</class>
<extends>QLabel</extends>
<header location="global">titlelabel.h</header>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

187
plugins/vpn/vpnitem.cpp Normal file
View File

@ -0,0 +1,187 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "vpnitem.h"
#include <QPainter>
#define FRAME_SPEED 150
#define LIMIT_TIME 60*1000
#define TOTAL_PAGE 8
#define RADIUS 6.0
#define THEME_QT_SCHEMA "org.ukui.style"
#define MODE_QT_KEY "style-name"
VpnItem::VpnItem(bool bAcitve, QWidget *parent)
: m_isAcitve(bAcitve), QPushButton(parent)
{
this->setMinimumSize(550, 58);
this->setProperty("useButtonPalette", true);
this->setFlat(true);
QPalette pal = this->palette();
QColor color = pal.color(QPalette::Button);
color.setAlphaF(0.5);
pal.setColor(QPalette::Button, color);
this->setPalette(pal);
QHBoxLayout *mLanLyt = new QHBoxLayout(this);
mLanLyt->setContentsMargins(16,0,16,0);
mLanLyt->setSpacing(16);
m_iconLabel = new QLabel(this);
m_iconLabel->setProperty("useIconHighlightEffect", 0x2);
m_titileLabel = new FixLabel(this);
m_statusLabel = new QLabel(this);
m_statusLabel->setAlignment(Qt::AlignRight | Qt::AlignVCenter);
m_infoLabel = new GrayInfoButton(this);
m_moreButton = new QToolButton(this);
m_moreButton->setProperty("useButtonPalette", true);
m_moreButton->setPopupMode(QToolButton::InstantPopup);
m_moreButton->setAutoRaise(true);
m_moreButton->setIcon(QIcon::fromTheme("view-more-horizontal-symbolic"));
m_moreMenu = new QMenu(m_moreButton);
m_connectAction = new QAction(m_moreMenu);
m_deleteAction = new QAction(tr("Delete"), m_moreMenu);
setConnectActionText(m_isAcitve);
m_moreMenu->addAction(m_connectAction);
m_moreMenu->addAction(m_deleteAction);
m_moreButton->setMenu(m_moreMenu);
mLanLyt->addWidget(m_iconLabel);
mLanLyt->addWidget(m_titileLabel,Qt::AlignLeft);
mLanLyt->addStretch();
mLanLyt->addWidget(m_statusLabel);
mLanLyt->addWidget(m_infoLabel);
mLanLyt->addWidget(m_moreButton);
m_loadIcons.append(QIcon::fromTheme("ukui-loading-1-symbolic"));
m_loadIcons.append(QIcon::fromTheme("ukui-loading-2-symbolic"));
m_loadIcons.append(QIcon::fromTheme("ukui-loading-3-symbolic"));
m_loadIcons.append(QIcon::fromTheme("ukui-loading-4-symbolic"));
m_loadIcons.append(QIcon::fromTheme("ukui-loading-5-symbolic"));
m_loadIcons.append(QIcon::fromTheme("ukui-loading-6-symbolic"));
m_loadIcons.append(QIcon::fromTheme("ukui-loading-7-symbolic"));
m_waitTimer = new QTimer(this);
connect(m_waitTimer, &QTimer::timeout, this, &VpnItem::updateIcon);
connect(m_connectAction, &QAction::triggered, this, &VpnItem::onConnectTriggered);
connect(m_deleteAction, &QAction::triggered, this, &VpnItem::onDeletetTriggered);
m_moreMenu->installEventFilter(this);
}
void VpnItem::updateIcon()
{
if (m_currentIconIndex > 6) {
m_currentIconIndex = 0;
}
m_statusLabel->setPixmap(m_loadIcons.at(m_currentIconIndex).pixmap(16,16));
m_currentIconIndex ++;
}
void VpnItem::startLoading()
{
m_waitTimer->start(FRAME_SPEED);
m_loading = true;
}
void VpnItem::stopLoading(){
m_waitTimer->stop();
m_loading = false;
}
void VpnItem::setConnectActionText(bool isAcitve)
{
if (isAcitve) {
m_connectAction->setText(tr("Disconnect"));
} else {
m_connectAction->setText(tr("Connect"));
}
}
void VpnItem::onConnectTriggered()
{
if (!m_connectAction) {
return;
}
if (m_connectAction->text() == tr("Connect")) {
Q_EMIT connectActionTriggered();
} else if (m_connectAction->text() == tr("Disconnect")) {
Q_EMIT disconnectActionTriggered();
}
}
void VpnItem::onDeletetTriggered()
{
if (!m_deleteAction) {
return;
}
Q_EMIT deleteActionTriggered();
}
void VpnItem::paintEvent(QPaintEvent *event)
{
QPalette pal = this->palette();
QPainter painter(this);
painter.setRenderHint(QPainter:: Antialiasing, true); //设置渲染,启动反锯齿
painter.setPen(Qt::NoPen);
painter.setBrush(pal.color(QPalette::Base));
QRect rect = this->rect();
#if 0
if (!m_useHalfFillet) {
painter.drawRect(rect);
} else {
QPainterPath path;
// path.addRoundedRect (rect, RADIUS, RADIUS);
// QRect temp_rect(rect.left(), rect.top(), rect.width(), rect.height()/2);
// path.addRect(temp_rect);
//设置起点
path.moveTo(rect.topLeft().x(), rect.topLeft().y());
path.lineTo(rect.bottomLeft().x(), rect.bottomLeft().y() - RADIUS);
//绘制圆角 圆弧以外切圆的270度位置为起点逆时针画圆弧运行90度结束
path.arcTo(QRect(QPoint(rect.bottomLeft().x(), rect.bottomLeft().y() - (RADIUS * 2)), QSize(RADIUS * 2, RADIUS * 2)), 180, 90);
path.lineTo(rect.bottomRight().x() - RADIUS, rect.bottomRight().y());
//画圆弧
path.arcTo(QRect(QPoint(rect.bottomRight().x() - (RADIUS * 2), rect.bottomRight().y() - (RADIUS * 2)), QSize(RADIUS * 2, RADIUS * 2)), 270, 90);
path.lineTo(rect.topRight());
path.lineTo(rect.topLeft());
painter.drawPath(path);
}
#endif
painter.drawRect(rect);
QPushButton::paintEvent(event);
}
bool VpnItem::eventFilter(QObject *watched, QEvent *event)
{
//菜单右边界与按钮右边界对齐
if (event->type() == QEvent::Show && watched == m_moreMenu) {
int menuXPos = m_moreMenu->pos().x();
int menuWidth = m_moreMenu->size().width();
int btnWidth = m_moreButton->size().width();
QPoint pos = QPoint (menuXPos - menuWidth + btnWidth, m_moreMenu->pos().y());
m_moreMenu->move(pos);
return true;
}
return false;
}

87
plugins/vpn/vpnitem.h Normal file
View File

@ -0,0 +1,87 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef VPNITEM_H
#define VPNITEM_H
#include <QWidget>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLabel>
#include <QVariantMap>
#include <QTimer>
#include <QDebug>
#include <QGSettings>
#include <QImage>
#include <QPainter>
#include <QToolButton>
#include <QMenu>
#include <QEvent>
#include "fixlabel.h"
#include "../component/AddBtn/grayinfobutton.h"
class VpnItem : public QPushButton
{
Q_OBJECT
public:
VpnItem(bool bAcitve, QWidget *parent = nullptr);
public:
QLabel * m_iconLabel = nullptr;
GrayInfoButton * m_infoLabel = nullptr;
FixLabel * m_titileLabel = nullptr;
QLabel * m_statusLabel = nullptr;
QToolButton* m_moreButton = nullptr;
QMenu* m_moreMenu = nullptr;
QAction* m_connectAction = nullptr;
QAction* m_deleteAction = nullptr;
QString m_uuid = "";
QString m_dbusPath = "";
void setHalfFillet(bool flag) {m_useHalfFillet = flag; repaint();}
public:
void startLoading();
void stopLoading();
void setConnectActionText(bool isAcitve);
bool m_isAcitve = false;
bool m_loading = false;
protected:
void paintEvent(QPaintEvent *event);
bool eventFilter(QObject *watched, QEvent *event);
private:
QTimer *m_waitTimer = nullptr;
bool m_useHalfFillet = false;
QList<QIcon> m_loadIcons;
int m_currentIconIndex=0;
private slots:
void updateIcon();
void onConnectTriggered();
void onDeletetTriggered();
Q_SIGNALS:
void connectActionTriggered();
void disconnectActionTriggered();
void deleteActionTriggered();
};
#endif // VPNITEM_H

View File

@ -0,0 +1,10 @@
INCLUDEPATH += $$PWD
include(../../src/backend/dbus-interface/dbus-interface.pri)
HEADERS += \
$$PWD/vpndbusadaptor.h
SOURCES += \
$$PWD/vpndbusadaptor.cpp
DISTFILES +=

View File

@ -0,0 +1,78 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp com.kylin.weather.xml -a VpnDbusAdaptor -c VpnDbusAdaptor -l MainWindow
*
* qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
*
* This is an auto-generated file.
* Do not edit! All changes made to it will be lost.
*/
#include "vpndbusadaptor.h"
#include <QtCore/QMetaObject>
#include <QtCore/QByteArray>
#include <QtCore/QList>
#include <QtCore/QMap>
#include <QtCore/QString>
#include <QtCore/QStringList>
#include <QtCore/QVariant>
/*
* Implementation of adaptor class VpnDbusAdaptor
*/
VpnDbusAdaptor::VpnDbusAdaptor(vpnObject *parent)
: QDBusAbstractAdaptor(parent)
{
qDBusRegisterMetaType<QMap<QString, bool> >();
qDBusRegisterMetaType<QMap<QString, int> >();
qDBusRegisterMetaType<QVector<QStringList> >();
setAutoRelaySignals(true);
}
//虚拟连接列表
QVector<QStringList> VpnDbusAdaptor::getVirtualList()
{
QVector<QStringList> vector;
parent()->getVirtualList(vector);
return vector;
}
//删除
void VpnDbusAdaptor::deleteVpn(QString uuid)
{
qDebug() << "delete vpn" << uuid;
parent()->deleteVpn(uuid);
}
//连接 根据网卡类型 参数1 0:lan 1:wlan 参数3 为ssid/uuid
void VpnDbusAdaptor::activateVpn(const QString& connUuid)
{
qDebug() << "activate vpn" << connUuid;
parent()->activateVpn(connUuid);
}
//断开连接 根据网卡类型 参数1 0:lan 1:wlan 参数3 为ssid/uuid
void VpnDbusAdaptor::deactivateVpn(const QString& connUuid)
{
qDebug() << "deactivate vpn" << connUuid;
parent()->deactivateVpn(connUuid);
}
void VpnDbusAdaptor::showKylinVpn()
{
parent()->onShowMainWindow();
}
void VpnDbusAdaptor::showVpnAddWidget()
{
qDebug() << "showVpnAddWidget";
parent()->showVpnAddWidget();
}
void VpnDbusAdaptor::showDetailPage(const QString& connUuid)
{
qDebug() << "showDetailPage vpn" << connUuid;
parent()->showDetailPage(connUuid);
}

View File

@ -0,0 +1,64 @@
/*
* This file was generated by qdbusxml2cpp version 0.8
* Command line was: qdbusxml2cpp com.kylin.weather.xml -a dbusadaptor -c DbusAdaptor -l MainWindow
*
* qdbusxml2cpp is Copyright (C) 2015 The Qt Company Ltd.
*
* This is an auto-generated file.
* This file may have been hand-edited. Look for HAND-EDIT comments
* before re-generating it.
*/
#ifndef VPNDBUSADAPTOR_H
#define VPNDBUSADAPTOR_H
#include <QtCore/QObject>
#include <QtDBus/QtDBus>
#include <QtDBus/QDBusMetaType>
#include "singlepage.h"
#include "kylinnetworkdeviceresource.h"
#include "kyvpnconnectoperation.h"
QT_BEGIN_NAMESPACE
class QByteArray;
template<class Key, class Value> class QMap;
class QString;
class QStringList;
class QVariant;
template<class T> class QVector;
QT_END_NAMESPACE
#include "vpnobject.h"
class VpnDbusAdaptor: public QDBusAbstractAdaptor
{
Q_OBJECT
Q_CLASSINFO("D-Bus Interface", "com.kylin.kylinvpn")
public:
VpnDbusAdaptor(vpnObject *parent);
inline vpnObject *parent() const
{ return static_cast<vpnObject *>(QObject::parent()); }
public Q_SLOTS:
QVector<QStringList> getVirtualList();
Q_NOREPLY void deleteVpn(QString uuid);
Q_NOREPLY void activateVpn(const QString& connUuid);
Q_NOREPLY void deactivateVpn(const QString& connUuid);
Q_NOREPLY void showVpnAddWidget();
Q_NOREPLY void showDetailPage(const QString& connUuid);
void showKylinVpn();
Q_SIGNALS:
void vpnAdd(QStringList info);
void vpnRemove(QString dbusPath);
void vpnUpdate(QStringList info);
void vpnActiveConnectionStateChanged(QString uuid, int status);
void activateFailed(QString errorMessage);
void deactivateFailed(QString errorMessage);
};
#endif

View File

@ -0,0 +1,11 @@
INCLUDEPATH += $$PWD
include(../../src/frontend/tools/tools.pri)
include(list-items/list-items.pri)
include(vpndetails/vpndetails.pri)
include(single-pages/single-pages.pri)
HEADERS += \
$$PWD/vpnobject.h
SOURCES += \
$$PWD/vpnobject.cpp

View File

@ -0,0 +1,10 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/listitem.h \
$$PWD/vpnlistitem.h
SOURCES += \
$$PWD/listitem.cpp \
$$PWD/vpnlistitem.cpp

View File

@ -0,0 +1,151 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "listitem.h"
#include <QDebug>
#define MAIN_LAYOUT_MARGINS 0,0,0,0
#define MAIN_LAYOUT_SPACING 0
#define ITEM_FRAME_MARGINS 12,6,16,6
#define ITEM_FRAME_SPACING 8
#define FRAME_WIDTH 404
#define INFO_ICON_WIDTH 16
#define INFO_ICON_HEIGHT 16
#define LIGHT_HOVER_COLOR QColor(240,240,240,255)
#define DARK_HOVER_COLOR QColor(15,15,15,255)
ListItem::ListItem(QWidget *parent) : QFrame(parent)
{
m_connectState = UnknownState;
initUI();
initConnection();
connect(qApp, &QApplication::paletteChanged, this, &ListItem::onPaletteChanged);
// m_itemFrame->installEventFilter(this);
}
ListItem::~ListItem()
{
if (nullptr != m_netButton) {
delete m_netButton;
m_netButton = nullptr;
}
if (nullptr != m_infoButton) {
delete m_infoButton;
m_infoButton = nullptr;
}
}
void ListItem::setName(const QString &name)
{
m_nameLabel->setText(name);
}
//仅无线调用,有线自己获取
void ListItem::setActive(const bool &isActive)
{
m_netButton->setActive(isActive);
m_isActive = isActive;
}
void ListItem::setConnectState(ConnectState state)
{
m_connectState = state;
}
void ListItem::mousePressEvent(QMouseEvent *event)
{
qDebug()<<"[ListItem]"<<"mousePressEvent";
if (event->button() == Qt::LeftButton) {
onNetButtonClicked();
} else if (event->button() == Qt::RightButton) {
onRightButtonClicked();
}
return QFrame::mousePressEvent(event);
}
void ListItem::enterEvent(QEvent *event)
{
}
void ListItem::leaveEvent(QEvent *event)
{
}
void ListItem::paintEvent(QPaintEvent *event)
{
}
void ListItem::initUI()
{
m_menu = new QMenu(this);//右键菜单
// m_menu->setStyleSheet("QMenu::item{border:3px; border-radius:3px}");
// m_menu->setStyleSheet("QMenu{border-radius:6px; margin:6px 6px 6px 6px}");
connect(m_menu, &QMenu::triggered, this, &ListItem::onMenuTriggered);
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setContentsMargins(MAIN_LAYOUT_MARGINS);
m_mainLayout->setSpacing(MAIN_LAYOUT_SPACING);
this->setLayout(m_mainLayout);
m_itemFrame = new QFrame(this);
m_itemFrame->setFixedWidth(FRAME_WIDTH);
m_hItemLayout = new QHBoxLayout(m_itemFrame);
m_hItemLayout->setContentsMargins(ITEM_FRAME_MARGINS);
m_hItemLayout->setSpacing(ITEM_FRAME_SPACING);
m_hItemLayout->setAlignment(Qt::AlignHCenter);
m_netButton = new RadioItemButton(m_itemFrame);
m_nameLabel = new QLabel(m_itemFrame);
m_nameLabel->setMinimumWidth(262);
m_infoButton = new InfoButton(m_itemFrame);
m_infoButton->setIconSize(QSize(INFO_ICON_WIDTH,INFO_ICON_HEIGHT));
m_hItemLayout->addWidget(m_netButton);
m_hItemLayout->addWidget(m_nameLabel);
m_hItemLayout->addStretch();
m_hItemLayout->addWidget(m_infoButton);
m_mainLayout->addWidget(m_itemFrame);
// this->setAutoFillBackground(true);
// this->setBackgroundRole(QPalette::Base);
// QPalette pal = qApp->palette();
// pal.setColor(QPalette::Window, qApp->palette().base().color());
// this->setPalette(pal);
}
void ListItem::initConnection()
{
connect(this->m_netButton, &RadioItemButton::clicked, this, &ListItem::onNetButtonClicked);
// connect(this->m_infoButton, &InfoButton::clicked, this, &ListItem::onInfoButtonClicked);
}
void ListItem::onPaletteChanged()
{
// QPalette pal = qApp->palette();
// pal.setColor(QPalette::Window, qApp->palette().base().color());
// this->setPalette(pal);
}

View File

@ -0,0 +1,87 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef LISTITEM_H
#define LISTITEM_H
#include <QFrame>
#include <QEvent>
#include <QHBoxLayout>
#include <QDebug>
#include <QMouseEvent>
#include <QMenu>
#include <QApplication>
#include "radioitembutton.h"
#include "infobutton.h"
typedef enum{
UnknownState = 0, /**< The active connection is in an unknown state */
Activating, /**< The connection is activating */
Activated, /**< The connection is activated */
Deactivating, /**< The connection is being torn down and cleaned up */
Deactivated /**< The connection is no longer active */
}ConnectState;
class ListItem : public QFrame
{
Q_OBJECT
public:
ListItem(QWidget *parent = nullptr);
~ListItem();
void setName(const QString &name);
void setActive(const bool &isActive);
void setConnectState(ConnectState state);
static void showDesktopNotify(const QString &message, QString soundName);
protected:
void mousePressEvent(QMouseEvent *event);
void enterEvent(QEvent *event);
void leaveEvent(QEvent *event);
void paintEvent(QPaintEvent *event);
virtual void onRightButtonClicked() = 0;
protected:
QFrame * m_itemFrame = nullptr;
QLabel * m_nameLabel = nullptr;
RadioItemButton * m_netButton = nullptr;
InfoButton * m_infoButton = nullptr;
bool m_isActive = false;
ConnectState m_connectState;
QMenu *m_menu = nullptr;
public:
QVBoxLayout * m_mainLayout = nullptr;
QHBoxLayout * m_hItemLayout = nullptr;
private:
void initUI();
void initConnection();
public Q_SLOTS:
virtual void onNetButtonClicked() = 0;
void onPaletteChanged();
virtual void onMenuTriggered(QAction *action)=0;
Q_SIGNALS:
void detailShow(bool isShow);
};
#endif // LISTITEM_H

View File

@ -0,0 +1,248 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "vpnlistitem.h"
#include "kylinconnectitem.h"
#include <QDebug>
#define LOG_FLAG "[VpnListItem]"
VpnListItem::VpnListItem(const KyConnectItem *vpnConnectItem, QWidget *parent):ListItem(parent)
{
m_connectOperation = new KyVpnConnectOperation(this);
m_deviceResource = new KyNetworkDeviceResourse(this);
connectItemCopy(vpnConnectItem);
m_nameLabel->setText(m_vpnConnectItem.m_connectName);
m_netButton->setButtonIcon(QIcon::fromTheme("ukui-vpn-symbolic"));
qDebug() << "VpnListItem init:" << m_vpnConnectItem.m_connectName << m_vpnConnectItem.m_connectState << m_vpnConnectItem.m_ifaceName;
if (Deactivated == m_vpnConnectItem.m_connectState || Activated == m_vpnConnectItem.m_connectState) {
m_netButton->stopLoading();
if (m_vpnConnectItem.m_connectState == Activated) {
setIcon(true);
} else {
setIcon(false);
}
} else {
m_netButton->startLoading();
}
m_itemFrame->installEventFilter(this);
connect(this->m_infoButton, &InfoButton::clicked, this, &VpnListItem::onInfoButtonClicked);
connect(m_menu, &QMenu::triggered, this, &VpnListItem::onMenuTriggered);
}
VpnListItem::VpnListItem(QWidget *parent) : ListItem(parent)
{
m_isActive = false;
m_netButton->setButtonIcon(QIcon::fromTheme("ukui-vpn-symbolic"));
setIcon(false);
const QString str=tr("Not connected");
m_nameLabel->setText(str);
this->m_infoButton->hide();
}
VpnListItem::~VpnListItem()
{
qDebug()<<"[LanPage] lan list item is deleted." << m_vpnConnectItem.m_connectName;
}
void VpnListItem::setIcon(bool isOn)
{
if (isOn) {
m_netButton->setActive(true); //设置图标显示不同颜色
} else {
m_netButton->setActive(false);
}
}
void VpnListItem::connectItemCopy(const KyConnectItem *vpnConnectItem)
{
if (vpnConnectItem) {
m_vpnConnectItem.m_connectName = vpnConnectItem->m_connectName;
m_vpnConnectItem.m_connectPath = vpnConnectItem->m_connectPath;
m_vpnConnectItem.m_connectState = vpnConnectItem->m_connectState;
m_vpnConnectItem.m_connectUuid = vpnConnectItem->m_connectUuid;
m_vpnConnectItem.m_ifaceName = vpnConnectItem->m_ifaceName;
m_vpnConnectItem.m_itemType = vpnConnectItem->m_itemType;
} else {
qDebug() << LOG_FLAG <<"the connect item is nullptr";
m_vpnConnectItem.m_connectName = "";
m_vpnConnectItem.m_connectPath = "";
m_vpnConnectItem.m_connectState = NetworkManager::ActiveConnection::State::Unknown;
m_vpnConnectItem.m_connectUuid = "";
m_vpnConnectItem.m_ifaceName = "";
m_vpnConnectItem.m_itemType = NetworkManager::ConnectionSettings::ConnectionType::Unknown;
}
}
void VpnListItem::activeConnection()
{
if (m_vpnConnectItem.m_connectUuid.isEmpty()) {
qDebug() << LOG_FLAG << "connect is empty, so can not connect or disconnect.";
return;
}
if (Deactivated == m_vpnConnectItem.m_connectState) {
//断开的连接,点击激活连接
m_connectOperation->activateVpnConnection(m_vpnConnectItem.m_connectUuid);
qDebug() << LOG_FLAG << "it will activate connection" << m_vpnConnectItem.m_connectName;
m_netButton->startLoading();
} else {
qDebug() << LOG_FLAG <<"the connection" << m_vpnConnectItem.m_connectName
<< "is not deactived, so it can not be operation.";
}
}
void VpnListItem::onNetButtonClicked()
{
if (m_vpnConnectItem.m_connectUuid.isEmpty()) {
qDebug() << LOG_FLAG << "connect is empty, so can not connect or disconnect.";
return;
}
if (Deactivated == m_vpnConnectItem.m_connectState) {
//断开的连接,点击激活连接
m_connectOperation->activateVpnConnection(m_vpnConnectItem.m_connectUuid);
qDebug() << LOG_FLAG << "it will activate connection" << m_vpnConnectItem.m_connectName;
m_netButton->startLoading();
} else {
qDebug() << LOG_FLAG <<"the connection" << m_vpnConnectItem.m_connectName
<< "is not deactived, so it can not be operation.";
}
}
void VpnListItem::onRightButtonClicked()
{
//右键点击事件
qDebug()<< LOG_FLAG <<"onRightButtonClicked";
if (!m_menu) {
return;
}
m_menu->clear();
if (Activated == m_vpnConnectItem.m_connectState || Activating == m_vpnConnectItem.m_connectState) {
m_menu->addAction(new QAction(tr("Disconnect"), this));
} else if (Deactivated == m_vpnConnectItem.m_connectState) {
m_menu->addAction(new QAction(tr("Connect"), this));
} else {
return;
}
m_menu->move(cursor().pos());
m_menu->show();
}
void VpnListItem::onMenuTriggered(QAction *action)
{
if (action->text() == tr("Connect")) {
this->onNetButtonClicked();
} else if (action->text() == tr("Disconnect")) {
m_connectOperation->deactivateVpnConnection(m_vpnConnectItem.m_connectName, m_vpnConnectItem.m_connectUuid);
qDebug() << LOG_FLAG << "it will disconnect connection" << m_vpnConnectItem.m_connectName;
m_netButton->startLoading();
}
}
bool VpnListItem::launchApp(QString desktopFile)
{
QDBusInterface appManagerDbusInterface(KYLIN_APP_MANAGER_NAME,
KYLIN_APP_MANAGER_PATH,
KYLIN_APP_MANAGER_INTERFACE,
QDBusConnection::sessionBus());
if (!appManagerDbusInterface.isValid()) {
qWarning()<<"appManagerDbusInterface init error";
return false;
} else {
QDBusReply<bool> reply = appManagerDbusInterface.call("LaunchApp", desktopFile);
return reply;
}
}
void VpnListItem::runExternalApp() {
if (!launchApp("nm-connection-editor.desktop")){
QString cmd = "nm-connection-editor";
QProcess process(this);
process.startDetached(cmd);
}
}
void VpnListItem::onInfoButtonClicked()
{
if (m_vpnConnectItem.m_itemType != NetworkManager::ConnectionSettings::ConnectionType::Vpn) {
runExternalApp();
return;
}
if(m_vpnDetail != nullptr){
m_vpnDetail->activateWindow();
return;
}
m_vpnDetail = new vpnDetail(m_vpnConnectItem.m_connectUuid, getConnectionName());
connect(m_vpnDetail, &vpnDetail::destroyed, [&](){
if (m_vpnDetail != nullptr) {
m_vpnDetail = nullptr;
}
});
m_vpnDetail->show();
}
void VpnListItem::updateConnectionState(ConnectState state)
{
m_vpnConnectItem.m_connectState = (NetworkManager::ActiveConnection::State)state;
if (Deactivated == state || Activated == state) {
m_netButton->stopLoading();
if (state == Activated) {
setIcon(true);
} else {
setIcon(false);
}
} else {
m_netButton->startLoading();
}
}
QString VpnListItem::getConnectionName()
{
return m_vpnConnectItem.m_connectName;
}
void VpnListItem::updateConnectionName(QString connectionName)
{
m_vpnConnectItem.m_connectName = connectionName;
m_nameLabel->setText(m_vpnConnectItem.m_connectName);
}
QString VpnListItem::getConnectionPath()
{
return m_vpnConnectItem.m_connectPath;
}
void VpnListItem::updateConnectionPath(QString connectionPath)
{
m_vpnConnectItem.m_connectPath = connectionPath;
}

View File

@ -0,0 +1,88 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef VPNLISTITEM_H
#define VPNLISTITEM_H
#include "listitem.h"
#include "kylinactiveconnectresource.h"
#include <QDBusInterface>
#include <QEvent>
#include <QAction>
#include <QProcess>
#include "vpndetails/vpndetail.h"
#include "kylinconnectresource.h"
//#include "kylinwiredconnectoperation.h"
#include "kyvpnconnectoperation.h"
#define KYLIN_APP_MANAGER_NAME "com.kylin.AppManager"
#define KYLIN_APP_MANAGER_PATH "/com/kylin/AppManager"
#define KYLIN_APP_MANAGER_INTERFACE "com.kylin.AppManager"
class VpnListItem : public ListItem
{
Q_OBJECT
public:
VpnListItem(const KyConnectItem *vpnConnectItem, QWidget *parent = nullptr);
VpnListItem(QWidget *parent = nullptr);
~VpnListItem();
public:
void updateConnectionState(ConnectState state);
QString getConnectionName();
void updateConnectionName(QString connectionName);
QString getConnectionPath();
void updateConnectionPath(QString connectionPath);
void activeConnection();
protected:
void setIcon(bool isOn);
void onRightButtonClicked();
bool launchApp(QString desktopFile);
void runExternalApp();
private:
void connectItemCopy(const KyConnectItem *vpnConnectItem);
public Q_SLOTS:
void onInfoButtonClicked();
private Q_SLOTS:
void onNetButtonClicked();
void onMenuTriggered(QAction *action);
private:
KyConnectItem m_vpnConnectItem;
KyVpnConnectOperation *m_connectOperation = nullptr;
KyNetworkDeviceResourse *m_deviceResource = nullptr;
QString m_deviceName = "";
vpnDetail *m_vpnDetail = nullptr;
};
#endif // VPNLISTITEM_H

View File

@ -0,0 +1,10 @@
INCLUDEPATH += $$PWD
HEADERS += \
$$PWD/vpnpage.h \
$$PWD/singlepage.h
SOURCES += \
$$PWD/vpnpage.cpp \
$$PWD/singlepage.cpp

View File

@ -0,0 +1,185 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "singlepage.h"
#include <qsettings.h>
#include <QDBusInterface>
#include <QLabel>
#include <QApplication>
#include <QDBusReply>
#include <KWindowEffects>
SinglePage::SinglePage(QWidget *parent) : QWidget(parent)
{
initUI();
initWindowProperties();
initTransparency();
}
SinglePage::~SinglePage()
{
}
void SinglePage::initUI()
{
m_mainLayout = new QVBoxLayout(this);
m_mainLayout->setContentsMargins(MAIN_LAYOUT_MARGINS);
m_mainLayout->setSpacing(MAIN_LAYOUT_SPACING);
this->setLayout(m_mainLayout);
m_titleFrame = new QFrame(this);
m_titleFrame->setFixedHeight(TITLE_FRAME_HEIGHT);
m_titleLayout = new QHBoxLayout(m_titleFrame);
m_titleLayout->setContentsMargins(TITLE_LAYOUT_MARGINS);
m_titleFrame->setLayout(m_titleLayout);
m_titleLabel = new QLabel(m_titleFrame);
m_titleLayout->addWidget(m_titleLabel);
m_titleLayout->addStretch();
m_netDivider = new Divider(this);
m_listFrame = new QFrame(this);
m_listLayout = new QVBoxLayout(m_listFrame);
m_listLayout->setContentsMargins(NET_LAYOUT_MARGINS);
m_listFrame->setLayout(m_listLayout);
m_listWidget = new QListWidget(m_listFrame);
m_listLayout->addWidget(m_listWidget);
m_setDivider = new Divider(this);
m_settingsFrame = new QFrame(this);
m_settingsFrame->setFixedHeight(TITLE_FRAME_HEIGHT);
m_settingsLayout = new QHBoxLayout(m_settingsFrame);
m_settingsLayout->setContentsMargins(SETTINGS_LAYOUT_MARGINS);
m_settingsLabel = new KyLable(m_settingsFrame);
m_settingsLabel->setCursor(Qt::PointingHandCursor);
m_settingsLabel->setText(tr("Settings"));
m_settingsLabel->setScaledContents(true);
m_settingsLayout->addWidget(m_settingsLabel);
m_settingsLayout->addStretch();
m_settingsFrame->setLayout(m_settingsLayout);
m_mainLayout->addWidget(m_titleFrame);
m_mainLayout->addWidget(m_netDivider);
m_mainLayout->addWidget(m_listFrame);
m_mainLayout->addWidget(m_setDivider);
m_mainLayout->addWidget(m_settingsFrame);
}
void SinglePage::initWindowProperties()
{
QPalette pal = m_listFrame->palette();
pal.setBrush(QPalette::Base, QColor(0,0,0,0)); //背景透明
m_listFrame->setPalette(pal);
this->setFixedWidth(MAX_WIDTH);
this->setAttribute(Qt::WA_TranslucentBackground);
this->setProperty("useStyleWindowManager", false); //禁用拖动
//绘制毛玻璃特效
QString platform = QGuiApplication::platformName();
if(!platform.startsWith(QLatin1String("wayland"),Qt::CaseInsensitive))
{
QPainterPath path;
auto rect = this->rect();
path.addRoundedRect(rect, 12, 12);
path.addRect(rect);
KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(path.toFillPolygon().toPolygon())); //背景模糊
}
}
void SinglePage::showDesktopNotify(const QString &message, QString soundName)
{
QDBusInterface iface("org.freedesktop.Notifications",
"/org/freedesktop/Notifications",
"org.freedesktop.Notifications",
QDBusConnection::sessionBus());
QStringList actions; //跳转动作
actions.append("kylin-vpn");
actions.append("default"); //默认动作:点击消息体时打开麒麟录音
QMap<QString, QVariant> hints;
if (!soundName.isEmpty()) {
hints.insert("sound-name",soundName); //添加声音
}
QList<QVariant> args;
args<<(tr("Kylin VPN"))
<<((unsigned int) 0)
<<QString("gnome-dev-ethernet")
<<tr("kylin vpn applet desktop message") //显示的是什么类型的信息
<<message //显示的具体信息
<<actions
<<hints
<<(int)-1;
iface.callWithArgumentList(QDBus::AutoDetect,"Notify",args);
}
void SinglePage::paintEvent(QPaintEvent *event) {
Q_UNUSED(event);
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing);
painter.setPen(Qt::transparent);
QColor col = qApp->palette().window().color();
QPainterPath rectPath;
col.setAlphaF(m_transparency);
rectPath.addRoundedRect(this->rect(),12,12);
painter.setBrush(col);
painter.drawPath(rectPath);
KWindowEffects::enableBlurBehind(this->winId(), true, QRegion(rectPath.toFillPolygon().toPolygon())); //背景模糊
}
void SinglePage::initTransparency()
{
if(QGSettings::isSchemaInstalled(QByteArray(TRANSPARENCY_GSETTINGS))) {
m_transGsettings = new QGSettings(QByteArray(TRANSPARENCY_GSETTINGS));
if(m_transGsettings->keys().contains(TRANSPARENCY)) {
m_transparency = m_transGsettings->get(TRANSPARENCY).toDouble() + 0.15;
m_transparency = (m_transparency > 1) ? 1 : m_transparency;
connect(m_transGsettings, &QGSettings::changed, this, &SinglePage::onTransChanged);
}
}
}
void SinglePage::onTransChanged()
{
m_transparency = m_transGsettings->get("transparency").toDouble() + 0.15;
m_transparency = (m_transparency > 1) ? 1 : m_transparency;
paintWithTrans();
}
void SinglePage::paintWithTrans()
{
QPalette pal = this->palette();
QColor color = qApp->palette().base().color();
color.setAlphaF(m_transparency);
pal.setColor(QPalette::Window, color);
this->setPalette(pal);
}
void SinglePage::keyPressEvent(QKeyEvent *event)
{
if (event->key() == Qt::Key_Escape) {
this->hide();
}
return QWidget::keyPressEvent(event);
}

View File

@ -0,0 +1,112 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef SINGLEPAGE_H
#define SINGLEPAGE_H
#include "divider.h"
#include "kylable.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QFormLayout>
#include <QLabel>
#include <QScrollArea>
#include <QListWidget>
#include <QDir>
#include <QComboBox>
#include <QEvent>
#include <QProcess>
#include <QDebug>
#include "kylinnetworkdeviceresource.h"
#include "kwidget.h"
#include "kswitchbutton.h"
using namespace kdk;
#define MAIN_LAYOUT_MARGINS 0,0,0,0
#define MAIN_LAYOUT_SPACING 0
#define TITLE_FRAME_HEIGHT 60 //TabWidget的tab和widget有间隙和设计稿看起来一致就不能设为设计稿里的高度
#define TITLE_LAYOUT_MARGINS 24,0,24,0
#define NET_LAYOUT_MARGINS 8,8,8,8
#define TEXT_HEIGHT 20
#define SETTINGS_LAYOUT_MARGINS 23,0,24,0
#define MAX_ITEMS 4
#define MAX_WIDTH 412
#define MIN_WIDTH 404
#define SCROLL_STEP 4
#define TRANSPARENCY "transparency"
#define TRANSPARENCY_GSETTINGS "org.ukui.control-center.personalise"
class SinglePage : public QWidget
{
Q_OBJECT
public:
explicit SinglePage(QWidget *parent = nullptr);
~SinglePage();
static void showDesktopNotify(const QString &message, QString soundName);
Q_SIGNALS:
void activateFailed(QString errorMessage);
void deactivateFailed(QString errorMessage);
private Q_SLOTS:
void onTransChanged();
protected:
void paintEvent(QPaintEvent *event);
void keyPressEvent(QKeyEvent *event);
protected:
void initUI();
void initTransparency();
void paintWithTrans();
private:
void initWindowProperties();
protected:
QVBoxLayout * m_mainLayout = nullptr;
QLabel * m_titleLabel = nullptr;
QFrame * m_titleFrame = nullptr;
QHBoxLayout * m_titleLayout = nullptr;
QFrame * m_listFrame = nullptr;
QListWidget * m_listWidget = nullptr;
QVBoxLayout * m_listLayout = nullptr;
QFrame * m_settingsFrame = nullptr;
QHBoxLayout * m_settingsLayout = nullptr;
KyLable * m_settingsLabel = nullptr;
Divider * m_netDivider = nullptr;
Divider * m_setDivider = nullptr;
QGSettings * m_transGsettings = nullptr;
double m_transparency = 1.0; //透明度
};
#endif // TABPAGE_H

View File

@ -0,0 +1,702 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "vpnpage.h"
#include <QDebug>
#include <QScrollBar>
#include "windowmanager/windowmanager.h"
VpnPage::VpnPage(QWidget *parent) : SinglePage(parent)
{
m_activeResourse = new KyActiveConnectResourse(this);
m_connectResourse = new KyConnectResourse(this);
m_vpnConnectOperation = new KyVpnConnectOperation(this);
initUI();
initVpnArea();
installEventFilter(this);
connect(m_activeResourse, &KyActiveConnectResourse::stateChangeReason, this, &VpnPage::onConnectionStateChange);
connect(m_activeResourse, &KyActiveConnectResourse::activeConnectRemove, this, [=] (QString activeConnectUuid) {
sendVpnStateChangeSignal(activeConnectUuid,Deactivated);
} );
connect(m_connectResourse, &KyConnectResourse::connectionAdd, this, &VpnPage::onAddConnection);
connect(m_connectResourse, &KyConnectResourse::connectionRemove, this, &VpnPage::onRemoveConnection);
connect(m_connectResourse, &KyConnectResourse::connectionUpdate, this, &VpnPage::onUpdateConnection);
connect(m_vpnConnectOperation, &KyVpnConnectOperation::activateConnectionError, this, &VpnPage::activateFailed);
connect(m_vpnConnectOperation, &KyVpnConnectOperation::deactivateConnectionError, this, &VpnPage::deactivateFailed);
connect(KWindowSystem::self(), &KWindowSystem::activeWindowChanged, this, [&](WId activeWindowId){
if (activeWindowId != this->winId() && activeWindowId != 0) {
hide();
}
});
}
VpnPage::~VpnPage()
{
}
void VpnPage::deleteConnectionMapItem(QMap<QString, QListWidgetItem *> &connectMap,
QListWidget *vpnListWidget, QString uuid)
{
QListWidgetItem *p_listWidgetItem = connectMap.value(uuid);
if (p_listWidgetItem) {
connectMap.remove(uuid);
VpnListItem *p_vpnItem = (VpnListItem *)vpnListWidget->itemWidget(p_listWidgetItem);
vpnListWidget->removeItemWidget(p_listWidgetItem);
delete p_vpnItem;
p_vpnItem = nullptr;
delete p_listWidgetItem;
p_listWidgetItem = nullptr;
}
return;
}
void VpnPage::clearConnectionMap(QMap<QString, QListWidgetItem *> &connectMap,
QListWidget *vpnListWidget)
{
QMap<QString, QListWidgetItem *>::iterator iter;
iter = connectMap.begin();
while (iter != connectMap.end()) {
qDebug()<<"[VpnPage] clear connection map item"<< iter.key();
QListWidgetItem *p_widgetItem = iter.value();
VpnListItem *p_vpnItem = (VpnListItem *)vpnListWidget->itemWidget(p_widgetItem);
vpnListWidget->removeItemWidget(p_widgetItem);
delete p_vpnItem;
p_vpnItem = nullptr;
delete p_widgetItem;
p_widgetItem = nullptr;
iter = connectMap.erase(iter);
}
return;
}
void VpnPage::constructItemArea()
{
QList<KyConnectItem *> activedList;
QList<KyConnectItem *> netList;
activedList.clear();
netList.clear();
clearConnectionMap(m_activeItemMap, m_listWidget);
clearConnectionMap(m_vpnItemMap, m_listWidget);
m_connectResourse->getVpnAndVirtualConnections(netList);
KyConnectItem *p_newItem = nullptr;
if (!netList.isEmpty()) {
for (int index = 0; index < netList.size(); index++) {
KyConnectItem *p_netConnectionItem = netList.at(index);
p_newItem = m_activeResourse->getActiveConnectionByUuid(p_netConnectionItem->m_connectUuid);
if (p_newItem == nullptr) {
if (m_vpnItemMap.contains(p_netConnectionItem->m_connectUuid)) {
qDebug()<<LOG_FLAG << "has contain uuid" << p_netConnectionItem->m_connectUuid;
}
QListWidgetItem *p_listWidgetItem = addNewItem(p_netConnectionItem, m_listWidget);
m_vpnItemMap.insert(p_netConnectionItem->m_connectUuid, p_listWidgetItem);
} else {
if (m_activeItemMap.contains(p_netConnectionItem->m_connectUuid)) {
qDebug()<<LOG_FLAG << "has contain uuid" << p_netConnectionItem->m_connectUuid;
}
QListWidgetItem *p_listWidgetItem = addNewItem(p_newItem, m_listWidget);
m_activeItemMap.insert(p_netConnectionItem->m_connectUuid, p_listWidgetItem);
}
delete p_netConnectionItem;
p_netConnectionItem = nullptr;
}
}
if (QGSettings::isSchemaInstalled(GSETTINGS_VPNICON_VISIBLE)) {
QGSettings vpnGsettings(GSETTINGS_VPNICON_VISIBLE);
if (vpnGsettings.keys().contains(QString(VISIBLE))) {
if (!netList.isEmpty()) {
vpnGsettings.set(VISIBLE, true);
} else {
vpnGsettings.set(VISIBLE, false);
}
}
}
if (m_listWidget->count() <= MAX_ITEMS) {
m_listFrame->setFixedWidth(MIN_WIDTH);
} else {
m_listFrame->setFixedWidth(MAX_WIDTH);
}
}
void VpnPage::initVpnArea()
{
constructItemArea();
}
void VpnPage::resetPageHeight()
{
int height = 0;
int count = m_listWidget->count();
m_listFrame->setFixedHeight((count >= 4) ? (MAX_ITEMS * ITEM_HEIGHT + ITEM_SPACE) : (count * ITEM_HEIGHT + ITEM_SPACE));
if (count == 0) {
m_listWidget->setHidden(true);
m_listFrame->setHidden(true);
m_netDivider->setHidden(true);
} else {
m_listWidget->show();
m_listFrame->show();
m_netDivider->show();
}
for (int i = 0; i < m_mainLayout->count(); i ++) {
QWidget *w = m_mainLayout->itemAt(i)->widget();
if (w != nullptr && w->isHidden() != true) {
height += w->height();
}
}
this->setFixedHeight(height + PAGE_SPACE);
}
bool VpnPage::removeConnectionItem(QMap<QString, QListWidgetItem *> &connectMap,
QListWidget *vpnListWidget, QString path)
{
QMap<QString, QListWidgetItem *>::iterator iter;
for (iter = connectMap.begin(); iter != connectMap.end(); ++iter) {
QListWidgetItem *p_listWidgetItem = iter.value();
VpnListItem *p_vpnItem = (VpnListItem*)vpnListWidget->itemWidget(p_listWidgetItem);
if (p_vpnItem->getConnectionPath() == path) {
qDebug()<<"[VpnPage] Remove a connection from list";
vpnListWidget->removeItemWidget(p_listWidgetItem);
delete p_vpnItem;
p_vpnItem = nullptr;
delete p_listWidgetItem;
p_listWidgetItem = nullptr;
iter = connectMap.erase(iter);
if (m_listWidget->count() <= MAX_ITEMS) {
m_listFrame->setFixedWidth(MIN_WIDTH);
}
return true;
}
}
return false;
}
void VpnPage::onRemoveConnection(QString path) //删除时后端会自动断开激活,将其从未激活列表中删除
{
//for dbus
qDebug() << "[VpnPage] emit lanRemove because onRemoveConnection " << path;
Q_EMIT vpnRemove(path);
removeConnectionItem(m_vpnItemMap, m_listWidget, path);
removeConnectionItem(m_activeItemMap, m_listWidget, path);
resetPageHeight();
resetWindowPosition();
this->update();
}
void VpnPage::onAddConnection(QString uuid) //新增一个有线连接,将其加入到激活列表
{
if (!m_connectResourse->isVirtualConncection(uuid)) {
return;
}
KyConnectItem *p_newItem = nullptr;
p_newItem = m_connectResourse->getConnectionItemByUuid(uuid);
if (nullptr == p_newItem) {
return;
}
sendVpnAddSignal(p_newItem);
qDebug()<<"[VpnPage] Add a new connection, name:"<<p_newItem->m_connectName;
QListWidgetItem *p_listWidgetItem = insertNewItem(p_newItem, m_listWidget);
if (m_vpnItemMap.contains(p_newItem->m_connectUuid)) {
qDebug()<<LOG_FLAG << "the connection is exist" << p_newItem->m_connectUuid;
}
m_vpnItemMap.insert(p_newItem->m_connectUuid, p_listWidgetItem);
delete p_newItem;
p_newItem = nullptr;
if (m_listWidget->count() >= MAX_ITEMS) {
m_listFrame->setFixedWidth(MAX_WIDTH);
}
resetPageHeight();
resetWindowPosition();
this->update();
return;
}
void VpnPage::onShowControlCenter()
{
QProcess process;
process.startDetached("ukui-control-center -m vpn");
}
void VpnPage::initUI()
{
m_titleLabel->setText(tr("VPN"));
// m_listFrame->setMaximumHeight(MAX_ITEMS * ITEM_HEIGHT + ITEM_SPACE);
m_listWidget->setFrameShape(QFrame::Shape::NoFrame);
m_listWidget->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
m_listWidget->setVerticalScrollMode(QAbstractItemView::ScrollMode::ScrollPerPixel);
m_listWidget->verticalScrollBar()->setProperty("drawScrollBarGroove",false); //去除滚动条的外侧黑框
m_listWidget->verticalScrollBar()->setSingleStep(SCROLL_STEP);
m_listWidget->verticalScrollBar()->setContextMenuPolicy(Qt::NoContextMenu);
m_settingsLabel->setText(tr("VPN Settings"));
m_settingsLabel->installEventFilter(this);
}
QListWidgetItem *VpnPage::insertNewItem(KyConnectItem *itemData, QListWidget *listWidget)
{
int index = 0;
for(index = 0; index < m_listWidget->count(); index++) {
QListWidgetItem *p_listWidgetItem = m_listWidget->item(index);
VpnListItem *p_vpnItem = (VpnListItem *)m_listWidget->itemWidget(p_listWidgetItem);
QString name1 = p_vpnItem->getConnectionName();
QString name2 = itemData->m_connectName;
if (QString::compare(name1, name2, Qt::CaseInsensitive) > 0) {
break;
}
}
QListWidgetItem *p_sortListWidgetItem = new QListWidgetItem();
p_sortListWidgetItem->setFlags(p_sortListWidgetItem->flags() & (~Qt::ItemIsSelectable)); //设置不可被选中
p_sortListWidgetItem->setSizeHint(QSize(listWidget->width(),ITEM_HEIGHT));
listWidget->insertItem(index, p_sortListWidgetItem);
VpnListItem *p_sortLanItem = nullptr;
p_sortLanItem = new VpnListItem(itemData);
listWidget->setItemWidget(p_sortListWidgetItem, p_sortLanItem);
return p_sortListWidgetItem;
}
QListWidgetItem *VpnPage::addNewItem(KyConnectItem *itemData, QListWidget *listWidget)
{
QListWidgetItem *p_listWidgetItem = new QListWidgetItem();
p_listWidgetItem->setFlags(p_listWidgetItem->flags() & (~Qt::ItemIsSelectable));
p_listWidgetItem->setSizeHint(QSize(listWidget->width() - 16, ITEM_HEIGHT));
listWidget->addItem(p_listWidgetItem);
VpnListItem *p_vpnItem = nullptr;
if (itemData != nullptr) {
p_vpnItem = new VpnListItem(itemData);
qDebug() << "[VpnPage] addNewItem, connection: " << itemData->m_connectName;
} else {
p_vpnItem = new VpnListItem();
qDebug() << "[VpnPage] Add nullItem!";
}
listWidget->setItemWidget(p_listWidgetItem, p_vpnItem);
return p_listWidgetItem;
}
void VpnPage::updateActivatedConnectionArea(KyConnectItem *p_newItem)
{
if (m_activeItemMap.contains(p_newItem->m_connectUuid)) {
return;
}
deleteConnectionMapItem(m_vpnItemMap, m_listWidget, p_newItem->m_connectUuid);
qDebug()<<"[VpnPage]update active connection item"<<p_newItem->m_connectName;
deleteConnectionMapItem(m_activeItemMap, m_listWidget, p_newItem->m_connectUuid);
QListWidgetItem *p_listWidgetItem = addNewItem(p_newItem, m_listWidget);
m_activeItemMap.insert(p_newItem->m_connectUuid, p_listWidgetItem);
if (m_listWidget->count() <= MAX_ITEMS) {
m_listFrame->setFixedWidth(MIN_WIDTH);
}
return;
}
void VpnPage::updateConnectionArea(KyConnectItem *p_newItem)
{
if (m_vpnItemMap.contains(p_newItem->m_connectUuid)) {
return;
}
deleteConnectionMapItem(m_activeItemMap, m_listWidget, p_newItem->m_connectUuid);
qDebug()<<"[VpnPage] update connection item"<<p_newItem->m_connectName;
QListWidgetItem *p_listWidgetItem = insertNewItem(p_newItem, m_listWidget);
m_vpnItemMap.insert(p_newItem->m_connectUuid, p_listWidgetItem);
if (m_listWidget->count() <= MAX_ITEMS) {
m_listFrame->setFixedWidth(MIN_WIDTH);
} else {
m_listFrame->setFixedWidth(MAX_WIDTH);
}
}
void VpnPage::updateConnectionState(QMap<QString, QListWidgetItem *> &connectMap,
QListWidget *vpnListWidget, QString uuid, ConnectState state)
{
qDebug() << LOG_FLAG << "update connection state";
QListWidgetItem *p_listWidgetItem = connectMap.value(uuid);
if (p_listWidgetItem) {
VpnListItem *p_vpnItem = (VpnListItem *)vpnListWidget->itemWidget(p_listWidgetItem);
p_vpnItem->updateConnectionState(state);
}
}
void VpnPage::onConnectionStateChange(QString uuid,
NetworkManager::ActiveConnection::State state,
NetworkManager::ActiveConnection::Reason reason)
{
//VpnPage函数内持续监听连接状态的变化并记录供其他函数调用获取状态
if (!m_connectResourse->isVirtualConncection(uuid)) {
qDebug() << "[VpnPage] connection state change signal but not vpn";
return;
}
sendVpnStateChangeSignal(uuid, (ConnectState)state);
if (m_activeItemMap.keys().contains(uuid) && state == NetworkManager::ActiveConnection::State::Activated) {
return;
}
qDebug()<<"[VpnPage] connection uuid"<< uuid
<< "state change slot:"<< state;
KyConnectItem *p_newItem = nullptr;
QString deviceName = "";
QString ssid = "";
if (state == NetworkManager::ActiveConnection::State::Activated) {
p_newItem = m_activeResourse->getActiveConnectionByUuid(uuid);
if (nullptr == p_newItem) {
qWarning()<<"[VpnPage] get active connection failed, connection uuid" << uuid;
return;
}
ssid = p_newItem->m_connectName;
updateActivatedConnectionArea(p_newItem);
updateConnectionState(m_activeItemMap, m_listWidget, uuid, (ConnectState)state);
} else if (state == NetworkManager::ActiveConnection::State::Deactivated) {
p_newItem = m_connectResourse->getConnectionItemByUuid(uuid);
qDebug() << "[VpnPage] deactivated reason" << reason;
if (nullptr == p_newItem) {
qWarning()<<"[VpnPage] get active connection failed, connection uuid" << uuid;
return;
}
ssid = p_newItem->m_connectName;
updateConnectionArea(p_newItem);
updateConnectionState(m_vpnItemMap, m_listWidget, uuid, (ConnectState)state);
} else if (state == NetworkManager::ActiveConnection::State::Activating) {
updateConnectionState(m_vpnItemMap, m_listWidget, uuid, (ConnectState)state);
} else if (state == NetworkManager::ActiveConnection::State::Deactivating) {
updateConnectionState(m_activeItemMap, m_listWidget, uuid, (ConnectState)state);
}
Q_EMIT vpnActiveConnectionStateChanged(uuid, state);
if (p_newItem) {
delete p_newItem;
p_newItem = nullptr;
}
return;
}
void VpnPage::getVirtualList(QVector<QStringList> &vector)
{
QList<KyConnectItem *> netConnectList;
vector.clear();
m_connectResourse->getVpnAndVirtualConnections(netConnectList); //未激活列表的显示
if (!netConnectList.isEmpty()) {
for (int i = 0; i < netConnectList.size(); i++) {
KyConnectItem *p_newItem = nullptr;
KyConnectItem *p_netConnectionItem = netConnectList.at(i);
p_newItem = m_activeResourse->getActiveConnectionByUuid(p_netConnectionItem->m_connectUuid);
NetworkManager::ActiveConnection::State state = p_netConnectionItem->m_connectState;
if (p_newItem != nullptr) {
state = NetworkManager::ActiveConnection::Activated;
}
vector.append(QStringList() << netConnectList.at(i)->m_connectName
<< netConnectList.at(i)->m_connectUuid
<< netConnectList.at(i)->m_connectPath
<< QString::number(state));
}
}
return;
}
void VpnPage::sendVpnUpdateSignal(KyConnectItem *p_connectItem)
{
QStringList info;
info << p_connectItem->m_connectName << p_connectItem->m_connectUuid << p_connectItem->m_connectPath;
Q_EMIT vpnUpdate(info);
return;
}
void VpnPage::sendVpnAddSignal(KyConnectItem *p_connectItem)
{
QStringList info;
KyConnectItem *p_newItem = nullptr;
p_newItem = m_activeResourse->getActiveConnectionByUuid(p_connectItem->m_connectUuid);
NetworkManager::ActiveConnection::State state = p_connectItem->m_connectState;
if (p_newItem != nullptr) {
state = NetworkManager::ActiveConnection::Activated;
}
info << p_connectItem->m_connectName
<< p_connectItem->m_connectUuid
<< p_connectItem->m_connectPath
<< QString::number(state);
qDebug() << "[VpnPage] emit vpnAdd because addConnection ";
Q_EMIT vpnAdd(info);
return;
}
void VpnPage::sendVpnStateChangeSignal(QString uuid, ConnectState state)
{
if (state == Activating || state == Deactivating) {
if (m_activeResourse->connectionIsVirtual(uuid)) {
return;
}
}
Q_EMIT this->vpnConnectChanged(state);
return;
}
void VpnPage::updateConnectionProperty(KyConnectItem *p_connectItem)
{
QString newUuid = p_connectItem->m_connectUuid;
if (m_vpnItemMap.contains(newUuid)) {
QListWidgetItem *p_listWidgetItem = m_vpnItemMap.value(newUuid);
VpnListItem *p_vpnItem = (VpnListItem*)m_listWidget->itemWidget(p_listWidgetItem);
if (p_connectItem->m_connectName != p_vpnItem->getConnectionName()){
//只要名字改变就要删除,重新插入,主要是为了排序
deleteConnectionMapItem(m_vpnItemMap, m_listWidget, newUuid);
QListWidgetItem *p_sortListWidgetItem = insertNewItem(p_connectItem, m_listWidget);
if (m_vpnItemMap.contains(newUuid)) {
qDebug()<<LOG_FLAG << "has contained connection" << newUuid;
}
m_vpnItemMap.insert(newUuid, p_sortListWidgetItem);
} else if (p_connectItem->m_connectPath != p_vpnItem->getConnectionPath()) {
p_vpnItem->updateConnectionPath(p_connectItem->m_connectPath);
}
} else if (!m_activeItemMap.contains(newUuid)){
if (p_connectItem->m_ifaceName.isEmpty()) {
QListWidgetItem *p_listWidgetItem = insertNewItem(p_connectItem, m_listWidget);
if (m_vpnItemMap.contains(newUuid)) {
qDebug()<<LOG_FLAG << "has contained connection uuid" << newUuid;
}
m_vpnItemMap.insert(newUuid, p_listWidgetItem);
}
} else {
qWarning() << LOG_FLAG << newUuid <<" is in activemap, so not process.";
}
return;
}
void VpnPage::updateActiveConnectionProperty(KyConnectItem *p_connectItem)
{
QString newUuid = p_connectItem->m_connectUuid;
if (m_activeItemMap.contains(newUuid)) {
QListWidgetItem *p_listWidgetItem = m_activeItemMap.value(newUuid);
VpnListItem *p_vpnItem = (VpnListItem *)m_listWidget->itemWidget(p_listWidgetItem);
if (p_vpnItem->getConnectionName() != p_connectItem->m_connectName) {
p_vpnItem->updateConnectionName(p_connectItem->m_connectName);
}
if (p_vpnItem->getConnectionName() != p_connectItem->m_connectPath) {
p_vpnItem->updateConnectionPath(p_connectItem->m_connectPath);
}
}
return;
}
void VpnPage::onUpdateConnection(QString uuid)
{
if (!m_connectResourse->isVirtualConncection(uuid)) {
return;
}
qDebug() << "[VpnPage]:Connection property Changed." << Q_FUNC_INFO << __LINE__;
KyConnectItem *p_newItem = nullptr;
if (m_connectResourse->isActivatedConnection(uuid)) {
p_newItem = m_activeResourse->getActiveConnectionByUuid(uuid);
if (nullptr == p_newItem) {
qWarning()<<"[VpnPage] get item failed, when update activate connection."
<<"connection uuid" << uuid;
return;
}
updateActiveConnectionProperty(p_newItem);
} else {
p_newItem = m_connectResourse->getConnectionItemByUuid(uuid);
if (nullptr == p_newItem) {
qWarning()<<"[VpnPage] get item failed, when update connection."
<<"connection uuid"<<uuid;
return;
}
updateConnectionProperty(p_newItem);
}
sendVpnUpdateSignal(p_newItem);
delete p_newItem;
p_newItem = nullptr;
return;
}
bool VpnPage::eventFilter(QObject *watched, QEvent *event)
{
if (watched == m_settingsLabel) {
if (event->type() == QEvent::MouseButtonRelease) {
onShowControlCenter();
}
}
return QWidget::eventFilter(watched, event);
}
void VpnPage::deleteVpn(const QString &connUuid)
{
qDebug() << "[VpnPage] deleteVpn" << connUuid;
if (connUuid == nullptr) {
return;
}
m_vpnConnectOperation->deleteVpnConnect(connUuid);
}
void VpnPage::activateVpn(const QString& connUuid)
{
if (m_vpnItemMap.contains(connUuid)) {
qDebug() << "[VpnPage] activateVpn" << connUuid;
m_vpnConnectOperation->activateVpnConnection(connUuid);
}
}
void VpnPage::deactivateVpn(const QString& connUuid)
{
qDebug() << "[VpnPage] deactivateVpn" << connUuid;
QString name("");
m_vpnConnectOperation->deactivateVpnConnection(name, connUuid);
}
void VpnPage::showDetailPage(QString uuid)
{
QListWidgetItem * vpnlistItem = m_vpnItemMap.value(uuid);
VpnListItem *vpnItem = (VpnListItem *)m_listWidget->itemWidget(vpnlistItem);
vpnItem->onInfoButtonClicked();
}
void VpnPage::showUI()
{
//2209中窗管在hide界面时会刷新属性需要重新设置无图标属性
const KWindowInfo info(this->winId(), NET::WMState);
if (!info.hasState(NET::SkipTaskbar) || !info.hasState(NET::SkipPager)) {
KWindowSystem::setState(this->winId(), NET::SkipTaskbar | NET::SkipPager);
}
resetPageHeight();
showNormal();
raise();
activateWindow();
resetWindowPosition();
return;
}
void VpnPage::resetWindowPosition()
{
#define MARGIN 4
#define PANEL_TOP 1
#define PANEL_LEFT 2
#define PANEL_RIGHT 3
//#define PANEL_BOTTOM 4
if (!m_positionInterface) {
m_positionInterface = new QDBusInterface("org.ukui.panel",
"/panel/position",
"org.ukui.panel",
QDBusConnection::sessionBus());
}
QRect rect;
QDBusReply<QVariantList> reply = m_positionInterface->call("GetPrimaryScreenGeometry");
//reply获取的参数共5个分别是 主屏可用区域的起点x坐标主屏可用区域的起点y坐标主屏可用区域的宽度主屏可用区域高度任务栏位置
if (!m_positionInterface->isValid() || !reply.isValid() || reply.value().size() < 5) {
qCritical() << QDBusConnection::sessionBus().lastError().message();
kdk::WindowManager::setGeometry(this->windowHandle(), QRect(0, 0, this->width(), this->height()));
return;
}
QVariantList position_list = reply.value();
int position = position_list.at(4).toInt();
switch(position){
case PANEL_TOP:
//任务栏位于上方
rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN,
position_list.at(1).toInt() + MARGIN,
this->width(), this->height());
break;
//任务栏位于左边
case PANEL_LEFT:
rect = QRect(position_list.at(0).toInt() + MARGIN,
position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN,
this->width(), this->height());
break;
//任务栏位于右边
case PANEL_RIGHT:
rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN,
position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN,
this->width(), this->height());
break;
//任务栏位于下方
default:
rect = QRect(position_list.at(0).toInt() + position_list.at(2).toInt() - this->width() - MARGIN,
position_list.at(1).toInt() + reply.value().at(3).toInt() - this->height() - MARGIN,
this->width(), this->height());
break;
}
kdk::WindowManager::setGeometry(this->windowHandle(), rect);
qDebug() << " Position of ukui-panel is " << position << "; Position of mainwindow is " << this->geometry() << "." << Q_FUNC_INFO << __LINE__;
}

View File

@ -0,0 +1,137 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef VPNPAGE_H
#define VPNPAGE_H
#include "divider.h"
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QLabel>
#include <QScrollArea>
#include <QListWidget>
#include <QMap>
#include <QGSettings>
#include <KWindowSystem>
#include "list-items/listitem.h"
#include "list-items/vpnlistitem.h"
#include "single-pages/singlepage.h"
#define VPNPAGE_LAYOUT_MARGINS 0,0,0,0
#define VPN_LIST_SPACING 0
#define ITEM_HEIGHT 50
#define ITEM_SPACE 16
#define PAGE_SPACE 22
#define LOG_FLAG "[VpnPage]"
#define VISIBLE "visible"
const QByteArray GSETTINGS_VPNICON_VISIBLE = "org.ukui.kylin-nm.vpnicon";
class VpnListItem;
class VpnPage : public SinglePage
{
Q_OBJECT
public:
explicit VpnPage(QWidget *parent = nullptr);
~VpnPage();
//for dbus
void getVirtualList(QVector<QStringList> &vector);
void deleteVpn(const QString &connUuid);
void activateVpn(const QString& connUuid);
void deactivateVpn(const QString& connUuid);
void showDetailPage(QString uuid);
protected:
bool eventFilter(QObject *watched, QEvent *event);
private:
void initUI();
void initVpnArea();
void resetPageHeight();
inline void initDeviceCombox() { return; }
QListWidgetItem *insertNewItem(KyConnectItem *itemData, QListWidget *listWidget);
QListWidgetItem *addNewItem(KyConnectItem *itemData, QListWidget *listWidget);
bool removeConnectionItem(QMap<QString, QListWidgetItem *> &connectMap,
QListWidget *vpnListWidget, QString path);
void constructItemArea();
void updateConnectionArea(KyConnectItem *p_newItem);
void updateActivatedConnectionArea(KyConnectItem *p_newItem);
void updateConnectionState(QMap<QString, QListWidgetItem *> &connectMap,
QListWidget *vpnListWidget, QString uuid, ConnectState state);
void updateActiveConnectionProperty(KyConnectItem *p_connectItem);
void updateConnectionProperty(KyConnectItem *p_connectItem);
void sendVpnUpdateSignal(KyConnectItem *p_connectItem);
void sendVpnAddSignal(KyConnectItem *p_connectItem);
void sendVpnStateChangeSignal(QString uuid, ConnectState state);
void clearConnectionMap(QMap<QString, QListWidgetItem *> &connectMap,
QListWidget *vpnListWidget);
void deleteConnectionMapItem(QMap<QString, QListWidgetItem *> &connectMap,
QListWidget *vpnListWidget, QString uuid);
void resetWindowPosition();
Q_SIGNALS:
void vpnAdd(QStringList info);
void vpnRemove(QString dbusPath);
void vpnUpdate(QStringList info);
void vpnActiveConnectionStateChanged(QString uuid, int status);
void vpnConnectChanged(int state);
private Q_SLOTS:
void onConnectionStateChange(QString uuid,
NetworkManager::ActiveConnection::State state,
NetworkManager::ActiveConnection::Reason reason);
void onAddConnection(QString uuid);
void onRemoveConnection(QString path);
void onUpdateConnection(QString uuid);
void onShowControlCenter();
private:
KyVpnConnectOperation *m_vpnConnectOperation = nullptr;
KyActiveConnectResourse *m_activeResourse = nullptr; //激活的连接
KyConnectResourse *m_connectResourse = nullptr; //未激活的连接
QMap<QString, QListWidgetItem *> m_vpnItemMap;
QMap<QString, QListWidgetItem *> m_activeItemMap;
QDBusInterface * m_positionInterface = nullptr;
public Q_SLOTS:
void showUI();
};
#endif // LANPAGE_H

View File

@ -0,0 +1,138 @@
#include "vpnobject.h"
#include <QApplication>
#include "ukuistylehelper/ukuistylehelper.h"
vpnObject::vpnObject(QMainWindow *parent) : QMainWindow(parent)
{
initUI();
initTrayIcon();
initDbusConnnect();
}
vpnObject::~vpnObject()
{
if (m_vpnGsettings != nullptr) {
delete m_vpnGsettings;
m_vpnGsettings = nullptr;
}
}
void vpnObject::initUI()
{
m_vpnPage = new VpnPage(nullptr);
m_vpnPage->update();
}
void vpnObject::initTrayIcon()
{
m_vpnTrayIcon = new QSystemTrayIcon(this);
m_vpnTrayIcon->setToolTip(QString(tr("vpn tool")));
m_vpnTrayIcon->setIcon(QIcon::fromTheme("ukui-vpn-symbolic"));
m_vpnTrayIcon->setVisible(true);
initVpnIconVisible();
connect(m_vpnTrayIcon, &QSystemTrayIcon::activated, this, &vpnObject::onTrayIconActivated);
}
void vpnObject::initVpnIconVisible()
{
if (QGSettings::isSchemaInstalled(QByteArray(GSETTINGS_VPNICON_VISIBLE))) {
m_vpnGsettings = new QGSettings(QByteArray(GSETTINGS_VPNICON_VISIBLE));
if (m_vpnGsettings->keys().contains(QString(VISIBLE))) {
m_vpnTrayIcon->setVisible(m_vpnGsettings->get(VISIBLE).toBool());
connect(m_vpnGsettings, &QGSettings::changed, this, [=]() {
m_vpnTrayIcon->setVisible(m_vpnGsettings->get(VISIBLE).toBool());
});
}
}
}
/**
* @brief vpnObject::onTrayIconActivated
*/
void vpnObject::onTrayIconActivated(QSystemTrayIcon::ActivationReason reason)
{
switch(reason) {
case QSystemTrayIcon::Trigger:
if(m_vpnPage->isActiveWindow()) {
m_vpnPage->hide();
} else {
onShowMainWindow();
}
break;
default:
break;
}
}
void vpnObject::getVirtualList(QVector<QStringList> &vector)
{
vector.clear();
if (nullptr != m_vpnPage) {
m_vpnPage->getVirtualList(vector);
}
}
//Vpn连接删除
void vpnObject::deleteVpn(const QString &connUuid)
{
m_vpnPage->deleteVpn(connUuid);
}
//Vpn连接断开
void vpnObject::activateVpn(const QString& connUuid)
{
m_vpnPage->activateVpn(connUuid);
}
void vpnObject::deactivateVpn(const QString& connUuid)
{
m_vpnPage->deactivateVpn(connUuid);
}
void vpnObject::showDetailPage(const QString& connUuid)
{
m_vpnPage->showDetailPage(connUuid);
}
void vpnObject::onShowMainWindow()
{
kdk::UkuiStyleHelper::self()->removeHeader(m_vpnPage);
m_vpnPage->showUI();
}
void vpnObject::initDbusConnnect()
{
connect(m_vpnPage, &VpnPage::activateFailed, this, &vpnObject::activateFailed);
connect(m_vpnPage, &VpnPage::deactivateFailed, this, &vpnObject::deactivateFailed);
connect(m_vpnPage, &VpnPage::vpnAdd, this, &vpnObject::vpnAdd);
connect(m_vpnPage, &VpnPage::vpnRemove, this, &vpnObject::vpnRemove);
connect(m_vpnPage, &VpnPage::vpnUpdate, this, &vpnObject::vpnUpdate);
connect(m_vpnPage, &VpnPage::vpnActiveConnectionStateChanged, this, &vpnObject::vpnActiveConnectionStateChanged);
//模式切换
QDBusConnection::sessionBus().connect(QString("com.kylin.statusmanager.interface"),
QString("/"),
QString("com.kylin.statusmanager.interface"),
QString("mode_change_signal"), this, SLOT(onTabletModeChanged(bool)));
}
void vpnObject::onTabletModeChanged(bool mode)
{
qDebug() << "TabletMode change" << mode;
Q_UNUSED(mode)
//模式切换时,隐藏主界面
m_vpnPage->hide();
}
void vpnObject::showVpnAddWidget()
{
if (m_vpnAddPage == nullptr) {
m_vpnAddPage = new vpnAddPage();
connect(m_vpnAddPage, &vpnAddPage::closed, [&] () {m_vpnAddPage = nullptr;});
m_vpnAddPage->show();
}
m_vpnAddPage->raise();
}

View File

@ -0,0 +1,75 @@
#ifndef VPNOBJECT_H
#define VPNOBJECT_H
#include <QObject>
#include <QWidget>
#include <QScreen>
#include <QSystemTrayIcon>
#include <QMainWindow>
#include "vpnpage.h"
#include "vpnaddpage.h"
class VpnPage;
#define VISIBLE "visible"
#define GSETTINGS_VPNICON_VISIBLE "org.ukui.kylin-nm.vpnicon"
//const QByteArray GSETTINGS_VPNICON_VISIBLE = "org.ukui.kylin-nm.vpnicon";
class vpnObject : public QMainWindow
{
Q_OBJECT
public:
explicit vpnObject(QMainWindow *parent = nullptr);
~vpnObject();
void getVirtualList(QVector<QStringList> &vector);
//Vpn连接删除
void deleteVpn(const QString &connUuid);
//有线连接断开
void activateVpn(const QString& connUuid);
void deactivateVpn(const QString& connUuid);
void showDetailPage(const QString& connUuid);
void showVpnAddWidget();
private:
void initUI();
void initTrayIcon();
void initVpnIconVisible();
void initDbusConnnect();
private:
VpnPage *m_vpnPage = nullptr;
QSystemTrayIcon * m_vpnTrayIcon = nullptr;
QGSettings * m_vpnGsettings; //VPN配置文件
double tran =1;
QGSettings *StyleSettings = nullptr;
QWidget * vpnWidget = nullptr;
QDBusInterface * m_positionInterface = nullptr;
bool m_isShowInCenter = false;
vpnAddPage *m_vpnAddPage = nullptr;
public Q_SLOTS:
void onShowMainWindow();
private Q_SLOTS:
void onTrayIconActivated(QSystemTrayIcon::ActivationReason reason);
void onTabletModeChanged(bool mode);
Q_SIGNALS:
void vpnAdd(QStringList info);
void vpnRemove(QString dbusPath);
void vpnUpdate(QStringList info);
void vpnActiveConnectionStateChanged(QString uuid, int status);
void activateFailed(QString errorMessage);
void deactivateFailed(QString errorMessage);
void mainWindowVisibleChanged(const bool &visible);
};
#endif // VPNOBJECT_H

18
src-vpn/kylin-vpn.desktop Normal file
View File

@ -0,0 +1,18 @@
[Desktop Entry]
Encoding=UTF-8
Name=Kylin VPN
Name[zh_CN]=麒麟VPN设置工具
Name[zh_HK]=麒麟VPN設置工具
Name[zh_TW]=麒麟VPN設置工具
Icon=gnome-dev-ethernet
Comment=Beautiful Network Config Applet
Comment[zh_CN]=麒麟VPN设置工具提供查看和简单设置功能拥有美观的界面和舒适的操作.
Keywords=applet;vpn;network;network-manager;
Exec=/usr/bin/kylin-vpn
StartupNotify=false
Terminal=false
Type=Application
OnlyShowIn=UKUI
X-UKUI-AutoRestart=true
NoDisplay=true
X-UKUI-Autostart-Phase=Application

137
src-vpn/main.cpp Normal file
View File

@ -0,0 +1,137 @@
/*
* Copyright (C) 2020 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, see <http://www.gnu.org/licenses/&gt;.
*
*/
//#include "mainwindow.h"
//#include "dbusadaptor.h"
#include "vpndbusadaptor.h"
#include <QTranslator>
#include <QLocale>
#include "qt-single-application.h"
#include <QDebug>
#include <QDesktopWidget>
#include <QFile>
#include <ukui-log4qt.h>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
#include "xatom-helper.h"
#endif
#include "vpnobject.h"
#define LOG_IDENT "kylin_vpn"
const QString QT_TRANSLATE_FILE = "/usr/share/qt5/translations/qt_zh_CN.qm";
void messageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QByteArray localMsg = msg.toLocal8Bit();
QByteArray currentDateTime = QDateTime::currentDateTime().toString().toLocal8Bit();
bool showDebug = true;
QString logFilePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + "/.config/ukui/kylin-nm.log";
FILE *log_file = nullptr;
if (showDebug) {
log_file = fopen(logFilePath.toLocal8Bit().constData(), "a+");
}
const char *file = context.file ? context.file : "";
const char *function = context.function ? context.function : "";
switch (type) {
case QtDebugMsg:
if (!log_file) {
break;
}
fprintf(log_file, "Debug: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtInfoMsg:
fprintf(log_file? log_file: stdout, "Info: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtWarningMsg:
fprintf(log_file? log_file: stderr, "Warning: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtCriticalMsg:
fprintf(log_file? log_file: stderr, "Critical: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function);
break;
case QtFatalMsg:
fprintf(log_file? log_file: stderr, "Fatal: %s: %s (%s:%u, %s)\n", currentDateTime.constData(), localMsg.constData(), file, context.line, function);
break;
}
if (log_file)
fclose(log_file);
}
int main(int argc, char *argv[])
{
initUkuiLog4qt("kylin-vpn");
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps);
QString id = QString("kylin-vpn"+ QLatin1String(getenv("DISPLAY")));
QtSingleApplication a(id, argc, argv);
QApplication::setQuitOnLastWindowClosed(false);
QThread thread;
KyNetworkResourceManager *p_networkResource = KyNetworkResourceManager::getInstance();
p_networkResource->moveToThread(&thread);
QObject::connect(&thread, SIGNAL(started()), p_networkResource, SLOT(onInitNetwork()));
thread.start();
// Internationalization
QString locale = QLocale::system().name();
QTranslator trans_global;
qDebug() << "QLocale " << QLocale();
if (trans_global.load(QLocale(), "kylin-vpn", "_", ":/translations/"))
{
a.installTranslator(&trans_global);
qDebug()<<"Translations load success";
} else {
qWarning() << "Translations load fail";
}
QTranslator qtBaseTranslator;
if (qtBaseTranslator.load(QLocale(), "qt", "_", "/usr/share/qt5/translations/"))
{
a.installTranslator(&qtBaseTranslator);
qDebug()<<"QtBase Translations load success";
} else {
qWarning() << "QtBase Translations load fail";
}
while (!p_networkResource->NetworkManagerIsInited()) {
::usleep(1000);
}
vpnObject vpnobject;
a.setActivationWindow(&vpnobject);
vpnobject.setProperty("useStyleWindowManager", false); //禁用拖动
a.setWindowIcon(QIcon::fromTheme("ukui-vpn-symbolic"));
VpnDbusAdaptor vpnAdaptor(&vpnobject);
Q_UNUSED(vpnAdaptor);
auto connection = QDBusConnection::sessionBus();
if (!connection.registerService("com.kylin.kylinvpn")
|| !connection.registerObject("/com/kylin/kylinvpn", &vpnobject)) {
qCritical() << "QDbus register service failed reason:" << connection.lastError();
}
return a.exec();
}

View File

@ -0,0 +1,9 @@
<schemalist gettext-domain="kylin-vpn">
<schema id="org.ukui.kylin-nm.vpnicon" path="/org/ukui/kylin-nm/vpnicon/">
<key type="b" name="visible">
<default>false</default>
<summary>vpnicon visible</summary>
<description>vpnicon visible.true is visible,false is invisible.</description>
</key>
</schema>
</schemalist>

View File

@ -0,0 +1,205 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
**
****************************************************************************/
#include "qt-local-peer.h"
#include <QCoreApplication>
#include <QDataStream>
#include <QTime>
#if defined(Q_OS_UNIX)
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#endif
namespace QtLP_Private {
#include "qt-locked-file.cpp"
#include "qt-locked-file-unix.cpp"
}
const char* QtLocalPeer::ack = "ack";
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
: QObject(parent), id(appId) {
QString prefix = id;
if(id.isEmpty()) {
id = QCoreApplication::applicationFilePath();
#if defined(Q_OS_WIN)
id = id.toLower();
#endif
prefix = id.section(QLatin1Char('/'), -1); //完整路径按‘/’分隔后取最后一个字段
}
prefix.remove(QRegExp("[^a-zA-Z]")); //去掉名称中的非字母
prefix.truncate(6); //取前六位
QByteArray idc = id.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
socketName = QLatin1String("qtsingleapp-") + prefix
+ QLatin1Char('-') + QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if(!pProcessIdToSessionId) {
QLibrary lib("kernel32");
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if(pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
+ QLatin1String("-lockfile"); //tmp目录下的锁文件
lockFile.setFileName(lockName);
lockFile.open(QIODevice::ReadWrite);
}
bool QtLocalPeer::isClient() {
if(lockFile.isLocked())
return false;
if(!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
return true;
//由于文件锁的存在仅当本进程第一次启动时能执行到此并使server进行监听和关联槽函数
bool res = server->listen(socketName);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
// ### Workaround
if(!res && server->serverError() == QAbstractSocket::AddressInUseError) {
QFile::remove(QDir::cleanPath(QDir::tempPath()) + QLatin1Char('/') + socketName);
res = server->listen(socketName);
}
#endif
if(!res)
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
QObject::connect(server, &QLocalServer::newConnection, this, &QtLocalPeer::receiveConnection);
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout) {
if(!isClient())
return false;
QLocalSocket socket;
bool connOk = false;
for(int i = 0; i < 2; i++) {
// Try twice, in case the other instance is just starting up
socket.connectToServer(socketName);
connOk = socket.waitForConnected(timeout / 2);
if(connOk || i)
break;
int ms = 250;
#if defined(Q_OS_WIN)
Sleep(DWORD(ms));
#else
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&ts, NULL);
#endif
}
if(!connOk)
return false;
QByteArray uMsg(message.toUtf8());
QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size());
bool res = socket.waitForBytesWritten(timeout);
if(res) {
res &= socket.waitForReadyRead(timeout); // wait for ack
if(res)
res &= (socket.read(qstrlen(ack)) == ack);
}
return res;
}
/**
* @brief QtLocalPeer::receiveConnection server,server接收到newConnection信号并触发此槽函数
*/
void QtLocalPeer::receiveConnection() {
QLocalSocket* socket = server->nextPendingConnection(); //获取新进程的socket
if(!socket)
return;
while(true) {
if(socket->state() == QLocalSocket::UnconnectedState) {
qWarning("QtLocalPeer: Peer disconnected");
delete socket;
return;
}
if(socket->bytesAvailable() >= qint64(sizeof(quint32)))
break;
socket->waitForReadyRead();
}
QDataStream ds(socket);
QByteArray uMsg;
quint32 remaining;
ds >> remaining;
uMsg.resize(remaining);
int got = 0;
char* uMsgBuf = uMsg.data();
do {
got = ds.readRawData(uMsgBuf, remaining);
remaining -= got;
uMsgBuf += got;
} while(remaining && got >= 0 && socket->waitForReadyRead(2000));
if(got < 0) {
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
delete socket;
return;
}
QString message(QString::fromUtf8(uMsg));
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
socket->waitForDisconnected(1000); // make sure client reads ack
delete socket;
Q_EMIT messageReceived(message); //获取新进程的启动信息并作为信号发送给前端
}

View File

@ -0,0 +1,80 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
**
****************************************************************************/
#ifndef QTLOCALPEER_H
#define QTLOCALPEER_H
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include "qt-locked-file.h"
class QtLocalPeer : public QObject {
Q_OBJECT
public:
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
bool isClient();
bool sendMessage(const QString &message, int timeout);
QString applicationId() const {
return id;
}
Q_SIGNALS:
void messageReceived(const QString &message);
protected Q_SLOTS:
void receiveConnection();
protected:
QString id;
QString socketName;
QLocalServer* server;
QtLP_Private::QtLockedFile lockFile;
private:
static const char* ack;
};
#endif // QTLOCALPEER_H

View File

@ -0,0 +1,113 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "qt-locked-file.h"
bool QtLockedFile::lock(LockMode mode, bool block) {
if(!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if(mode == NoLock)
return unlock();
if(mode == m_lock_mode)
return true;
if(m_lock_mode != NoLock)
unlock();
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
int cmd = block ? F_SETLKW : F_SETLK;
int ret = fcntl(handle(), cmd, &fl);
if(ret == -1) {
if(errno != EINTR && errno != EAGAIN)
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock() {
if(!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if(!isLocked())
return true;
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
int ret = fcntl(handle(), F_SETLKW, &fl);
if(ret == -1) {
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = NoLock;
return true;
}
QtLockedFile::~QtLockedFile() {
if(isOpen())
unlock();
}

View File

@ -0,0 +1,189 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qt-locked-file.h"
/*!
\class QtLockedFile
\brief The QtLockedFile class extends QFile with advisory locking
functions.
A file may be locked in read or write mode. Multiple instances of
\e QtLockedFile, created in multiple processes running on the same
machine, may have a file locked in read mode. Exactly one instance
may have it locked in write mode. A read and a write lock cannot
exist simultaneously on the same file.
The file locks are advisory. This means that nothing prevents
another process from manipulating a locked file using QFile or
file system functions offered by the OS. Serialization is only
guaranteed if all processes that access the file use
QLockedFile. Also, while holding a lock on a file, a process
must not open the same file again (through any API), or locks
can be unexpectedly lost.
The lock provided by an instance of \e QtLockedFile is released
whenever the program terminates. This is true even when the
program crashes and no destructors are called.
*/
/*! \enum QtLockedFile::LockMode
This enum describes the available lock modes.
\value ReadLock A read lock.
\value WriteLock A write lock.
\value NoLock Neither a read lock nor a write lock.
*/
/*!
Constructs an unlocked \e QtLockedFile object. This constructor
behaves in the same way as \e QFile::QFile().
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile()
: QFile() {
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Constructs an unlocked QtLockedFile object with file \a name. This
constructor behaves in the same way as \e QFile::QFile(const
QString&).
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile(const QString &name)
: QFile(name) {
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Opens the file in OpenMode \a mode.
This is identical to QFile::open(), with the one exception that the
Truncate mode flag is disallowed. Truncation would conflict with the
advisory file locking, since the file would be modified before the
write lock is obtained. If truncation is required, use resize(0)
after obtaining the write lock.
Returns true if successful; otherwise false.
\sa QFile::open(), QFile::resize()
*/
bool QtLockedFile::open(OpenMode mode) {
if(mode & QIODevice::Truncate) {
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
return false;
}
return QFile::open(mode);
}
/*!
Returns \e true if this object has a in read or write lock;
otherwise returns \e false.
\sa lockMode()
*/
bool QtLockedFile::isLocked() const {
return m_lock_mode != NoLock;
}
/*!
Returns the type of lock currently held by this object, or \e
QtLockedFile::NoLock.
\sa isLocked()
*/
QtLockedFile::LockMode QtLockedFile::lockMode() const {
return m_lock_mode;
}
/*!
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
Obtains a lock of type \a mode. The file must be opened before it
can be locked.
If \a block is true, this function will block until the lock is
aquired. If \a block is false, this function returns \e false
immediately if the lock cannot be aquired.
If this object already has a lock of type \a mode, this function
returns \e true immediately. If this object has a lock of a
different type than \a mode, the lock is first released and then a
new lock is obtained.
This function returns \e true if, after it executes, the file is
locked by this object, and \e false otherwise.
\sa unlock(), isLocked(), lockMode()
*/
/*!
\fn bool QtLockedFile::unlock()
Releases a lock.
If the object has no lock, this function returns immediately.
This function returns \e true if, after it executes, the file is
not locked by this object, and \e false otherwise.
\sa lock(), isLocked(), lockMode()
*/
/*!
\fn QtLockedFile::~QtLockedFile()
Destroys the \e QtLockedFile object. If any locks were held, they
are released.
*/

View File

@ -0,0 +1,97 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCKEDFILE_H
#define QTLOCKEDFILE_H
#include <QFile>
#ifdef Q_OS_WIN
#include <QVector>
#endif
#if defined(Q_OS_WIN)
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
# define QT_QTLOCKEDFILE_EXPORT
# elif defined(QT_QTLOCKEDFILE_IMPORT)
# if defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# endif
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
# elif defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTLOCKEDFILE_EXPORT
#endif
namespace QtLP_Private {
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile {
public:
enum LockMode { NoLock = 0, ReadLock, WriteLock };
QtLockedFile();
QtLockedFile(const QString &name);
~QtLockedFile();
bool open(OpenMode mode);
bool lock(LockMode mode, bool block = true);
bool unlock();
bool isLocked() const;
LockMode lockMode() const;
private:
#ifdef Q_OS_WIN
Qt::HANDLE wmutex;
Qt::HANDLE rmutex;
QVector<Qt::HANDLE> rmutexes;
QString mutexname;
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
#endif
LockMode m_lock_mode;
};
}
#endif

View File

@ -0,0 +1,351 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
**
****************************************************************************/
#include "qt-single-application.h"
#include "qt-local-peer.h"
#include <QWidget>
#include <QDesktopWidget>
#include <QDBusConnection>
#include <QDBusInterface>
#include <QDBusReply>
#include <QMainWindow>
#include "../vpnobject.h"
/*!
\class QtSingleApplication qtsingleapplication.h
\brief The QtSingleApplication class provides an API to detect and
communicate with running instances of an application.
This class allows you to create applications where only one
instance should be running at a time. I.e., if the user tries to
launch another instance, the already running instance will be
activated instead. Another usecase is a client-server system,
where the first started instance will assume the role of server,
and the later instances will act as clients of that server.
By default, the full path of the executable file is used to
determine whether two processes are instances of the same
application. You can also provide an explicit identifier string
that will be compared instead.
The application should create the QtSingleApplication object early
in the startup phase, and call isRunning() to find out if another
instance of this application is already running. If isRunning()
returns false, it means that no other instance is running, and
this instance has assumed the role as the running instance. In
this case, the application should continue with the initialization
of the application user interface before entering the event loop
with exec(), as normal.
The messageReceived() signal will be emitted when the running
application receives messages from another instance of the same
application. When a message is received it might be helpful to the
user to raise the application so that it becomes visible. To
facilitate this, QtSingleApplication provides the
setActivationWindow() function and the activateWindow() slot.
If isRunning() returns true, another instance is already
running. It may be alerted to the fact that another instance has
started by using the sendMessage() function. Also data such as
startup parameters (e.g. the name of the file the user wanted this
new instance to open) can be passed to the running instance with
this function. Then, the application should terminate (or enter
client mode).
If isRunning() returns true, but sendMessage() fails, that is an
indication that the running instance is frozen.
Here's an example that shows how to convert an existing
application to use QtSingleApplication. It is very simple and does
not make use of all QtSingleApplication's functionality (see the
examples for that).
\code
// Original
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyMainWidget mmw;
mmw.show();
return app.exec();
}
// Single instance
int main(int argc, char **argv)
{
QtSingleApplication app(argc, argv);
if (app.isRunning())
return !app.sendMessage(someDataString);
MyMainWidget mmw;
app.setActivationWindow(&mmw);
mmw.show();
return app.exec();
}
\endcode
Once this QtSingleApplication instance is destroyed (normally when
the process exits or crashes), when the user next attempts to run the
application this instance will not, of course, be encountered. The
next instance to call isRunning() or sendMessage() will assume the
role as the new running instance.
For console (non-GUI) applications, QtSingleCoreApplication may be
used instead of this class, to avoid the dependency on the QtGui
library.
\sa QtSingleCoreApplication
*/
void QtSingleApplication::sysInit(const QString &appId) {
m_activateWindow = 0;
m_peer = new QtLocalPeer(this, appId);
connect(m_peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::messageReceived);
}
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a GUIenabled are passed on to the QAppliation constructor.
If you are creating a console application (i.e. setting \a
GUIenabled to false), you may consider using
QtSingleCoreApplication instead.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
: QApplication(argc, argv, GUIenabled) {
sysInit();
}
/*!
Creates a QtSingleApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
: QApplication(argc, argv) {
sysInit(appId);
}
#if QT_VERSION < 0x050000
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a type are passed on to the QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
: QApplication(argc, argv, type) {
sysInit();
}
# if defined(Q_WS_X11)
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
and \a cmap are passed on to the QApplication constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, visual, cmap) {
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap) {
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be \a appId. \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap) {
sysInit(appId);
}
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleApplication::isRunning() {
return m_peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleApplication::sendMessage(const QString &message, int timeout) {
return m_peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleApplication::id() const {
return m_peer->applicationId();
}
/*!
Sets the activation window of this application to \a aw. The
activation window is the widget that will be activated by
activateWindow(). This is typically the application's main window.
If \a activateOnMessage is true (the default), the window will be
activated automatically every time a message is received, just prior
to the messageReceived() signal being emitted.
\sa activateWindow(), messageReceived()
*/
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage) {
m_activateWindow = aw;
if (activateOnMessage)
connect(m_peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
else
disconnect(m_peer, &QtLocalPeer::messageReceived, this, &QtSingleApplication::activateWindow);
}
/*!
Returns the applications activation window if one has been set by
calling setActivationWindow(), otherwise returns 0.
\sa setActivationWindow()
*/
QWidget* QtSingleApplication::activationWindow() const {
return m_activateWindow;
}
/*!
De-minimizes, raises, and activates this application's activation window.
This function does nothing if no activation window has been set.
This is a convenience function to show the user that this
application instance has been activated when he has tried to start
another instance.
This function should typically be called in response to the
messageReceived() signal. By default, that will happen
automatically, if an activation window has been set.
\sa setActivationWindow(), messageReceived(), initialize()
*/
void QtSingleApplication::activateWindow() {
if (m_activateWindow) {
if(this->applicationState() & Qt::ApplicationInactive)
{
m_activateWindow->setWindowState(m_activateWindow->windowState() & ~Qt::WindowMinimized);
m_activateWindow->raise();
m_activateWindow->showNormal();
m_activateWindow->activateWindow();
}
else {
m_activateWindow->setWindowState(m_activateWindow->windowState() & Qt::WindowMinimized);
m_activateWindow->hide();
}
}
}
/*!
\fn void QtSingleApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage(), setActivationWindow(), activateWindow()
*/
/*!
\fn void QtSingleApplication::initialize(bool dummy = true)
\obsolete
*/

View File

@ -0,0 +1,109 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies)
** 2020 KylinSoft Co., Ltd.
** Contact: http://www.qt-project.org/legal
**
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
**
****************************************************************************/
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include <QApplication>
class QtLocalPeer;
#if defined(Q_OS_WIN)
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
# define QT_QTSINGLEAPPLICATION_EXPORT
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
# if defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# endif
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport)
# elif defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTSINGLEAPPLICATION_EXPORT
#endif
class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication {
Q_OBJECT
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv);
#if QT_VERSION < 0x050000
QtSingleApplication(int &argc, char **argv, Type type);
# if defined(Q_WS_X11)
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap = 0);
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
bool isRunning();
QString id() const;
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
QWidget* activationWindow() const;
// Obsolete:
void initialize(bool dummy = true) {
isRunning();
Q_UNUSED(dummy)
}
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
void activateWindow();
Q_SIGNALS:
void messageReceived(const QString &message);
private:
void sysInit(const QString &appId = QString());
QtLocalPeer *m_peer;
QWidget *m_activateWindow;
};
#endif // QTSINGLEAPPLICATION_H

View File

@ -0,0 +1,27 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
QT *= network
greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets
qtsingleapplication-uselib:!qtsingleapplication-buildlib {
LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME
} else {
SOURCES +=
HEADERS +=
}
win32 {
contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT
else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT
}
HEADERS += \
$$PWD/qt-local-peer.h \
$$PWD/qt-locked-file.h \
$$PWD/qt-single-application.h
SOURCES += \
$$PWD/qt-local-peer.cpp \
$$PWD/qt-locked-file-unix.cpp \
$$PWD/qt-single-application.cpp \
$$PWD/qt-locked-file.cpp

73
src-vpn/src-vpn.pro Normal file
View File

@ -0,0 +1,73 @@
#-------------------------------------------------
#
# Project created by QtCreator 2018-10-19T15:29:47
#
#-------------------------------------------------
QT += core gui x11extras dbus KWindowSystem svg concurrent network
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = kylin-vpn
TEMPLATE = app
CONFIG += c++14 qt warn_on link_pkgconfig no_keywords
#CONFIG += release
PKGCONFIG +=gio-2.0 glib-2.0 gio-unix-2.0 libnm libnma libsecret-1 gtk+-3.0 gsettings-qt libcap kysdk-qtwidgets kysdk-waylandhelper
PKGCONFIG +=kysdk-sysinfo
INCLUDEPATH += /usr/include/KF5/NetworkManagerQt
LIBS += -L/usr/lib/ -lgsettings-qt -lX11 -lKF5NetworkManagerQt -lukui-log4qt -lkysec
target.path = /usr/bin
target.source += $$TARGET
desktop.path = /etc/xdg/autostart/
desktop.files = kylin-vpn.desktop
gschema.files = org.ukui.kylin-vpn.switch.gschema.xml
gschema.path = /usr/share/glib-2.0/schemas/
INSTALLS += target \
desktop \
gschema \
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
# QMAKE_CXXFLAGS += -Wno-unused-parameter
QMAKE_CPPFLAGS *= $(shell dpkg-buildflags --get CPPFLAGS)
QMAKE_CFLAGS *= $(shell dpkg-buildflags --get CFLAGS)
QMAKE_CXXFLAGS *= $(shell dpkg-buildflags --get CXXFLAGS)
QMAKE_LFLAGS *= $(shell dpkg-buildflags --get LDFLAGS)
include(singleapplication/qt-single-application.pri)
include(backend/backend.pri)
include(frontend/frontend.pri)
RESOURCES += \
vpnqrc.qrc
SOURCES += \
main.cpp
unix {
UI_DIR = .ui
MOC_DIR = .moc
OBJECTS_DIR = .obj
}
DISTFILES += \
org.ukui.kylin-vpn.switch.gschema.xml
TRANSLATIONS += \
translations/kylin-vpn_zh_CN.ts \
translations/kylin-vpn_bo_CN.ts

View File

@ -0,0 +1,147 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="bo_CN">
<context>
<name>SinglePage</name>
<message>
<location filename="../frontend/single-pages/singlepage.cpp" line="73"/>
<source>Settings</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/single-pages/singlepage.cpp" line="121"/>
<source>Kylin VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/single-pages/singlepage.cpp" line="124"/>
<source>kylin vpn applet desktop message</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>VpnListItem</name>
<message>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="61"/>
<source>Not connected</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="160"/>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="176"/>
<source>Disconnect</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="162"/>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="174"/>
<source>Connect</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>VpnPage</name>
<message>
<location filename="../frontend/single-pages/vpnpage.cpp" line="259"/>
<source>VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/single-pages/vpnpage.cpp" line="270"/>
<source>VPN Settings</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>vpnAddPage</name>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="15"/>
<source>create VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="47"/>
<source>VPN Type</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="75"/>
<source>VPN Name</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="81"/>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="103"/>
<source>Required</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="98"/>
<source>VPN Server</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>vpnConfigPage</name>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="35"/>
<source>VPN Type</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>vpnDetail</name>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="15"/>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="27"/>
<source>VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="28"/>
<source>IPv4</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="30"/>
<source>IPv6</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="32"/>
<source>Advanced</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>vpnDetailPage</name>
<message>
<location filename="../frontend/vpndetails/vpndetailpage.cpp" line="12"/>
<source>VPN</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetailpage.cpp" line="41"/>
<source>Auto Connection</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetailpage.cpp" line="53"/>
<source>Confirm</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetailpage.cpp" line="56"/>
<source>Cancel</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>vpnObject</name>
<message>
<location filename="../frontend/vpnobject.cpp" line="31"/>
<source>vpn tool</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

View File

@ -0,0 +1,838 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1" language="zh_CN">
<context>
<name>SinglePage</name>
<message>
<location filename="../frontend/single-pages/singlepage.cpp" line="73"/>
<source>Settings</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/single-pages/singlepage.cpp" line="121"/>
<source>Kylin VPN</source>
<translation>VPN工具</translation>
</message>
<message>
<location filename="../frontend/single-pages/singlepage.cpp" line="124"/>
<source>kylin vpn applet desktop message</source>
<translation>vpn配置桌面提示</translation>
</message>
</context>
<context>
<name>VpnAdvancedPage</name>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="791"/>
<source>MPPE encryption algorithm:</source>
<translation>MPPE加密算法</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="792"/>
<source>Use Stateful encryption</source>
<translation>使</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="793"/>
<source>Send PPP echo packets</source>
<translation>PPP回显包</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="794"/>
<source>Authentication Mode:</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="795"/>
<source>PAP authentication</source>
<translation>PAP认证</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="796"/>
<source>CHAP authentication</source>
<translation>CHAP认证</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="797"/>
<source>MSCHAP authentication</source>
<translation>MSCHAP认证</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="798"/>
<source>MSCHAP2 authentication</source>
<translation>MSCHAP2认证</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="799"/>
<source>EAP authentication</source>
<translation>EAP认证</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="800"/>
<source>Compression Mode:</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="801"/>
<source>Allow BSD data compression</source>
<translation>BSD压缩</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="802"/>
<source>Allow Default data compression</source>
<translation>Default压缩</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="803"/>
<source>Allow TCP header compression</source>
<translation>TCP头压缩</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="804"/>
<source>Use protocol field compression negotiation</source>
<translation>使</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="805"/>
<source>Use Address/Control compression</source>
<translation>使/</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="811"/>
<source>All Available</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="812"/>
<source>128-bit</source>
<translation>128</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="813"/>
<source>40-bit</source>
<translation>40</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1010"/>
<source>Use custom gateway port</source>
<translation>使</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1011"/>
<source>Use compression</source>
<translation>使</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1012"/>
<source>Use a TCP connection</source>
<translation>使TCP连接</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1013"/>
<source>Set virtual device type</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1014"/>
<source>Set virtual device name</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1015"/>
<source>Limit TCP Maximum Segment Size(MSS)</source>
<translation>TCP最大段尺寸MSS</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1016"/>
<source>Randomize remote hosts</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1017"/>
<source>IPv6 tun link</source>
<translation>IPv6 tun连接</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1018"/>
<source>Specify ping interval</source>
<translation>Ping周期</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1019"/>
<source>Specify exit or restart ping</source>
<translation>退Ping</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1020"/>
<source>Specify max routes</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1021"/>
<source>Infinite retry on error</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1022"/>
<source>Use custom key size</source>
<translation>使</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1023"/>
<source>Choose</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1026"/>
<source>Use custom renegotiation interval</source>
<translation>使</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1028"/>
<source>Use custom tunnel Maximum Transmission Umit(MTU)</source>
<translation>使MTU</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1030"/>
<source>Use custom UDP fragment size</source>
<translation>使UDP分片大小</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1032"/>
<source>Accept authenticated packets from any address (Float)</source>
<translation>Float</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1034"/>
<source>Subject Match</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1035"/>
<source>Key File</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1036"/>
<source>Key Direction</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1038"/>
<source>Server Address</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1039"/>
<source>Port</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1040"/>
<source>Proxy USername</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1041"/>
<source>Proxy Password</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1043"/>
<source>General</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1044"/>
<source>TLS settings</source>
<translation>TLS设置</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1045"/>
<source>Server Certificate Check</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1047"/>
<source>Use the previous authentication end (server) certificate</source>
<translation>使</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1049"/>
<source>Verify peer (server) certificate nsCertType specification</source>
<translation>nsCertType指定</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1050"/>
<source>Mode</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1051"/>
<source>Proxies</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1052"/>
<source>Proxy Type</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1053"/>
<source>Security</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1054"/>
<source>HMAC Authentication</source>
<translation>HMAC认证</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1064"/>
<source>Input content</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1066"/>
<source>No</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1070"/>
<source>Self-adaption</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1071"/>
<source>Automatic</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1076"/>
<source>Exit</source>
<translation>退</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1077"/>
<source>Restart</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1079"/>
<source>Don&apos;t verify certificate identification</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1080"/>
<source>Verify the entire subject exactly</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1081"/>
<source>Verify name exactly</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1082"/>
<source>Verify name by prefix</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1084"/>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1087"/>
<source>Server</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1085"/>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1088"/>
<source>Client</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1090"/>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1094"/>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1103"/>
<source>None</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1091"/>
<source>TLS-Certification</source>
<translation>TLS-</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1092"/>
<source>TLS-Encryption</source>
<translation>TLS-</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1098"/>
<source>Not Required</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1102"/>
<source>Default</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1176"/>
<source>Options:</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1179"/>
<source>Request an inner IP address</source>
<translation>IP地址</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1180"/>
<source>Enforce UDP encapsulation</source>
<translation>UDP封装</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1181"/>
<source>Use IP compression</source>
<translation>使IP压缩</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnadvancedpage.cpp" line="1182"/>
<source>Enable custom password suggestions</source>
<translation></translation>
</message>
</context>
<context>
<name>VpnConfigPage</name>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="312"/>
<source>Type</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="313"/>
<source>Name</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="314"/>
<source>Static Key</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="315"/>
<source>Local IP</source>
<translation>IP地址</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="316"/>
<source>Remote IP</source>
<translation>IP地址</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="317"/>
<source>PIN Code</source>
<translation>PIN码</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="318"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="790"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="797"/>
<source>Password</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="319"/>
<source>NT Domain</source>
<translation>NT域</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="321"/>
<source>Server Address</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="322"/>
<source>Authentication Mode</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="323"/>
<source>CA Certificate</source>
<translation>CA证书</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="324"/>
<source>User Certificate</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="325"/>
<source>Key Direction</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="326"/>
<source>Private Key</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="327"/>
<source>Private Key Password</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="328"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="330"/>
<source>Password Options</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="329"/>
<source>Username</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="333"/>
<source>Notice:
If key direction is used, it must be opposite to the VPN side used. If &apos;1&apos; is used, the connection must use &apos;0&apos;. If you are not sure which value to use, please contact your system administrator.</source>
<translation>
使使VPN端相反使1使0使</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="340"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="341"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="342"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="343"/>
<source>Choose</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="350"/>
<source>None</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="354"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="360"/>
<source>Save password only for this user</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="355"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="361"/>
<source>Save password for all users</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="356"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="362"/>
<source>Ask password every time</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="357"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="363"/>
<source>Don&apos;t require a password</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="366"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="367"/>
<source>Required</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="795"/>
<source>Certificate(TLS)</source>
<translation>TLS</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="796"/>
<source>Static key</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="798"/>
<source>Password and certificate(TLS)</source>
<translation>TLS</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="807"/>
<source>Certificate/Private key</source>
<translation>/</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="808"/>
<source>Certificate/ssh-agent</source>
<translation>/ssh-agent</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="809"/>
<source>Smart card</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="864"/>
<source>Choose a private key</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="866"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="905"/>
<source>Key Files (*.key *.pem *.der *.p12 *.pfx)</source>
<translation>(*.key *.pem *.der *.p12 *.pfx)</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="877"/>
<source>Choose a CA certificate</source>
<translation>CA证书</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="879"/>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="892"/>
<source>CA Files (*.pem *.der *.p12 *.crt *.cer *.pfx)</source>
<translation>CA文件 (*.pem *.der *.p12 *.crt *.cer *.pfx)</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="890"/>
<source>Choose a User certificate</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnconfigpage.cpp" line="903"/>
<source>Choose a Static key</source>
<translation></translation>
</message>
</context>
<context>
<name>VpnIpv4Page</name>
<message>
<location filename="../frontend/vpndetails/vpnipv4page.cpp" line="152"/>
<source>IPv4 Config</source>
<translation>IPv4配置</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv4page.cpp" line="153"/>
<source>Address</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv4page.cpp" line="154"/>
<source>Netmask</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv4page.cpp" line="155"/>
<source>Default Gateway</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv4page.cpp" line="156"/>
<source>DNS Server</source>
<translation>DNS服务器</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv4page.cpp" line="157"/>
<source>Search Domain</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv4page.cpp" line="158"/>
<source>DHCP Client ID</source>
<translation>DHCP客户端ID</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv4page.cpp" line="160"/>
<source>Auto(DHCP)</source>
<translation>(DHCP)</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv4page.cpp" line="161"/>
<source>Manual</source>
<translation></translation>
</message>
</context>
<context>
<name>VpnIpv6Page</name>
<message>
<location filename="../frontend/vpndetails/vpnipv6page.cpp" line="141"/>
<source>IPv6 Config</source>
<translation>IPv6配置</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv6page.cpp" line="142"/>
<source>Address</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv6page.cpp" line="143"/>
<source>Netmask</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv6page.cpp" line="144"/>
<source>Default Gateway</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv6page.cpp" line="145"/>
<source>DNS Server</source>
<translation>DNS服务器</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv6page.cpp" line="146"/>
<source>Search Domain</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv6page.cpp" line="148"/>
<source>Auto(DHCP)</source>
<translation>(DHCP)</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnipv6page.cpp" line="149"/>
<source>Manual</source>
<translation></translation>
</message>
</context>
<context>
<name>VpnListItem</name>
<message>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="61"/>
<source>Not connected</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="160"/>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="176"/>
<source>Disconnect</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="162"/>
<location filename="../frontend/list-items/vpnlistitem.cpp" line="174"/>
<source>Connect</source>
<translation></translation>
</message>
</context>
<context>
<name>VpnPage</name>
<message>
<location filename="../frontend/single-pages/vpnpage.cpp" line="259"/>
<source>VPN</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/single-pages/vpnpage.cpp" line="270"/>
<source>VPN Settings</source>
<translation>VPN设置</translation>
</message>
</context>
<context>
<name>vpnAddPage</name>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="15"/>
<source>create VPN</source>
<translation>VPN</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="47"/>
<source>VPN Type</source>
<translation>VPN类型</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="75"/>
<source>VPN Name</source>
<translation>VPN名称</translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="81"/>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="103"/>
<source>Required</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpnaddpage.cpp" line="98"/>
<source>VPN Server</source>
<translation></translation>
</message>
</context>
<context>
<name>vpnConfigPage</name>
<message>
<source>VPN Type</source>
<translation type="vanished">VPN类型</translation>
</message>
</context>
<context>
<name>vpnDetail</name>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="61"/>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="145"/>
<source>VPN</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="146"/>
<source>IPv4</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="148"/>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="225"/>
<source>IPv6</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="153"/>
<source>Advanced</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="158"/>
<source>Auto Connection</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="159"/>
<source>Cancel</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetail.cpp" line="160"/>
<source>Confirm</source>
<translation></translation>
</message>
</context>
<context>
<name>vpnDetailPage</name>
<message>
<location filename="../frontend/vpndetails/vpndetailpage.cpp" line="12"/>
<source>VPN</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetailpage.cpp" line="41"/>
<source>Auto Connection</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetailpage.cpp" line="53"/>
<source>Confirm</source>
<translation></translation>
</message>
<message>
<location filename="../frontend/vpndetails/vpndetailpage.cpp" line="56"/>
<source>Cancel</source>
<translation></translation>
</message>
</context>
<context>
<name>vpnObject</name>
<message>
<location filename="../frontend/vpnobject.cpp" line="31"/>
<source>vpn tool</source>
<translation>VPN工具</translation>
</message>
</context>
</TS>

6
src-vpn/vpnqrc.qrc Normal file
View File

@ -0,0 +1,6 @@
<RCC>
<qresource prefix="/">
<file>translations/kylin-vpn_zh_CN.qm</file>
<file>translations/kylin-vpn_bo_CN.qm</file>
</qresource>
</RCC>

View File

@ -21,6 +21,7 @@ HEADERS += \
$$PWD/kywirelessconnectoperation.h \ $$PWD/kywirelessconnectoperation.h \
$$PWD/kywirelessnetitem.h \ $$PWD/kywirelessnetitem.h \
$$PWD/kywirelessnetresource.h \ $$PWD/kywirelessnetresource.h \
$$PWD/kyvpnconnectoperation.h \
$$PWD/nm-macros-internal.h $$PWD/nm-macros-internal.h
SOURCES += \ SOURCES += \
@ -42,5 +43,6 @@ SOURCES += \
$$PWD/kylinwiredconnectoperation.cpp \ $$PWD/kylinwiredconnectoperation.cpp \
$$PWD/kywirelessconnectoperation.cpp \ $$PWD/kywirelessconnectoperation.cpp \
$$PWD/kywirelessnetitem.cpp \ $$PWD/kywirelessnetitem.cpp \
$$PWD/kyvpnconnectoperation.cpp \
$$PWD/kywirelessnetresource.cpp $$PWD/kywirelessnetresource.cpp

View File

@ -42,11 +42,36 @@ static bool subLanListSort(const KyConnectItem* info1, const KyConnectItem* info
return result; return result;
} }
static bool subVpnListSort(const KyConnectItem* info1, const KyConnectItem* info2)
{
if (info1->m_connectState != info2->m_connectState) {
if (info1->m_connectState == 2) {
return true;
}
if (info2->m_connectState == 2) {
return false;
}
}
QString name1 = info1->m_connectName;
QString name2 = info2->m_connectName;
bool result = true;
if (QString::compare(name1, name2, Qt::CaseInsensitive) > 0) {
result = false;
}
return result;
}
static void lanListSort(QList<KyConnectItem *> &list) static void lanListSort(QList<KyConnectItem *> &list)
{ {
qSort(list.begin(), list.end(), subLanListSort); qSort(list.begin(), list.end(), subLanListSort);
} }
static void vpnListSort(QList<KyConnectItem *> &list)
{
qSort(list.begin(), list.end(), subVpnListSort);
}
KyConnectResourse::KyConnectResourse(QObject *parent) : QObject(parent) KyConnectResourse::KyConnectResourse(QObject *parent) : QObject(parent)
{ {
m_networkResourceInstance = KyNetworkResourceManager::getInstance(); m_networkResourceInstance = KyNetworkResourceManager::getInstance();
@ -200,6 +225,61 @@ KyConnectItem * KyConnectResourse::getConnectionItemByUuid(QString connectUuid,
return nullptr; return nullptr;
} }
void KyConnectResourse::getVpnAndVirtualConnections(QList<KyConnectItem *> &connectItemList)
{
int index = 0;
NetworkManager::Connection::List connectList;
qDebug()<<"[KyConnectResourse]"<<"get vpn && virtual connections";
connectList.clear();
connectList = m_networkResourceInstance->getConnectList();
if (connectList.empty()) {
qWarning()<<"[KyConnectResourse]"<<"get vpn connections failed, the connect list is empty";
return;
}
NetworkManager::Connection::Ptr connectPtr = nullptr;
for (index = 0; index < connectList.size(); index++) {
connectPtr = connectList.at(index);
if (connectPtr.isNull()) {
continue;
}
if (NetworkManager::ConnectionSettings::ConnectionType::Vpn != connectPtr->settings()->connectionType()
&& NetworkManager::ConnectionSettings::ConnectionType::Bond != connectPtr->settings()->connectionType()
&& NetworkManager::ConnectionSettings::ConnectionType::Bridge != connectPtr->settings()->connectionType()
&& NetworkManager::ConnectionSettings::ConnectionType::Vlan != connectPtr->settings()->connectionType()
&& NetworkManager::ConnectionSettings::ConnectionType::Team != connectPtr->settings()->connectionType()
&& NetworkManager::ConnectionSettings::ConnectionType::IpTunnel != connectPtr->settings()->connectionType()
&& NetworkManager::ConnectionSettings::ConnectionType::Wired != connectPtr->settings()->connectionType()) {
continue;
}
NetworkManager::Device::Ptr devicePtr = nullptr;
devicePtr = m_networkResourceInstance->findDeviceInterface(connectPtr->settings()->interfaceName());
if (NetworkManager::ConnectionSettings::ConnectionType::Wired == connectPtr->settings()->connectionType()) {
if (devicePtr == nullptr || !devicePtr->udi().startsWith("/sys/devices/virtual/net")) {
continue;
}
}
QString devName = "";
if (!devicePtr.isNull()) {
devName = devicePtr->interfaceName();
}
KyConnectItem *connectItem = getConnectionItem(connectPtr, devName);
if (nullptr != connectItem) {
connectItemList << connectItem;
}
connectPtr = nullptr;
}
if (connectItemList.size() > 1) {
vpnListSort(connectItemList);
}
}
void KyConnectResourse::getConnectionList(QString deviceName, void KyConnectResourse::getConnectionList(QString deviceName,
NetworkManager::ConnectionSettings::ConnectionType connectionType, NetworkManager::ConnectionSettings::ConnectionType connectionType,
QList<KyConnectItem *> &connectItemList) QList<KyConnectItem *> &connectItemList)
@ -748,6 +828,35 @@ void KyConnectResourse::getApConnections(QList<KyApConnectItem *> &apConnectItem
return; return;
} }
bool KyConnectResourse::isVirtualConncection(QString uuid)
{
NetworkManager::Connection::Ptr connectPtr = nullptr;
connectPtr = m_networkResourceInstance->getConnect(uuid);
if (nullptr == connectPtr) {
return false;
}
if (NetworkManager::ConnectionSettings::ConnectionType::Vpn == connectPtr->settings()->connectionType()
||NetworkManager::ConnectionSettings::ConnectionType::Bond == connectPtr->settings()->connectionType()
||NetworkManager::ConnectionSettings::ConnectionType::Bridge == connectPtr->settings()->connectionType()
||NetworkManager::ConnectionSettings::ConnectionType::Vlan == connectPtr->settings()->connectionType()
||NetworkManager::ConnectionSettings::ConnectionType::Team == connectPtr->settings()->connectionType()
||NetworkManager::ConnectionSettings::ConnectionType::IpTunnel == connectPtr->settings()->connectionType()) {
return true;
}
NetworkManager::Device::Ptr devicePtr = nullptr;
devicePtr = m_networkResourceInstance->findDeviceInterface(connectPtr->settings()->interfaceName());
if (devicePtr.isNull()) {
return false;
}
if (devicePtr->udi().startsWith("/sys/devices/virtual/net")) {
return true;
}
return false;
}
bool KyConnectResourse::isWiredConnection(QString uuid) bool KyConnectResourse::isWiredConnection(QString uuid)
{ {

View File

@ -40,6 +40,7 @@ public:
KyConnectItem *getConnectionItemByUuid(QString connectUuid); KyConnectItem *getConnectionItemByUuid(QString connectUuid);
KyConnectItem *getConnectionItemByUuidWithoutActivateChecking(QString connectUuid); KyConnectItem *getConnectionItemByUuidWithoutActivateChecking(QString connectUuid);
KyConnectItem *getConnectionItemByUuid(QString connectUuid, QString deviceName); KyConnectItem *getConnectionItemByUuid(QString connectUuid, QString deviceName);
void getVpnAndVirtualConnections(QList<KyConnectItem *> &connectItemList);
void getConnectionList(QString deviceName, void getConnectionList(QString deviceName,
NetworkManager::ConnectionSettings::ConnectionType connectionType, NetworkManager::ConnectionSettings::ConnectionType connectionType,
QList<KyConnectItem *> &connectItemList); QList<KyConnectItem *> &connectItemList);
@ -55,6 +56,7 @@ public:
bool getInterfaceByUuid(QString &deviceName, const QString connUuid); bool getInterfaceByUuid(QString &deviceName, const QString connUuid);
void getConnectivity(NetworkManager::Connectivity &connectivity); void getConnectivity(NetworkManager::Connectivity &connectivity);
bool isVirtualConncection(QString uuid);
bool isWiredConnection(QString uuid); bool isWiredConnection(QString uuid);
bool isWirelessConnection(QString uuid); bool isWirelessConnection(QString uuid);
bool isActivatedConnection(QString uuid); bool isActivatedConnection(QString uuid);

View File

@ -165,61 +165,6 @@ void KyWiredConnectOperation::deactivateWiredConnection(const QString activeConn
return; return;
} }
void KyWiredConnectOperation::activateVpnConnection(const QString connectUuid)
{
QString connectPath = "";
QString deviceIdentifier = "";
QString connectName = "";
//QString deviceName = "";
QString specificObject = "";
NetworkManager::Connection::Ptr connectPtr = nullptr;
qDebug()<<"it will activate vpn connect"<<connectUuid;
connectPtr = NetworkManager::findConnectionByUuid(connectUuid);
if (nullptr == connectPtr) {
QString errorMessage = "the connect uuid " + connectUuid + "is not exsit";
qWarning()<<errorMessage;
Q_EMIT activateConnectionError(errorMessage);
return;
}
if (NetworkManager::ConnectionSettings::Vpn != connectPtr->settings()->connectionType()) {
QString errorMessage = tr("the connect type is")
+ connectPtr->settings()->connectionType()
+ tr(", but it is not vpn");
qWarning()<<errorMessage;
Q_EMIT activateConnectionError(errorMessage);
return;
}
connectPath = connectPtr->path();
connectName = connectPtr->name();
//deviceName = connectPtr->settings()->interfaceName();
specificObject = deviceIdentifier = QStringLiteral("/");
qDebug() <<"active wired connect: path "<< connectPath
<< "device identify " << deviceIdentifier
<< "connect name " << connectName
// << "device name" << deviceName
<< "specific parameter"<< specificObject;
QDBusPendingCallWatcher * watcher;
watcher = new QDBusPendingCallWatcher{NetworkManager::activateConnection(connectPath, deviceIdentifier, specificObject), this};
connect(watcher, &QDBusPendingCallWatcher::finished, [this, connectName] (QDBusPendingCallWatcher * watcher) {
if (watcher->isError() || !watcher->isValid()) {
QString errorMessage = tr("activate vpn connection failed: ") + watcher->error().message();
qWarning()<<errorMessage;
Q_EMIT this->activateConnectionError(errorMessage);
} else {
qWarning()<<"active vpn connect complete.";
}
watcher->deleteLater();
});
return;
}
void KyWiredConnectOperation::saveActiveConnection(QString &deviceName, QString &connectUuid) void KyWiredConnectOperation::saveActiveConnection(QString &deviceName, QString &connectUuid)
{ {
QSettings *p_settings = new QSettings(WIRED_NETWORK_STATE_CONF_FILE, QSettings::IniFormat); QSettings *p_settings = new QSettings(WIRED_NETWORK_STATE_CONF_FILE, QSettings::IniFormat);

View File

@ -45,7 +45,6 @@ public:
void updateWiredConnect(const QString &connectUuid, const KyConnectSetting &connectSettingsInfo); void updateWiredConnect(const QString &connectUuid, const KyConnectSetting &connectSettingsInfo);
void deleteWiredConnect(const QString &connectUuid); void deleteWiredConnect(const QString &connectUuid);
void activateWiredConnection(const QString connectUuid, const QString devName); void activateWiredConnection(const QString connectUuid, const QString devName);
void activateVpnConnection(const QString connectUuid);
void deactivateWiredConnection(const QString activeConnectName, const QString &activeConnectUuid); void deactivateWiredConnection(const QString activeConnectName, const QString &activeConnectUuid);
int closeWiredNetworkWithDevice(QString deviceName); int closeWiredNetworkWithDevice(QString deviceName);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,515 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* Copyright (C) 2022 Tianjin KYLIN Information Technology Co., Ltd.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef KYVPNCONNECTOPERATION_H
#define KYVPNCONNECTOPERATION_H
#include <QSettings>
#include <QDir>
#include "kylinnetworkresourcemanager.h"
#include "kylinconnectsetting.h"
#include "kylinconnectoperation.h"
#include "kylinconnectresource.h"
#include "kyenterpricesettinginfo.h"
#include <NetworkManagerQt/VpnSetting>
#define VPN_SERVERTYPE_L2TP "org.freedesktop.NetworkManager.l2tp"
#define VPN_SERVERTYPE_PPTP "org.freedesktop.NetworkManager.pptp"
#define VPN_SERVERTYPE_OPENVPN "org.freedesktop.NetworkManager.openvpn"
#define VPN_SERVERTYPE_STRONGSWAN "org.freedesktop.NetworkManager.strongswan"
#define KYVPN_VPN_KEY "vpn"
#define KYVPN_GATEWAY_KEY "gateway"
#define KYVPN_REMOTE_KEY "remote"
#define KYVPN_ADDRESS_KEY "address"
#define KYVPN_USER_KEY "user"
#define KYVPN_PASSWD_KEY "password"
#define KYVPN_SECRETS_KEY "secrets"
#define KYVPN_PASSWDFLAGS_KEY "password-flags"
#define KYVPN_REFUSEPAP_KEY "refuse-pap"
#define KYVPN_REFUSECHAP_KEY "refuse-chap"
#define KYVPN_REFUSEEAP_KEY "refuse-eap"
#define KYVPN_REFUSEMSCHAP_KEY "refuse-mschap"
#define KYVPN_REFUSEMSCHAPV2_KEY "refuse-mschapv2"
#define KYVPN_NOVJCOMP_KEY "no-vj-comp"
#define KYVPN_NOACCOMP_KEY "noaccomp"
#define KYVPN_NOBSDCOMP_KEY "nobsdcomp"
#define KYVPN_NODEFLATE_KEY "nodeflate"
#define KYVPN_NOPCOMP_KEY "nopcomp"
#define KYVPN_DOMAIN_KEY "domain"
#define KYVPN_REQUIREMPPE_KEY "require-mppe"
#define KYVPN_MPPESTATEFUL_KEY "mppe-stateful"
#define KYVPN_LCPECHOFAILURE_KEY "lcp-echo-failure"
#define KYVPN_LCPECHOINTERVAL_KEY "lcp-echo-interval"
#define KYVPN_MRU_KEY "mru"
#define KYVPN_MTU_KEY "mtu"
#define KYVPN_REQUIREMPPE128_KEY "require-mppe-128"
#define KYVPN_REQUIREMPPE40_KEY "require-mppe-40"
#define KYVPN_USERCERT_KEY "usercert"
#define KYVPN_USERKEY_KEY "userkey"
#define KYVPN_CERTPASSWD_KEY "cert-pass"
#define KYVPN_CERTPASSWDFLAGS_KEY "cert-pass-flags"
#define KYVPN_PIN_KEY "pin"
#define KYVPN_VIRTUAL_KEY "virtual"
#define KYVPN_ENCAP_KEY "encap"
#define KYVPN_IPCOMP_KEY "ipcomp"
#define KYVPN_PROPOSAL_KEY "proposal"
#define KYVPN_IKE_KEY "ike"
#define KYVPN_ESP_KEY "esp"
//openvpn
#define KYVPN_CONNECTIONTYPE_KEY "connection-type"
#define KYVPN_CA_KEY "ca"
#define KYVPN_CERT_KEY "cert"
#define KYVPN_KEY_KEY "key"
#define KYVPN_USERNAME_KEY "username"
#define KYVPN_STATICKEY_KEY "static-key"
#define KYVPN_STATICKEYDIR_KEY "static-key-direction"
#define KYVPN_LOCALIP_KEY "local-ip"
#define KYVPN_REMOTEIP_KEY "remote-ip"
#define KYVPN_PORT_KEY "port"
#define KYVPN_RENEGSEC_KEY "reneg-seconds"
#define KYVPN_COMPLZO_KEY "comp-lzo"
#define KYVPN_COMPRESS_KEY "compress"
#define COMPLZO_LZODISABLE "no-by-default"
#define COMPLZO_ADAPTIVE "adaptive"
#define COMPRESS_LZO "lzo"
#define COMPRESS_LZ4 "lz4"
#define COMPRESS_LZ4V2 "lz4-v2"
#define KYVPN_PROTOTCP_KEY "proto-tcp"
#define KYVPN_DEVTYPE_KEY "dev-type"
#define DEVTYPE_TUN "tun"
#define DEVTYPE_TAP "tap"
#define KYVPN_DEV_KEY "dev"
#define KYVPN_TUNNELMTU_KEY "tunnel-mtu"
#define KYVPN_FRAGMENTSIZE_KEY "fragment-size"
#define KYVPN_MSSFIX_KEY "mssfix"
#define KYVPN_REMOTERANDOM_KEY "remote-random"
#define KYVPN_TUNIPV6_KEY "tun-ipv6"
#define KYVPN_PING_KEY "ping"
#define KYVPN_PINGEXIT_KEY "ping-exit"
#define KYVPN_PINGRESTART_KEY "ping-restart"
#define KYVPN_FLOAT_KEY "float"
#define KYVPN_MAXROUTES_KEY "max-routes"
#define KYVPN_VERIFYX509NAME_KEY "verify-x509-name"
#define X509NAME_SUBJECT "subject"
#define X509NAME_NAME "name"
#define X509NAME_NAMEPREFIX "name-prefix"
#define KYVPN_REMOTECERTTLS_KEY "remote-cert-tls"
#define KYVPN_NSCERTTYPE_KEY "ns-cert-type"
#define KYVPN_SERVER "server"
#define KYVPN_CLIENT "client"
#define KYVPN_TA_KEY "ta"
#define KYVPN_TLSCRYPT_KEY "tls-crypt"
#define KYVPN_TADIR_KEY "ta-dir"
#define KYVPN_PROXYTYPE_KEY "proxy-type"
#define PROXYTYPE_HTTP "http"
#define PROXYTYPE_SOCKS "socks"
#define KYVPN_PROXYSERVER_KEY "proxy-server"
#define KYVPN_PROXYPORT_KEY "proxy-port"
#define KYVPN_PROXYRETRY_KEY "proxy-retry"
#define KYVPN_HTTPPROXYUSERNAME_KEY "http-proxy-username"
#define KYVPN_HTTPPROXYPASSWD_KEY "http-proxy-password"
#define KYVPN_HTTPPROXYPASSWDFLAGS_KEY "http-proxy-password-flags"
#define KYVPN_KEYSIZE_KEY "keysize"
#define KYVPN_AUTH_KEY "auth"
#define KYVPN_METHOD_KEY "method"
#define KYVPN_YES "yes"
#define KYVPN_NO "no"
//VPN类型
enum KyVpnType{
KYVPNTYPE_UNKNOWN = -1,
KYVPNTYPE_L2TP = 0,
KYVPNTYPE_OPENVPN,
KYVPNTYPE_PPTP,
KYVPNTYPE_STRONGSWAN
};
//密码策略
enum KyPasswdPolicy{
KYPASSWD_FORTHISUSER = 0,
KYPASSWD_FORALLUSER,
KYPASSWD_ASKEVERYTIME,
KYPASSWD_ISNOTREQUIRED = 4
};
//认证方式
enum KyAuthMethod2 {
KYAUTH2_PAP = 1u << 0, //PAP认证
KYAUTH2_CHAP = 1u << 1, //CHAP认证
KYAUTH2_MSCHAP = 1u << 2, //MSCHAP认证
KYAUTH2_MSCHAPV2 = 1u << 3, //MSCHAPV2认证
KYAUTH2_EAP = 1u << 4, //EAP认证
KYAUTH2_ALL = KYAUTH2_PAP | KYAUTH2_CHAP | KYAUTH2_MSCHAP | KYAUTH2_MSCHAPV2 | KYAUTH2_EAP
};
Q_DECLARE_FLAGS(KyAuthMethods, KyAuthMethod2)
//压缩方式
enum KyCompressMethod {
KYCOMP_BSD = 1u << 0, //允许BSD压缩
KYCOMP_DEFLATE = 1u << 1, //允许Deflate压缩
KYCOMP_TCP = 1u << 2, //允许TCP头压缩
KYCOMP_PROTO = 1u << 3, //使用协议域压缩协商
KYCOMP_ADDR = 1u << 4, //使用地址/控制压缩
KYCOMP_ALL = KYCOMP_BSD | KYCOMP_DEFLATE | KYCOMP_TCP | KYCOMP_PROTO | KYCOMP_ADDR
};
Q_DECLARE_FLAGS(KyCompressMethods, KyCompressMethod)
//高级设置
enum KyMPPEMethod {
KYMPPE_DEFAULT = 0, //默认MPPE加密
KYMPPE_REQUIRE128, //128位加密
KYMPPE_REQUIRE40 //40位加密
};
enum KyAuthMethod{
KYAUTH_ERROR = -1,
KYAUTH_PASSWD = 0,
KYAUTH_KEY,
KYAUTH_AGENT,
KYAUTH_SMARTCARD,
KYAUTH_EAP,
KYAUTH_CERTIFICATE,
KYAUTH_CERTIFICATEANDPASSWD,
KYAUTH_STATICPASSWD
};
enum KyCompressMethod2{
KYCOMP2_LZODISABLE = 0,
KYCOMP2_LZO,
KYCOMP2_LZ4,
KYCOMP2_LZ4V2,
KYCOMP2_LZOADAPTIVE,
KYCOMP2_AUTO
};
enum KyVirtualDeviceType{
KYVIRDEVTYPE_TUN = 0,
KYVIRDEVTYPE_TAP
};
enum KyVpnPingMethod{
KYVPNPING_EXIT = 0,
KYVPNPING_RESTART
};
enum KyVpnCheckServerMethod{
KYCHECKSERVER_NONE = 0,
KYCHECKSERVER_ENTIRETHEME,
KYCHECKSERVER_ENTIRENAME,
KYCHECKSERVER_PRENAME
};
enum KyVpnCertType{
KYVPNCERT_SERVER = 0,
KYVPNCERT_CLIENT
};
enum KyVpnTlsMode{
KYVPNTLS_NONE = 0,
KYVPNTLS_AUTHENTICATION,
KYVPNTLS_CRYPT
};
enum KyVpnProxyType{
KYVPNPROXY_NONE = 0,
KYVPNPROXY_HTTP,
KYVPNPROXY_SOCKS
};
enum KyHMACAuthMethod{
KYHMACAUTH_DEFAULT = 0,
KYHMACAUTH_NONE,
KYHMACAUTH_MD4,
KYHMACAUTH_MD5,
KYHMACAUTH_SHA1,
KYHMACAUTH_SHA224,
KYHMACAUTH_SHA256,
KYHMACAUTH_SHA384,
KYHMACAUTH_SHA512,
KYHMACAUTH_RIPEMD160
};
class KyVpnConfig : public KyConnectSetting
{
public:
KyVpnType m_vpnType;
QString m_vpnName;
QString m_gateway;
//认证方式
KyAuthMethod m_authMethod;
//VPN用户密码信息
QString m_userName;
//用户密码
QString m_userPasswd;
//密码策略
KyPasswdPolicy m_passwdPolicy = KYPASSWD_ASKEVERYTIME;
//NT域
QString m_ntDomain;
//CA证书
QString m_caCertificate;
//用户证书
QString m_userCertificate;
//用户私钥
QString m_userKey;
//静态密钥
QString m_staticKey;
//用户私有密钥密码
QString m_privatePasswd;
//用户私有密码策略
KyPasswdPolicy m_privatePasswdPolicy = KYPASSWD_ASKEVERYTIME;
//密钥方向
QString m_vpnKeyDir;
//本地IP地址
QString m_localAddress;
//远程IP地址
QString m_remoteAddress;
//PIN码
QString m_pinId;
//MPPE加密开关
bool m_mppeEnable = false;
//MPPE加密算法
KyMPPEMethod m_mppeEncryptMethod = KYMPPE_DEFAULT;
//使用有状态加密
bool m_isAllowStatefulEncryption = false;
//发送PPP回显包
bool m_sendPppPackage = false;
//认证方式
KyAuthMethods m_authMethods = KYAUTH2_ALL;
//压缩方式
KyCompressMethods m_compressMethods = KYCOMP_ALL;
//MRU 最大接收单元
QString m_mru;
//MTU 最大传输单元
QString m_mtu;
//请求使用内部IP
bool m_virtual;
//强制UDP封装
bool m_encap;
//使用IP压缩
bool m_ipcomp;
//启用自定义密码建议
bool m_proposal;
//IKE
QString m_ike;
//ESP
QString m_esp;
//使用自定义网关端口
bool m_useAssignPort;
QString m_assignPort;
//使用自定义重协商间隔
bool m_useRenegSeconds;
QString m_renegSeconds;
//使用压缩
bool m_useCompress;
KyCompressMethod2 m_openvpnCompress;
//使用TCP连接
bool m_useTcpLink;
//设置虚拟设备类型
bool m_setDevType;
KyVirtualDeviceType m_devType;
//设置虚拟设备名称
bool m_setDevName;
QString m_devName;
//使用自定义隧道最大单元传输
bool m_useTunnelMtu;
QString m_tunnelMtu;
//使用自定义UDP分片大小
bool m_useFragmentSize;
QString m_fragmentSize;
//限制TCP最大段尺寸
bool m_mssfix;
//随机化远程主机
bool m_remoteRandom;
//IPv6 tun link
bool m_ipv6TunLink;
//指定Ping周期
bool m_setPingCycle;
QString m_pingCycle;
//指定退出或重启Ping
bool m_usePingMethod;
KyVpnPingMethod m_pingMethod;
QString m_pingMethodTime;
//接受来自任何地址Float已通过身份验证的数据包
bool m_float;
//指定路由上限
bool m_setMaxRoute;
QString m_maxRoute;
//服务器证书检验
KyVpnCheckServerMethod m_checkServerCa;
//主题匹配
QString m_verifyName;
//验证对等(服务器)证书用法签名
bool m_useRemoteCertTls;
KyVpnCertType m_remoteCertType;
//验证对等服务器证书nsCertType签名
bool m_useNsCertTls;
KyVpnCertType m_nsCertType;
//其他TLS身份验证
//模式
KyVpnTlsMode m_vpnTlsMode;
//密钥文件
QString m_vpnKeyFile;
//密钥方向
QString m_vpnTlsTaDir;
//代理
//代理类型
KyVpnProxyType m_vpnProxyType;
//服务器地址
QString m_vpnProxyServer;
//端口
QString m_vpnProxyPort;
//出错时无限重试
bool m_vpnProxyRetry;
//代理用户名
QString m_vpnProxyName;
//代理用户名
QString m_vpnProxyPasswd;
//代理密码策略
KyPasswdPolicy m_vpnProxyPasswdPolicy = KYPASSWD_ASKEVERYTIME;
//安全
//使用自定义密钥大小
bool m_useKeysize;
QString m_keySize;
//HMAC认证
KyHMACAuthMethod m_hmacAuthMethod;
//IPv4Setting
QStringList m_ipv4DnsSearch;
QString m_ipv4DhcpClientId;
//IPv6Setting
QStringList m_ipv6DnsSearch;
};
class KyVpnConnectOperation : public KyConnectOperation
{
Q_OBJECT
public:
explicit KyVpnConnectOperation(QObject *parent = nullptr);
public:
void createVpnConnect(KyVpnConfig &vpnSettings);
void setVpnConfig(QString connectUuid, KyVpnConfig &vpnConfig);
KyVpnConfig getVpnConfig(QString connectUuid);
void activateVpnConnection(const QString connectUuid);
void deactivateVpnConnection(const QString activeConnectName, const QString &activeConnectUuid);
void deleteVpnConnect(const QString &connectUuid);
private:
KyHMACAuthMethod getHmacAuthMethod(const QString method);
KyAuthMethod getAuthMethod(const QString method);
void getConnectionSetting(QString connectUuid, KyVpnConfig &vpnConfig);
void setConnectionSetting(NetworkManager::ConnectionSettings::Ptr connectionSettings, KyVpnConfig &vpnConfig);
void getL2tpConfig(KyVpnConfig &vpnConfig);
void setL2tpConfig(KyVpnConfig &vpnConfig);
void getPptpConfig(KyVpnConfig &vpnConfig);
void setPptpConfig(KyVpnConfig &vpnConfig);
void getStrongswanConfig(KyVpnConfig &vpnConfig);
void setStrongswanConfig(KyVpnConfig &vpnConfig);
void getOpenvpnConfig(KyVpnConfig &vpnConfig);
void setOpenvpnConfig(KyVpnConfig &vpnConfig);
void getUsrPasswdAndPolicy(KyVpnConfig &vpnConfig);
void setUsrPasswdAndPolicy(KyVpnConfig &vpnConfig);
void getCertPasswdAndPolicy(KyVpnConfig &vpnConfig);
void setCertPasswdAndPolicy(KyVpnConfig &vpnConfig);
NMVariantMapMap setIpConfig(NetworkManager::ConnectionSettings::Ptr connectionSettings, KyVpnConfig &vpnConfig);
private:
QMap<QString, KyAuthMethod> m_authMethodMap = {
{"password" , KYAUTH_PASSWD },
{"key" , KYAUTH_KEY },
{"agent" , KYAUTH_AGENT },
{"smartcard" , KYAUTH_SMARTCARD },
{"eap" , KYAUTH_EAP },
{"tls" , KYAUTH_CERTIFICATE },
{"password-tls" , KYAUTH_CERTIFICATEANDPASSWD },
{"static-password" , KYAUTH_STATICPASSWD }
};
QMap<QString, KyHMACAuthMethod> m_hmacMap = {
{"none" , KYHMACAUTH_NONE },
{"RSA-MD4" , KYHMACAUTH_MD4 },
{"MD5" , KYHMACAUTH_MD5 },
{"SHA1" , KYHMACAUTH_SHA1 },
{"SHA224" , KYHMACAUTH_SHA224 },
{"SHA256" , KYHMACAUTH_SHA256 },
{"SHA384" , KYHMACAUTH_SHA384 },
{"SHA512" , KYHMACAUTH_SHA512 },
{"RIPEMD160" , KYHMACAUTH_RIPEMD160 }
};
NMStringMap m_vpnData;
NMStringMap m_vpnSecrets;
};
#endif // KYVPNCONNECTOPERATION_H