添加VPN相关代码(框架)
This commit is contained in:
parent
f13e392f14
commit
e823aae0e2
|
@ -5,6 +5,7 @@ CONFIG += ordered \
|
|||
|
||||
SUBDIRS = \
|
||||
plugins/plugin.pro \
|
||||
src-vpn/src-vpn.pro \
|
||||
src \
|
||||
|
||||
TRANSLATIONS += \
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
INCLUDEPATH += $$PWD
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/vpnobject.h
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/vpnobject.cpp
|
|
@ -0,0 +1,102 @@
|
|||
#include "vpnobject.h"
|
||||
#include <QApplication>
|
||||
#include <QDebug>
|
||||
|
||||
#include "ukuistylehelper/ukuistylehelper.h"
|
||||
|
||||
#define MAINWINDOW_WIDTH 420
|
||||
#define MAINWINDOW_HEIGHT 476
|
||||
|
||||
vpnObject::vpnObject(QMainWindow *parent) : QMainWindow(parent)
|
||||
{
|
||||
initUI();
|
||||
initTrayIcon();
|
||||
initDbusConnnect();
|
||||
this->setFixedSize(MAINWINDOW_WIDTH, MAINWINDOW_HEIGHT);
|
||||
}
|
||||
|
||||
vpnObject::~vpnObject()
|
||||
{
|
||||
if (m_vpnGsettings != nullptr) {
|
||||
delete m_vpnGsettings;
|
||||
m_vpnGsettings = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void vpnObject::initUI()
|
||||
{
|
||||
vpnWidget = new QWidget(this);
|
||||
QPalette pal = qApp->palette();
|
||||
// pal.set
|
||||
vpnWidget->setPalette(pal);
|
||||
this->setCentralWidget(vpnWidget);
|
||||
}
|
||||
|
||||
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(this->isActiveWindow()) {
|
||||
this->hide();
|
||||
} else {
|
||||
onShowMainWindow();
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void vpnObject::onShowMainWindow()
|
||||
{
|
||||
//去除窗管标题栏,传入参数为QWidget*
|
||||
kdk::UkuiStyleHelper::self()->removeHeader(this);
|
||||
this->show();
|
||||
this->raise();
|
||||
this->activateWindow();
|
||||
}
|
||||
|
||||
void vpnObject::initDbusConnnect()
|
||||
{
|
||||
//模式切换
|
||||
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)
|
||||
//模式切换时,隐藏主界面
|
||||
this->hide();
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
#ifndef VPNOBJECT_H
|
||||
#define VPNOBJECT_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QWidget>
|
||||
#include <QScreen>
|
||||
#include <QSystemTrayIcon>
|
||||
#include <QMainWindow>
|
||||
#include <QGSettings>
|
||||
#include <QDBusInterface>
|
||||
|
||||
#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();
|
||||
|
||||
private:
|
||||
void initUI();
|
||||
void initTrayIcon();
|
||||
void initVpnIconVisible();
|
||||
void initDbusConnnect();
|
||||
|
||||
|
||||
private:
|
||||
QWidget * vpnWidget = nullptr;
|
||||
|
||||
QSystemTrayIcon * m_vpnTrayIcon = nullptr;
|
||||
QGSettings * m_vpnGsettings; //VPN配置文件
|
||||
QGSettings * StyleSettings = nullptr;
|
||||
double tran =1;
|
||||
|
||||
QDBusInterface * m_positionInterface = nullptr;
|
||||
bool m_isShowInCenter = false;
|
||||
|
||||
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
|
|
@ -0,0 +1,8 @@
|
|||
INCLUDEPATH += $$PWD
|
||||
|
||||
HEADERS += \
|
||||
$$PWD/kylinvpndbus.h \
|
||||
|
||||
SOURCES += \
|
||||
$$PWD/kylinvpndbus.cpp \
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#include "kylinvpndbus.h"
|
||||
|
||||
KylinVpnDbus::KylinVpnDbus(QObject *parent) : QObject(parent)
|
||||
{
|
||||
qDBusRegisterMetaType<QVector<QStringList> >();
|
||||
}
|
||||
|
||||
void KylinVpnDbus::getVirtualList(QVector<QStringList> &vector)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void KylinVpnDbus::deleteVpn(const QString &connUuid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void KylinVpnDbus::activateVpn(const QString &connUuid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void KylinVpnDbus::deactivateVpn(const QString &connUuid)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void KylinVpnDbus::showKylinVpn()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void KylinVpnDbus::showVpnAddWidget()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void KylinVpnDbus::showDetailPage(const QString &connUuid)
|
||||
{
|
||||
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef KYLINVPNDBUS_H
|
||||
#define KYLINVPNDBUS_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QDBusMetaType>
|
||||
#include <QMetaObject>
|
||||
#include <QMetaType>
|
||||
#include <QDBusConnection>
|
||||
|
||||
#include <kylin-nm/kylinnetworkmanager.h>
|
||||
|
||||
class KylinVpnDbus : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_CLASSINFO("D-Bus Interface", "com.kylin.kylinvpntest")
|
||||
public:
|
||||
explicit KylinVpnDbus(QObject *parent = nullptr);
|
||||
~KylinVpnDbus() = default;
|
||||
|
||||
public Q_SLOTS:
|
||||
Q_NOREPLY void getVirtualList(QVector<QStringList> &vector);
|
||||
//删除
|
||||
Q_NOREPLY void deleteVpn(const QString &connUuid);
|
||||
//连接
|
||||
Q_NOREPLY void activateVpn(const QString& connUuid);
|
||||
//断开
|
||||
Q_NOREPLY void deactivateVpn(const QString& connUuid);
|
||||
|
||||
void showKylinVpn();
|
||||
|
||||
Q_NOREPLY void showVpnAddWidget();
|
||||
Q_NOREPLY void showDetailPage(const QString& connUuid);
|
||||
|
||||
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 // KYLINVPNDBUS_H
|
|
@ -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
|
|
@ -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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
//#include "mainwindow.h"
|
||||
#include "kylinvpndbus.h"
|
||||
#include <QTranslator>
|
||||
#include <QLocale>
|
||||
#include "qt-single-application.h"
|
||||
#include <QDebug>
|
||||
#include <QDesktopWidget>
|
||||
#include <QFile>
|
||||
#include <QDateTime>
|
||||
#include <QStandardPaths>
|
||||
#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"));
|
||||
|
||||
auto connection = QDBusConnection::sessionBus();
|
||||
KylinVpnDbus dbusObject(&vpnobject);
|
||||
if (!connection.registerService("com.kylin.kylinvpntest")
|
||||
|| !connection.registerObject("/com/kylin/kylinvpntest", &dbusObject,
|
||||
QDBusConnection::ExportAllSlots | QDBusConnection :: ExportAllSignals)) {
|
||||
qCritical() << "QDbus register service failed reason:" << connection.lastError();
|
||||
}
|
||||
|
||||
return a.exec();
|
||||
}
|
|
@ -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>
|
|
@ -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); //获取新进程的启动信息并作为信号发送给前端
|
||||
}
|
|
@ -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
|
|
@ -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();
|
||||
}
|
||||
|
|
@ -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.
|
||||
*/
|
|
@ -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
|
|
@ -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 "../frontend/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
|
||||
*/
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,74 @@
|
|||
#-------------------------------------------------
|
||||
#
|
||||
# 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
|
||||
#LIBS += -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(frontend/frontend.pri)
|
||||
include(kylin-vpn-dbus/kylin-vpn-dbus.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
|
|
@ -0,0 +1 @@
|
|||
<クdハ<>箆!ソ`。スン
|
|
@ -0,0 +1,144 @@
|
|||
<?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>
|
||||
<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>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>vpnObject</name>
|
||||
<message>
|
||||
<location filename="../frontend/vpnobject.cpp" line="31"/>
|
||||
<source>vpn tool</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
Binary file not shown.
|
@ -0,0 +1,835 @@
|
|||
<?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'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 '1' is used, the connection must use '0'. 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'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>
|
||||
<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>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>vpnObject</name>
|
||||
<message>
|
||||
<location filename="../frontend/vpnobject.cpp" line="31"/>
|
||||
<source>vpn tool</source>
|
||||
<translation>VPN工具</translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
|
@ -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>
|
Loading…
Reference in New Issue