507 lines
15 KiB
C++
507 lines
15 KiB
C++
|
|
#include "licensemanager.h"
|
|||
|
|
#include <QProcess>
|
|||
|
|
#include <QFile>
|
|||
|
|
#include <QTextStream>
|
|||
|
|
#include <QMessageBox>
|
|||
|
|
#include <QCryptographicHash>
|
|||
|
|
#include <QVBoxLayout>
|
|||
|
|
#include <QHBoxLayout>
|
|||
|
|
#include <QLabel>
|
|||
|
|
#include <QLineEdit>
|
|||
|
|
#include <QPushButton>
|
|||
|
|
#include <QDir>
|
|||
|
|
#include <QApplication>
|
|||
|
|
#include <QClipboard>
|
|||
|
|
#include <QDebug>
|
|||
|
|
#include <QTcpSocket>
|
|||
|
|
#include <QJsonDocument>
|
|||
|
|
#include <QJsonObject>
|
|||
|
|
#include <QDateTime>
|
|||
|
|
|
|||
|
|
// ==================== 静态成员初始化 ====================
|
|||
|
|
// 加密密钥
|
|||
|
|
const QByteArray LicenseManager::encryptKey = "GetonAgain2026SecretKey!@#$%";
|
|||
|
|
// 客户专用密码 - 根据不同客户修改此值
|
|||
|
|
const QString LicenseManager::customerPassword = "nuobo123";
|
|||
|
|
|
|||
|
|
// ==================== LicenseManager 实现 ====================
|
|||
|
|
|
|||
|
|
LicenseManager::LicenseManager(QObject *parent) : QObject(parent)
|
|||
|
|
{
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString LicenseManager::getMachineUUID()
|
|||
|
|
{
|
|||
|
|
QString uuid;
|
|||
|
|
|
|||
|
|
#ifdef Q_OS_WIN
|
|||
|
|
// Windows: 通过WMI获取主板UUID
|
|||
|
|
QProcess process;
|
|||
|
|
process.start("wmic", QStringList() << "csproduct" << "get" << "UUID");
|
|||
|
|
process.waitForFinished(5000);
|
|||
|
|
QString output = QString::fromLocal8Bit(process.readAllStandardOutput());
|
|||
|
|
|
|||
|
|
// 解析输出,获取UUID
|
|||
|
|
QStringList lines = output.split('\n', Qt::SkipEmptyParts);
|
|||
|
|
for (const QString &line : lines)
|
|||
|
|
{
|
|||
|
|
QString trimmed = line.trimmed();
|
|||
|
|
if (!trimmed.isEmpty() && trimmed != "UUID" && trimmed.contains('-'))
|
|||
|
|
{
|
|||
|
|
uuid = trimmed;
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
#else
|
|||
|
|
// Linux/Mac: 读取machine-id
|
|||
|
|
QFile file("/etc/machine-id");
|
|||
|
|
if (file.open(QIODevice::ReadOnly))
|
|||
|
|
{
|
|||
|
|
uuid = QString::fromUtf8(file.readAll()).trimmed();
|
|||
|
|
file.close();
|
|||
|
|
}
|
|||
|
|
#endif
|
|||
|
|
|
|||
|
|
if (uuid.isEmpty())
|
|||
|
|
{
|
|||
|
|
// 备用方案:使用机器名+用户名的哈希
|
|||
|
|
QString fallback = QSysInfo::machineHostName() + QDir::homePath();
|
|||
|
|
uuid = QString::fromLatin1(QCryptographicHash::hash(fallback.toUtf8(), QCryptographicHash::Md5).toHex());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return uuid;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString LicenseManager::getLicenseFilePath()
|
|||
|
|
{
|
|||
|
|
// 激活文件放在程序目录下
|
|||
|
|
return QCoreApplication::applicationDirPath() + "/license.gal";
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString LicenseManager::encrypt(const QString &plainText)
|
|||
|
|
{
|
|||
|
|
QByteArray data = plainText.toUtf8();
|
|||
|
|
|
|||
|
|
// 第一步:计算明文的SHA256哈希(用于完整性校验)
|
|||
|
|
QByteArray hash = QCryptographicHash::hash(data, QCryptographicHash::Sha256);
|
|||
|
|
|
|||
|
|
// 第二步:构造加密数据 = 哈希前8字节 + 原始数据
|
|||
|
|
QByteArray toEncrypt;
|
|||
|
|
toEncrypt.append(hash.left(8)); // 8字节校验头
|
|||
|
|
toEncrypt.append(data);
|
|||
|
|
|
|||
|
|
// 第三步:多层XOR加密
|
|||
|
|
QByteArray encrypted;
|
|||
|
|
for (int i = 0; i < toEncrypt.size(); ++i)
|
|||
|
|
{
|
|||
|
|
unsigned char c = static_cast<unsigned char>(toEncrypt[i]);
|
|||
|
|
|
|||
|
|
// 第一层:与主密钥XOR
|
|||
|
|
c = c ^ static_cast<unsigned char>(encryptKey[i % encryptKey.size()]);
|
|||
|
|
|
|||
|
|
// 第二层:字节置换(非线性变换)
|
|||
|
|
c = static_cast<unsigned char>((c * 7 + 13) % 256);
|
|||
|
|
|
|||
|
|
// 第三层:与位置相关的混淆
|
|||
|
|
c = c ^ static_cast<unsigned char>((i * 31 + 17) % 256);
|
|||
|
|
|
|||
|
|
encrypted.append(static_cast<char>(c));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 第四步:Base64编码
|
|||
|
|
return QString::fromLatin1(encrypted.toBase64());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString LicenseManager::decrypt(const QString &encryptedText)
|
|||
|
|
{
|
|||
|
|
// Base64解码
|
|||
|
|
QByteArray encrypted = QByteArray::fromBase64(encryptedText.toLatin1());
|
|||
|
|
|
|||
|
|
if (encrypted.size() < 9) // 至少8字节校验头 + 1字节数据
|
|||
|
|
{
|
|||
|
|
return QString();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 逆向解密
|
|||
|
|
QByteArray decrypted;
|
|||
|
|
for (int i = 0; i < encrypted.size(); ++i)
|
|||
|
|
{
|
|||
|
|
unsigned char c = static_cast<unsigned char>(encrypted[i]);
|
|||
|
|
|
|||
|
|
// 逆向第三层:位置混淆
|
|||
|
|
c = c ^ static_cast<unsigned char>((i * 31 + 17) % 256);
|
|||
|
|
|
|||
|
|
// 逆向第二层:字节置换的逆运算
|
|||
|
|
// 原式: c' = (c * 7 + 13) % 256
|
|||
|
|
// 需要找到 7 在 mod 256 下的逆元
|
|||
|
|
// 7 * 183 = 1281 = 5 * 256 + 1, 所以 7^(-1) ≡ 183 (mod 256)
|
|||
|
|
c = static_cast<unsigned char>(((c + 256 - 13) * 183) % 256);
|
|||
|
|
|
|||
|
|
// 逆向第一层:与主密钥XOR
|
|||
|
|
c = c ^ static_cast<unsigned char>(encryptKey[i % encryptKey.size()]);
|
|||
|
|
|
|||
|
|
decrypted.append(static_cast<char>(c));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 提取校验头和原始数据
|
|||
|
|
QByteArray storedHash = decrypted.left(8);
|
|||
|
|
QByteArray originalData = decrypted.mid(8);
|
|||
|
|
|
|||
|
|
// 验证哈希
|
|||
|
|
QByteArray computedHash = QCryptographicHash::hash(originalData, QCryptographicHash::Sha256);
|
|||
|
|
if (computedHash.left(8) != storedHash)
|
|||
|
|
{
|
|||
|
|
qDebug() << "License integrity check failed - data may be corrupted or tampered";
|
|||
|
|
return QString(); // 返回空表示解密失败
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return QString::fromUtf8(originalData);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString LicenseManager::generateActivationCode(const QString &uuid)
|
|||
|
|
{
|
|||
|
|
// 生成激活码格式: encrypt(UUID:password)
|
|||
|
|
// 这个方法供管理员/供应商使用,为特定设备生成激活码
|
|||
|
|
QString plainText = uuid + ":" + customerPassword;
|
|||
|
|
return encrypt(plainText);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool LicenseManager::readAndVerifyLicense()
|
|||
|
|
{
|
|||
|
|
QString filePath = getLicenseFilePath();
|
|||
|
|
QFile file(filePath);
|
|||
|
|
|
|||
|
|
if (!file.exists())
|
|||
|
|
{
|
|||
|
|
qDebug() << "License file not found:" << filePath;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
|
|||
|
|
{
|
|||
|
|
qDebug() << "Cannot open license file";
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QTextStream in(&file);
|
|||
|
|
QString encryptedContent = in.readAll().trimmed();
|
|||
|
|
file.close();
|
|||
|
|
|
|||
|
|
if (encryptedContent.isEmpty())
|
|||
|
|
{
|
|||
|
|
qDebug() << "License file is empty";
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 解密
|
|||
|
|
QString decrypted = decrypt(encryptedContent);
|
|||
|
|
qDebug() << "Decrypted license content (debug)";
|
|||
|
|
|
|||
|
|
// 解析格式: UUID:password
|
|||
|
|
// 使用 lastIndexOf 因为UUID中也可能包含冒号(虽然通常不会)
|
|||
|
|
int separatorIndex = decrypted.lastIndexOf(':');
|
|||
|
|
if (separatorIndex == -1)
|
|||
|
|
{
|
|||
|
|
qDebug() << "Invalid license format: no separator";
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString licenseUUID = decrypted.left(separatorIndex);
|
|||
|
|
QString password = decrypted.mid(separatorIndex + 1);
|
|||
|
|
|
|||
|
|
// 获取本机真实UUID
|
|||
|
|
QString currentUUID = getMachineUUID();
|
|||
|
|
|
|||
|
|
qDebug() << "License UUID:" << licenseUUID;
|
|||
|
|
qDebug() << "Current UUID:" << currentUUID;
|
|||
|
|
|
|||
|
|
// 验证UUID是否匹配
|
|||
|
|
if (licenseUUID != currentUUID)
|
|||
|
|
{
|
|||
|
|
qDebug() << "UUID mismatch - license not valid for this machine";
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 验证密码是否正确
|
|||
|
|
if (password != customerPassword)
|
|||
|
|
{
|
|||
|
|
qDebug() << "Password mismatch";
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
qDebug() << "License verification successful";
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool LicenseManager::saveLicenseFile(const QString &activationCode)
|
|||
|
|
{
|
|||
|
|
QString filePath = getLicenseFilePath();
|
|||
|
|
QFile file(filePath);
|
|||
|
|
|
|||
|
|
if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
|
|||
|
|
{
|
|||
|
|
qDebug() << "Cannot save license file to:" << filePath;
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QTextStream out(&file);
|
|||
|
|
out << activationCode;
|
|||
|
|
file.close();
|
|||
|
|
|
|||
|
|
qDebug() << "License file saved to:" << filePath;
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool LicenseManager::showActivationDialog(QWidget *parent)
|
|||
|
|
{
|
|||
|
|
ActivationDialog dialog(parent);
|
|||
|
|
|
|||
|
|
while (true)
|
|||
|
|
{
|
|||
|
|
if (dialog.exec() != QDialog::Accepted)
|
|||
|
|
{
|
|||
|
|
return false; // 用户取消
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString serverAddress = dialog.getServerAddress();
|
|||
|
|
QString activationCode = dialog.getActivationCode();
|
|||
|
|
|
|||
|
|
// 解析服务器地址和端口
|
|||
|
|
QString host;
|
|||
|
|
int port = 8080;
|
|||
|
|
if (serverAddress.contains(':'))
|
|||
|
|
{
|
|||
|
|
QStringList parts = serverAddress.split(':');
|
|||
|
|
host = parts[0];
|
|||
|
|
port = parts[1].toInt();
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
host = serverAddress;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 显示连接中提示
|
|||
|
|
QMessageBox waitMsg(parent);
|
|||
|
|
waitMsg.setWindowTitle("请稍候");
|
|||
|
|
waitMsg.setText("正在连接激活服务器...");
|
|||
|
|
waitMsg.setStandardButtons(QMessageBox::NoButton);
|
|||
|
|
waitMsg.show();
|
|||
|
|
QApplication::processEvents();
|
|||
|
|
|
|||
|
|
// 连接服务器
|
|||
|
|
QTcpSocket socket;
|
|||
|
|
socket.connectToHost(host, port);
|
|||
|
|
|
|||
|
|
bool connected = socket.waitForConnected(10000); // 10秒超时
|
|||
|
|
|
|||
|
|
if (!connected)
|
|||
|
|
{
|
|||
|
|
waitMsg.close();
|
|||
|
|
QMessageBox::warning(parent, "连接失败",
|
|||
|
|
QString("无法连接到服务器 %1:%2\n请检查网络连接和服务器地址。").arg(host).arg(port));
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 构建激活请求
|
|||
|
|
QJsonObject requestObj;
|
|||
|
|
requestObj["uuid"] = getMachineUUID();
|
|||
|
|
requestObj["code"] = activationCode;
|
|||
|
|
requestObj["timestamp"] = QDateTime::currentDateTime().toString(Qt::ISODate);
|
|||
|
|
QJsonDocument doc(requestObj);
|
|||
|
|
QByteArray requestData = doc.toJson(QJsonDocument::Compact);
|
|||
|
|
|
|||
|
|
// 发送请求
|
|||
|
|
socket.write(requestData);
|
|||
|
|
socket.write("\n");
|
|||
|
|
socket.flush();
|
|||
|
|
|
|||
|
|
// 等待响应
|
|||
|
|
if (!socket.waitForReadyRead(15000)) // 15秒超时
|
|||
|
|
{
|
|||
|
|
waitMsg.close();
|
|||
|
|
socket.close();
|
|||
|
|
QMessageBox::warning(parent, "激活失败", "服务器响应超时,请重试。");
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QByteArray response = socket.readAll();
|
|||
|
|
socket.close();
|
|||
|
|
waitMsg.close();
|
|||
|
|
|
|||
|
|
// 解析响应
|
|||
|
|
QJsonDocument responseDoc = QJsonDocument::fromJson(response);
|
|||
|
|
if (responseDoc.isNull() || !responseDoc.isObject())
|
|||
|
|
{
|
|||
|
|
QMessageBox::warning(parent, "激活失败", "服务器响应格式错误。");
|
|||
|
|
continue;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QJsonObject responseObj = responseDoc.object();
|
|||
|
|
QString status = responseObj["status"].toString();
|
|||
|
|
|
|||
|
|
if (status == "success")
|
|||
|
|
{
|
|||
|
|
QString license = responseObj["license"].toString();
|
|||
|
|
|
|||
|
|
// 保存激活文件
|
|||
|
|
if (saveLicenseFile(license))
|
|||
|
|
{
|
|||
|
|
// 验证保存的激活文件
|
|||
|
|
if (readAndVerifyLicense())
|
|||
|
|
{
|
|||
|
|
QMessageBox::information(parent, "成功", "软件激活成功!");
|
|||
|
|
return true;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QMessageBox::warning(parent, "错误", "保存激活文件失败!");
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
QString message = responseObj["message"].toString();
|
|||
|
|
if (message.isEmpty())
|
|||
|
|
message = "激活失败,请检查激活码是否正确。";
|
|||
|
|
|
|||
|
|
QMessageBox::StandardButton retry = QMessageBox::warning(
|
|||
|
|
parent, "激活失败", message,
|
|||
|
|
QMessageBox::Retry | QMessageBox::Cancel);
|
|||
|
|
|
|||
|
|
if (retry != QMessageBox::Retry)
|
|||
|
|
{
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== ActivationDialog 实现 ====================
|
|||
|
|
|
|||
|
|
ActivationDialog::ActivationDialog(QWidget *parent) : QDialog(parent)
|
|||
|
|
{
|
|||
|
|
setWindowTitle("软件激活");
|
|||
|
|
setFixedSize(420, 240);
|
|||
|
|
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
|||
|
|
|
|||
|
|
// 确保对话框接收键盘输入
|
|||
|
|
setAttribute(Qt::WA_InputMethodEnabled, true);
|
|||
|
|
|
|||
|
|
setupUI();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString ActivationDialog::getServerAddress() const
|
|||
|
|
{
|
|||
|
|
return serverEdit->text().trimmed();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString ActivationDialog::getActivationCode() const
|
|||
|
|
{
|
|||
|
|
return codeEdit->text().trimmed();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void ActivationDialog::setupUI()
|
|||
|
|
{
|
|||
|
|
QVBoxLayout *mainLayout = new QVBoxLayout(this);
|
|||
|
|
mainLayout->setContentsMargins(25, 20, 25, 20);
|
|||
|
|
mainLayout->setSpacing(12);
|
|||
|
|
|
|||
|
|
// 标题
|
|||
|
|
QLabel *titleLabel = new QLabel("软件激活");
|
|||
|
|
titleLabel->setStyleSheet("font-size: 20px; font-weight: bold; color: #333;");
|
|||
|
|
titleLabel->setAlignment(Qt::AlignCenter);
|
|||
|
|
mainLayout->addWidget(titleLabel);
|
|||
|
|
|
|||
|
|
mainLayout->addSpacing(8);
|
|||
|
|
|
|||
|
|
// 提示信息
|
|||
|
|
QLabel *infoLabel = new QLabel("请输入激活服务器地址和激活码");
|
|||
|
|
infoLabel->setStyleSheet("font-size: 12px; color: #666;");
|
|||
|
|
infoLabel->setAlignment(Qt::AlignCenter);
|
|||
|
|
mainLayout->addWidget(infoLabel);
|
|||
|
|
|
|||
|
|
mainLayout->addSpacing(8);
|
|||
|
|
|
|||
|
|
// 服务器地址输入 - 使用 QFormLayout 风格
|
|||
|
|
QHBoxLayout *serverLayout = new QHBoxLayout();
|
|||
|
|
serverLayout->setSpacing(10);
|
|||
|
|
QLabel *serverLabel = new QLabel("服务器地址:");
|
|||
|
|
serverLabel->setFixedWidth(80);
|
|||
|
|
serverLabel->setStyleSheet("font-size: 13px;");
|
|||
|
|
|
|||
|
|
serverEdit = new QLineEdit();
|
|||
|
|
serverEdit->setMinimumHeight(32);
|
|||
|
|
serverEdit->setPlaceholderText("例如: 192.168.1.100:8080");
|
|||
|
|
serverEdit->setStyleSheet("font-size: 13px; padding: 4px 8px;");
|
|||
|
|
|
|||
|
|
serverLayout->addWidget(serverLabel);
|
|||
|
|
serverLayout->addWidget(serverEdit, 1);
|
|||
|
|
mainLayout->addLayout(serverLayout);
|
|||
|
|
|
|||
|
|
// 激活码输入
|
|||
|
|
QHBoxLayout *codeLayout = new QHBoxLayout();
|
|||
|
|
codeLayout->setSpacing(10);
|
|||
|
|
QLabel *codeLabel = new QLabel("激 活 码:");
|
|||
|
|
codeLabel->setFixedWidth(80);
|
|||
|
|
codeLabel->setStyleSheet("font-size: 13px;");
|
|||
|
|
|
|||
|
|
codeEdit = new QLineEdit();
|
|||
|
|
codeEdit->setMinimumHeight(32);
|
|||
|
|
codeEdit->setPlaceholderText("例如: RB2026-XXXX-XXXX-XXXX");
|
|||
|
|
codeEdit->setStyleSheet("font-size: 13px; padding: 4px 8px;");
|
|||
|
|
|
|||
|
|
codeLayout->addWidget(codeLabel);
|
|||
|
|
codeLayout->addWidget(codeEdit, 1);
|
|||
|
|
mainLayout->addLayout(codeLayout);
|
|||
|
|
|
|||
|
|
mainLayout->addSpacing(15);
|
|||
|
|
|
|||
|
|
// 按钮
|
|||
|
|
QHBoxLayout *btnLayout = new QHBoxLayout();
|
|||
|
|
btnLayout->addStretch();
|
|||
|
|
|
|||
|
|
confirmBtn = new QPushButton("激 活");
|
|||
|
|
confirmBtn->setFixedSize(100, 36);
|
|||
|
|
confirmBtn->setStyleSheet(
|
|||
|
|
"QPushButton { background-color: #4CAF50; color: white; font-size: 14px; font-weight: bold; border-radius: 4px; }"
|
|||
|
|
"QPushButton:hover { background-color: #45a049; }"
|
|||
|
|
"QPushButton:pressed { background-color: #3d8b40; }");
|
|||
|
|
connect(confirmBtn, &QPushButton::clicked, this, &ActivationDialog::onConfirmClicked);
|
|||
|
|
|
|||
|
|
cancelBtn = new QPushButton("退 出");
|
|||
|
|
cancelBtn->setFixedSize(100, 36);
|
|||
|
|
cancelBtn->setStyleSheet(
|
|||
|
|
"QPushButton { background-color: #f44336; color: white; font-size: 14px; font-weight: bold; border-radius: 4px; }"
|
|||
|
|
"QPushButton:hover { background-color: #da3c30; }"
|
|||
|
|
"QPushButton:pressed { background-color: #c62828; }");
|
|||
|
|
connect(cancelBtn, &QPushButton::clicked, this, &QDialog::reject);
|
|||
|
|
|
|||
|
|
btnLayout->addWidget(confirmBtn);
|
|||
|
|
btnLayout->addSpacing(20);
|
|||
|
|
btnLayout->addWidget(cancelBtn);
|
|||
|
|
btnLayout->addStretch();
|
|||
|
|
mainLayout->addLayout(btnLayout);
|
|||
|
|
|
|||
|
|
// 确保可以Tab切换
|
|||
|
|
setTabOrder(serverEdit, codeEdit);
|
|||
|
|
setTabOrder(codeEdit, confirmBtn);
|
|||
|
|
setTabOrder(confirmBtn, cancelBtn);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void ActivationDialog::onConfirmClicked()
|
|||
|
|
{
|
|||
|
|
if (serverEdit->text().trimmed().isEmpty())
|
|||
|
|
{
|
|||
|
|
QMessageBox::warning(this, "提示", "请输入服务器地址!");
|
|||
|
|
serverEdit->setFocus();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (codeEdit->text().trimmed().isEmpty())
|
|||
|
|
{
|
|||
|
|
QMessageBox::warning(this, "提示", "请输入激活码!");
|
|||
|
|
codeEdit->setFocus();
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
accept();
|
|||
|
|
}
|