deep-wine-runner/VM-source/mainwindow.cpp

485 lines
17 KiB
C++
Raw Normal View History

2023-02-07 22:12:05 +08:00
/*
2023-04-24 21:49:18 +08:00
* gfdgd xi
2023-02-19 14:51:29 +08:00
* GPLV3
*/
2022-07-12 20:37:59 +08:00
#include "mainwindow.h"
#include "ui_mainwindow.h"
2023-02-07 22:12:05 +08:00
#include "buildvbox.h"
2022-07-12 20:37:59 +08:00
#include <QFileDialog>
#include <QDebug>
#include <QNetworkInterface>
#include <QProcess>
2023-02-07 22:12:05 +08:00
#include <QLoggingCategory>
2023-02-19 14:51:29 +08:00
#include <infoutils.h>
#include <QMessageBox>
2023-02-25 08:28:50 +08:00
#include <QTimer>
2023-02-25 09:52:53 +08:00
#include <QJsonParseError>
#include <QJsonValue>
#include <QJsonObject>
#include <QtMath>
#include <QJsonArray>
#include <QDesktopServices>
2023-04-08 11:07:42 +08:00
#include <QMessageBox>
2023-04-28 21:43:14 +08:00
#include <iostream>
#include <QIODevice>
#include <QInputDialog>
2023-04-15 19:14:30 +08:00
#include "qemusetting.h"
#include "vbox.h"
#include "qemu.h"
2022-07-12 20:37:59 +08:00
2024-04-27 15:42:25 +08:00
#include <QInputDialog>
2022-07-12 20:37:59 +08:00
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
2023-11-25 16:03:47 +08:00
//QApplication a(argc, argv);
2022-07-12 20:37:59 +08:00
ui->tabWidget->setTabPosition(QTabWidget::West); // 标签靠左
2023-04-08 11:07:42 +08:00
// 选择最优虚拟机
2023-04-08 11:57:36 +08:00
if(!system("which qemu-system-x86_64")){
2023-04-08 11:07:42 +08:00
ui->vmChooser->setCurrentIndex(0);
}
if(!system("which vboxmanage")){
ui->vmChooser->setCurrentIndex(1);
}
2023-04-08 11:57:36 +08:00
if(!QFile::exists(QCoreApplication::applicationDirPath() + "/../RunCommandWithTerminal.py")){
ui->getQemu->setDisabled(true);
}
2023-02-07 22:12:05 +08:00
// 允许输出 qDebug 信息
QLoggingCategory::defaultCategory()->setEnabled(QtDebugMsg, true);
2023-04-05 16:09:58 +08:00
// 判断是否安装 vbox无需判断
/*if(system("which VBoxManage")){
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), "检测到您似乎没有安装 VirtualBox立即安装") == QMessageBox::Yes){
2023-02-19 15:43:24 +08:00
system("xdg-open https://www.virtualbox.org/wiki/Linux_Downloads");
}
2023-04-05 16:09:58 +08:00
}*/
2023-02-25 08:28:50 +08:00
// QTimer
QTimer *cpuGet = new QTimer(this);
connect(cpuGet, &QTimer::timeout, this, &MainWindow::ShowCPUMessage);
2023-03-04 11:48:45 +08:00
cpuGet->setInterval(1000);
2023-02-25 08:28:50 +08:00
cpuGet->start();
2023-03-04 11:48:45 +08:00
MainWindow::ShowCPUMessage();
2023-02-25 09:52:53 +08:00
// 读取程序版本号
// / 版本号文件是否存在
QFile fileinfo(QCoreApplication::applicationDirPath() + "/../information.json");
if(!fileinfo.exists()){
fileinfo.close();
return;
}
fileinfo.open(QIODevice::ReadOnly);
QJsonParseError error;
QJsonDocument doc = QJsonDocument::fromJson(fileinfo.readAll(), &error);
if(error.error != QJsonParseError::NoError){
QMessageBox::critical(this, "错误", "无法读取版本号!");
qDebug() << error.errorString();
fileinfo.close();
return;
}
QJsonObject versionObject = doc.object();
2023-04-09 18:49:39 +08:00
QJsonValue buildTime = versionObject.value("Time");
2023-02-25 09:52:53 +08:00
QJsonValue versionValue = versionObject.value("Version");
QJsonArray thank = versionObject.value("Thank").toArray();
QString thankText = "";
for (int i = 0; thank.count() > i; i++) {
thankText += "<p>" + thank.at(i).toString() + "</p>\n";
qDebug() << thank.at(i).toString();
}
// 设置程序标题
2023-11-25 16:38:14 +08:00
this->setWindowTitle(tr("Wine 运行器虚拟机安装工具 ") + versionValue.toString());
2023-02-25 09:52:53 +08:00
// 读取谢明列表
2023-11-25 16:38:14 +08:00
ui->textBrowser_2->setHtml(tr("<p>程序版本号:") + versionValue.toString() + ", " + GetRunCommand("arch") + tr("</p><p>安装包构建时间:") + buildTime.toString() + tr("</p><p>该组件构建时间:")
2023-04-09 18:49:39 +08:00
+ __DATE__ + " " + __TIME__ + "</p>" + ui->textBrowser_2->toHtml() +
2023-11-25 16:38:14 +08:00
tr("<hr/><h1>谢明列表</h1>") + thankText);
2023-02-25 09:52:53 +08:00
connect(ui->textBrowser_2, &QTextBrowser::anchorClicked, this, [=](const QUrl &link){
QDesktopServices::openUrl(link);
});
2023-03-04 11:48:45 +08:00
connect(ui->textBrowser, &QTextBrowser::anchorClicked, this, [=](const QUrl &link){
QDesktopServices::openUrl(link);
});
connect(ui->textBrowser_3, &QTextBrowser::anchorClicked, this, [=](const QUrl &link){
QDesktopServices::openUrl(link);
});
// 设置标签栏图标
ui->tabWidget->setTabIcon(1, QIcon::fromTheme(":/application-vnd.oasis.opendocument.text.svg"));
// 设置窗口图标
this->setWindowIcon(QIcon(":/deepin-wine-runner.svg"));
2023-11-25 16:03:47 +08:00
2023-02-25 08:28:50 +08:00
}
void MainWindow::ShowCPUMessage(){
// 获取 CPU 占用率
long cpuAll = 0;
long cpuFree = 0;
infoUtils::cpuRate(cpuAll, cpuFree);
long cpu = ((cpuAll - m_cpuAll) - (cpuFree - m_cpuFree)) * 100 / (cpuAll - m_cpuAll);
if(cpu > 100){
// 处理异常值
cpu = 100;
}
// 获取内存占用率
long memory = 0;
long memoryAll = 0;
long swap = 0;
long swapAll = 0;
infoUtils::memoryRate(memory, memoryAll, swap, swapAll);
2023-02-25 09:52:53 +08:00
// 获取开机时间
double run,idle;
infoUtils::uptime(run,idle);
int time = qFloor(run);
int ss = time % 60;
int MM = (time % 3600) / 60;
int hh = (time % 86400) / 3600;
int dd = time / 86400;
2023-02-25 08:28:50 +08:00
QString info = "CPU: " + QString::number(cpu) + "% 内存: " +
2023-02-25 09:52:53 +08:00
QString::number(memory * 100 / memoryAll) + "% " + QString::number(memory / 1024) + "MB/" + QString::number(memoryAll / 1024) + "MB" +
" 开机时间: " + QString::number(dd) + "" + QString::number(hh) + ":" + QString::number(MM) + ":" + QString::number(ss);
//qDebug() << cpuAll << " " << cpuFree;
if(!stopShowTime){
ui->CPUValue->showMessage(info, 5000);
}
2023-02-25 08:28:50 +08:00
m_cpuAll = cpuAll;
m_cpuFree = cpuFree;
//ui->retranslateUi(this);
2023-02-19 15:43:24 +08:00
}
QString MainWindow::GetRunCommand(QString command){
QProcess process;
process.start(command);
process.waitForStarted();
process.waitForFinished();
QString re = process.readAllStandardOutput();
process.close();
return re;
2022-07-12 20:37:59 +08:00
}
2023-02-19 15:43:24 +08:00
2022-07-12 20:37:59 +08:00
MainWindow::~MainWindow()
{
delete ui;
}
void MainWindow::on_browser_clicked()
{
// 浏览镜像文件
2022-07-14 14:31:36 +08:00
QString filePath = QFileDialog::getOpenFileName(this, "选择 ISO 文件", QDir::homePath(), "ISO 镜像文件(*.iso);;所有文件(*.*)");
2022-07-12 20:37:59 +08:00
if(filePath != ""){
ui->isoPath->setText(filePath);
}
}
void MainWindow::on_install_clicked()
{
2023-04-08 11:07:42 +08:00
switch (ui->vmChooser->currentIndex()) {
case 0:
2023-04-08 11:57:36 +08:00
if(system("which qemu-system-x86_64")){
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), tr("您似乎没有安装 Qemu是否继续创建虚拟机")) == QMessageBox::No){
2023-04-08 11:07:42 +08:00
return;
}
}
break;
case 1:
if(system("which vboxmanage")){
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), tr("您似乎没有安装 VBox是否继续创建虚拟机")) == QMessageBox::No){
2023-04-08 11:07:42 +08:00
return;
}
}
break;
2023-11-11 22:10:49 +08:00
case 8:
if(system("which qemu-system-arm")){
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), tr("无法检测到 qemu-system-arm是否继续创建虚拟机")) == QMessageBox::No){
2023-11-11 22:10:49 +08:00
return;
}
}
break;
case 9:
if(system("which qemu-system-aarch64")){
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), tr("无法检测到 qemu-system-aarch64是否继续创建虚拟机")) == QMessageBox::No){
2023-11-11 22:10:49 +08:00
return;
}
}
break;
2023-04-08 11:07:42 +08:00
}
2023-08-10 14:36:41 +08:00
QFile file(QDir::homePath() + "/.config/deepin-wine-runner/QEMU-EFI");
QFile archFile(QDir::homePath() + "/.config/deepin-wine-runner/QEMU-ARCH");
2023-08-10 14:36:41 +08:00
QDir dir(QDir::homePath() + "/.config/deepin-wine-runner");
archFile.open(QIODevice::WriteOnly);
archFile.write("amd64");
archFile.close();
2023-08-09 22:57:14 +08:00
switch (ui->systemVersion->currentIndex()) {
case 0:
if(!QFile::exists(QCoreApplication::applicationDirPath() + "/Windows7X86Auto.iso")){
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), tr("似乎无法找到 Windows7X86Auto.iso是否继续创建虚拟机\n缺少该文件可能会导致虚拟机无法正常启动,尝试重新安装 Wine 运行器再试试?")) == QMessageBox::No){
return;
}
}
break;
case 1:
if(!QFile::exists(QCoreApplication::applicationDirPath() + "/Windows7X64Auto.iso")){
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), tr("似乎无法找到 Windows7X64Auto.iso是否继续创建虚拟机\n缺少该文件可能会导致虚拟机无法正常启动,尝试重新安装 Wine 运行器再试试?")) == QMessageBox::No){
return;
}
}
break;
2023-08-09 22:57:14 +08:00
case 3:
2023-08-10 14:36:41 +08:00
if(!QFile::exists("/usr/share/qemu/OVMF.fd") && !QFile::exists(QCoreApplication::applicationDirPath() + "/OVMF.fd") && ui->vmChooser->currentIndex() == 0){
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), tr("似乎无法找到 UEFI 固件,是否继续创建虚拟机?\nQemu 固件可以在“安装 Qemu”处安装")) == QMessageBox::No){
2023-08-09 22:57:14 +08:00
return;
}
}
2023-08-10 14:36:41 +08:00
if(!dir.exists()){
dir.mkpath(QDir::homePath() + "/.config/deepin-wine-runner");
}
if(!QFile::exists(QDir::homePath() + "/.config/deepin-wine-runner/QEMU-EFI")){
// 写入用于识别的空文件
file.open(QIODevice::WriteOnly);
file.write("1");
file.close();
}
break;
case 4:
2023-08-16 09:53:59 +08:00
case 5:
case 6:
case 7:
if(ui->vmChooser->currentIndex() == 0){
2023-11-25 16:38:14 +08:00
QMessageBox::warning(this, tr("提示"), tr("Qemu 不支持该选项!"));
return;
}
break;
2023-11-11 19:44:28 +08:00
case 8:
if(ui->vmChooser->currentIndex() == 1){
2023-11-25 16:38:14 +08:00
QMessageBox::warning(this, tr("提示"), tr("VirtualBox 不支持该选项!"));
2023-11-11 19:44:28 +08:00
return;
}
archFile.open(QIODevice::WriteOnly);
archFile.write("armhf");
archFile.close();
2023-11-11 19:44:28 +08:00
break;
case 9:
if(ui->vmChooser->currentIndex() == 1){
2023-11-25 16:38:14 +08:00
QMessageBox::warning(this, tr("提示"), tr("VirtualBox 不支持该选项!"));
2023-11-11 19:44:28 +08:00
return;
}
archFile.open(QIODevice::WriteOnly);
archFile.write("aarch64");
archFile.close();
2023-11-11 19:44:28 +08:00
break;
2023-08-10 14:36:41 +08:00
default:
if(ui->vmChooser->currentIndex() == 0 && QFile::exists(QDir::homePath() + "/.config/deepin-wine-runner/QEMU-EFI")){
QFile::remove(QDir::homePath() + "/.config/deepin-wine-runner/QEMU-EFI");
}
2023-08-09 22:57:14 +08:00
}
2023-04-08 11:07:42 +08:00
buildvbox(ui->isoPath->text(), ui->systemVersion->currentIndex(), ui->vmChooser->currentIndex());
ui->tabWidget->setCurrentIndex(1);
stopShowTime = 1;
2023-11-25 16:38:14 +08:00
ui->CPUValue->showMessage(tr("提示:目前已经尝试开启虚拟机,如果在一段时间后依旧还没看到虚拟机窗口开启,请在菜单栏查看虚拟机日志"), 10000);
2023-02-07 22:12:05 +08:00
return;
2022-07-12 20:37:59 +08:00
}
2023-04-08 11:57:36 +08:00
void MainWindow::on_getvbox_clicked()
{
QDesktopServices::openUrl(QUrl("https://www.virtualbox.org/wiki/Linux_Downloads"));
}
void MainWindow::on_getQemu_clicked()
{
2023-08-09 22:57:14 +08:00
system(("python3 '" + QCoreApplication::applicationDirPath() + "/../RunCommandWithTerminal.py' pkexec '" + QCoreApplication::applicationDirPath() + "/../QemuSystemInstall.sh'").toLatin1());
2023-04-08 11:57:36 +08:00
}
2023-04-15 19:14:30 +08:00
void MainWindow::on_vmChooser_currentIndexChanged(int index)
{
ui->qemuSetting->setDisabled(index);
}
void MainWindow::on_qemuSetting_clicked()
{
2023-04-16 22:06:38 +08:00
QemuSetting *show = new QemuSetting();
show->show();
2023-04-15 19:14:30 +08:00
}
2023-04-28 21:43:14 +08:00
void MainWindow::on_addQemuDisk_triggered()
{
if(QFile::exists(QDir::homePath() + "/Qemu/Windows/Windows.qcow2")){
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), tr("磁盘文件已存在,是否覆盖?\n覆盖后将无法恢复!")) == QMessageBox::No){
2023-04-28 21:43:14 +08:00
return;
}
}
2023-11-25 16:38:14 +08:00
QString path = QFileDialog::getOpenFileName(this, tr("选择 Qemu 镜像"), QDir::homePath(), tr("Qemu镜像(*.qcow2 *.img *.raw *.qcow *.qed *.vdi *.vhdx *.vmdk);;所有文件(*.*)"));
2023-04-28 21:43:14 +08:00
qDebug() << path;
if(path == ""){
return;
}
QDir dir(QDir::homePath() + "/Qemu/Windows");
2023-04-28 21:43:14 +08:00
if(!dir.exists()){
dir.mkpath(QDir::homePath() + "/Qemu/Windows");
2023-04-28 21:43:14 +08:00
}
if(QFile::exists(QDir::homePath() + "/Qemu/Windows/Windows.qcow2")){
if(!QFile::remove(QDir::homePath() + "/Qemu/Windows/Windows.qcow2") | !QFile::copy(path, QDir::homePath() + "/Qemu/Windows/Windows.qcow2")){
2023-11-25 16:38:14 +08:00
QMessageBox::critical(this, tr("提示"), tr("添加错误!"));
return;
}
}
else{
if(!QFile::copy(path, QDir::homePath() + "/Qemu/Windows/Windows.qcow2")){
2023-11-25 16:38:14 +08:00
QMessageBox::critical(this, tr("提示"), tr("添加错误!"));
return;
}
2023-04-28 21:43:14 +08:00
}
2023-11-25 16:38:14 +08:00
QMessageBox::information(this, tr("提示"), tr("添加完成!"));
2023-04-28 21:43:14 +08:00
}
void MainWindow::on_delQemuDisk_triggered()
{
if(!QFile::exists(QDir::homePath() + "/Qemu/Windows/Windows.qcow2")){
2023-11-25 16:38:14 +08:00
QMessageBox::information(this, tr("提示"), tr("不存在磁盘文件,无法导出"));
2023-04-28 21:43:14 +08:00
return;
}
std::system(("xdg-open \"" + QDir::homePath() + "/Qemu/Windows/\"").toUtf8());
}
void MainWindow::on_addQemuDiskButton_clicked()
{
MainWindow::on_addQemuDisk_triggered();
}
void MainWindow::on_saveQemuDiskButton_clicked()
{
MainWindow::on_delQemuDisk_triggered();
}
void MainWindow::on_delQemuDiskButton_clicked()
{
if(!QFile::exists(QDir::homePath() + "/Qemu/Windows/Windows.qcow2")){
2023-11-25 16:38:14 +08:00
QMessageBox::information(this, tr("提示"), tr("不存在磁盘文件,无法移除"));
return;
}
2023-11-25 16:38:14 +08:00
if(QMessageBox::question(this, tr("提示"), tr("是否删除?\n删除后将无法恢复!")) == QMessageBox::No){
return;
}
if(!QFile::remove(QDir::homePath() + "/Qemu/Windows/Windows.qcow2")){
2023-11-25 16:38:14 +08:00
QMessageBox::critical(this, tr("提示"), tr("移除失败"));
return;
}
2023-11-25 16:38:14 +08:00
QMessageBox::information(this, tr("提示"), tr("移除成功"));
}
2023-11-05 14:36:43 +08:00
void MainWindow::on_kvmTest_clicked()
{
if(system("which kvm-ok")&& !QFile::exists(QCoreApplication::applicationDirPath() + "/kvm-ok")){
2023-11-25 16:38:14 +08:00
QMessageBox::critical(this, tr("错误"), tr("未识别到命令 kvm-ok\n可以使用命令 sudo apt install cpu-checker 安装"));
2023-11-05 14:36:43 +08:00
return;
}
QString kvm_ok_path = "kvm-ok";
if(!system("which kvm-ok")){
kvm_ok_path = "kvm-ok";
}
else if(QFile::exists(QCoreApplication::applicationDirPath() + "/kvm-ok")){
kvm_ok_path = QCoreApplication::applicationDirPath() + "/kvm-ok";
}
2023-11-25 16:38:14 +08:00
qDebug() << tr("使用") << kvm_ok_path;
2023-11-05 14:36:43 +08:00
QProcess process;
process.start(kvm_ok_path);
process.waitForStarted();
process.waitForFinished();
if(process.exitCode()){
2023-11-25 16:38:14 +08:00
QMessageBox::critical(this, tr("错误"), tr("您的系统不支持使用 kvm\n") + process.readAll());
2023-11-05 14:36:43 +08:00
return;
}
2023-11-25 16:38:14 +08:00
QMessageBox::information(this, tr("提示"), tr("您的系统支持使用 kvm\n") + process.readAll());
2023-11-05 14:36:43 +08:00
}
void MainWindow::on_actionVMLog_triggered(){}
void MainWindow::on_actionVMRunlLog_triggered()
{
QFile file("/tmp/windows-virtual-machine-installer-for-wine-runner-run.log");
if(!file.exists()){
2023-11-25 16:38:14 +08:00
QMessageBox::information(this, tr("提示"), tr("没有日志文件"));
return;
}
file.open(QIODevice::ReadOnly);
2023-11-25 16:38:14 +08:00
QInputDialog::getMultiLineText(this, tr("运行日志"), tr("虚拟机运行日志"), file.readAll());
file.close();
}
void MainWindow::on_actionVMTest_triggered()
{
// 运行 Demo
2023-11-12 11:55:33 +08:00
if(QFile::exists(QCoreApplication::applicationDirPath() + "/test.qcow2")){
// 优先使用本地的磁盘
system(("qemu-system-i386 --hda '" + QCoreApplication::applicationDirPath() + "/test.qcow2' -rtc base=localtime > /tmp/windows-virtual-machine-installer-for-wine-runner-run.log 2>&1").toUtf8());
return;
}
// 写入 disk 文件
QFile file(":/TestDisk/test.qcow2");
// 计算随机数
QFile writeFile("/tmp/indows-virtual-machine-installer-for-wine-runner-test-disk.qcow2");
file.open(QIODevice::ReadOnly);
writeFile.open(QIODevice::WriteOnly);
writeFile.write(file.readAll());
file.close();
writeFile.close();
2023-11-11 19:44:28 +08:00
system("qemu-system-i386 --hda /tmp/indows-virtual-machine-installer-for-wine-runner-test-disk.qcow2 -rtc base=localtime > /tmp/windows-virtual-machine-installer-for-wine-runner-run.log 2>&1");
}
void MainWindow::on_actionVMInstallLog_triggered()
{
QFile file("/tmp/windows-virtual-machine-installer-for-wine-runner-install.log");
if(!file.exists()){
2023-11-25 16:38:14 +08:00
QMessageBox::information(this, tr("提示"), tr("没有日志文件"));
return;
}
file.open(QIODevice::ReadOnly);
2023-11-25 16:38:14 +08:00
QInputDialog::getMultiLineText(this, tr("安装日志"), tr("虚拟机安装日志"),file.readAll());
file.close();
}
void MainWindow::on_action_StopVirtualBox_triggered()
{
vbox vmControl("");
vmControl.Stop();
}
void MainWindow::on_action_StopQemu_triggered()
{
qemu vmControl("");
vmControl.Stop();
}
2024-04-27 15:42:25 +08:00
void MainWindow::on_actionQemuDiskAddSpace_triggered()
{
double data = QInputDialog::getDouble(this, tr("磁盘扩容"), "输入扩容多少GB\n1、扩容所需要的时间较长程序可能会出现假死的情况请不要关闭否则会导致虚拟磁盘损坏\n2、扩展后需要自行在虚拟机使用 Deepin Community Live CD、Live CD、Windows PE\n等工具调整系统分区大小才能使用");
if(data <= 0) {
return;
}
// 开始扩容
int result = qemu("").AddDiskSpace(QDir::homePath() + "/Qemu/Windows/Windows.qcow2", data);
qDebug() << "Exit Code: " << result;
if(result) {
QMessageBox::critical(this, tr("错误"), tr("扩容失败!"));
return;
}
QMessageBox::information(this, tr("提示"), tr("扩容完成!"));
}
void MainWindow::on_getDCLC_triggered()
{
QDesktopServices::openUrl(QUrl("https://github.com/gfdgd-xi/deepin-community-live-cd/"));
}