yhkylin-backup-tools/kybackup/module/ghostimage.cpp

1137 lines
41 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "ghostimage.h"
#include <QLabel>
#include <QPushButton>
#include <QComboBox>
#include <QMovie>
#include <QHBoxLayout>
#include <QVBoxLayout>
#include <QHostInfo>
#include <unistd.h>
#include "../component/clicklabel.h"
#include "../component/circlelabel.h"
#include "../component/myiconlabel.h"
#include "../component/mylabel.h"
#include "../component/mylineedit.h"
#include "../component/mypushbutton.h"
#include "../component/linelabel.h"
#include "../component/ringsprogressbar.h"
#include "../component/myfileselect.h"
#include "../../common/utils.h"
#include "../globalbackupinfo.h"
#include "selectrestorepoint.h"
#include "messageboxutils.h"
GhostImage::GhostImage(QWidget *parent) :
QStackedWidget(parent),
m_udector(new UdiskDetector()),
m_isLocal(true),
m_ghostImageState(GhostImageState::IDEL),
m_pInterface(nullptr)
{
// 界面手写代码创建,作为练手
initFirstWidget();
initSecondWidget();
initThirdWidget();
initForthWidget();
initLastWidget();
}
GhostImage::~GhostImage()
{
delete m_udector;
m_udector = nullptr;
delete m_pInterface;
m_pInterface = nullptr;
}
/**
* @brief 初始化第一个页面
*/
void GhostImage::initFirstWidget()
{
QWidget *first = new QWidget;
// 图片
QLabel *imageGhost_firstPage = new QLabel(first);
imageGhost_firstPage->setGeometry(421, 120, 300, 326);
QPixmap pixmap(":/images/ghost_image.svg");
imageGhost_firstPage->setPixmap(pixmap);
imageGhost_firstPage->setScaledContents(true);
// Ghost Image大字提示
MyLabel *labelGhost_firstPage = new MyLabel(first);
labelGhost_firstPage->setDeplayText(tr("Ghost Image"));
labelGhost_firstPage->setFixedWidth(500);
labelGhost_firstPage->setFixedHeight(48);
labelGhost_firstPage->move(41, 120);
// 默认水平左对齐,上下居中对齐;故不需要设置
// labelGhost_firstPage->setAlignment(Qt::AlignLeft | Qt::AlignVCenter);
// labelGhost_firstPage->setText(tr("System Backup"));
QFont font;
font.setBold(true);
font.setPixelSize(36);
labelGhost_firstPage->setFont(font);
// labelGhost_firstPage->setAttribute(Qt::WA_TranslucentBackground);
labelGhost_firstPage->setScaledContents(true);
labelGhost_firstPage->adjustSize();
// Ghost说明
MyLabel *labelNote_firstPage = new MyLabel(first);
labelNote_firstPage->setFixedWidth(700);
labelNote_firstPage->setFixedHeight(24);
labelNote_firstPage->move(41, 180);
// 必须存在本地系统备份,才能制作镜像文件
labelNote_firstPage->setDeplayText(tr("A ghost image file can only be created after backup system to local disk"));
font.setBold(false);
font.setPixelSize(18);
labelNote_firstPage->setFont(font);
labelNote_firstPage->setScaledContents(true);
labelNote_firstPage->adjustSize();
// 操作简单
MyIconLabel *iconSimple_firstPage = new MyIconLabel(first);
iconSimple_firstPage->setGeometry(41, 244, 180, 36);
iconSimple_firstPage->setThemeIcon("ukui-bf-simple-symbolic", ":/symbos/ukui-bf-simple-symbolic.png");
iconSimple_firstPage->setDesplayText(tr("Simple"));
iconSimple_firstPage->setEnabled(false);
// 快速
MyIconLabel *iconFast_firstPage = new MyIconLabel(first);
iconFast_firstPage->setGeometry(206, 244, 180, 36);
iconFast_firstPage->setThemeIcon("ukui-bf-fast-symbolic", ":/symbos/ukui-bf-fast-symbolic.png");
iconFast_firstPage->setDesplayText(tr("Fast"));
iconFast_firstPage->setEnabled(false);
// 安全
MyIconLabel *iconSecurity_firstPage = new MyIconLabel(first);
iconSecurity_firstPage->setGeometry(41, 296, 180, 36);
iconSecurity_firstPage->setThemeIcon("ukui-bf-security-symbolic", ":/symbos/ukui-bf-security-symbolic.png");
iconSecurity_firstPage->setDesplayText(tr("Security"));
iconSecurity_firstPage->setEnabled(false);
// 节省时间
MyIconLabel *iconSimple_firstPage1 = new MyIconLabel(first);
iconSimple_firstPage1->setGeometry(206, 296, 180, 36);
iconSimple_firstPage1->setThemeIcon("document-open-recent-symbolic", ":/symbos/document-open-recent-symbolic.png");
iconSimple_firstPage1->setDesplayText(tr("Timesaving"));
iconSimple_firstPage1->setEnabled(false);
// 制作镜像按钮
MyPushButton *beginBackup = new MyPushButton(first);
beginBackup->setGeometry(41, 372, 180, 52);
beginBackup->setText(tr("Start Ghost"));
beginBackup->setEnabled(true);
beginBackup->setAutoRepeat(true);
font.setPixelSize(24);
beginBackup->setFont(font);
connect(beginBackup, &MyPushButton::clicked, this, [=](bool checked) {
Q_UNUSED(checked)
this->m_uuid = "";
this->m_prefixDestPath = "";
this->m_backupName = "";
SelectRestorePoint * selectDialog = new SelectRestorePoint(this, SelectRestorePoint::SYSTEM, true);
connect(selectDialog, &SelectRestorePoint::selected, this, [=](ParseBackupList::BackupPoint backupPoint){
this->m_uuid = backupPoint.m_uuid;
this->m_backupName = backupPoint.m_backupName;
this->m_prefixDestPath = backupPoint.m_path;
});
if (QDialog::Accepted == selectDialog->exec()) {
QString udiskFlag = Utils::getSysRootPath() + "/media";
udiskFlag.replace("//", "/");
this->m_isLocal = this->m_prefixDestPath.startsWith(udiskFlag) ? false : true;
this->setCurrentIndex(SELECT_PATH_PAGE);
}
selectDialog->deleteLater();
});
addWidget(first);
}
/**
* @brief “上一步”按钮响应槽
* @param checked
*/
void GhostImage::on_pre_clicked(bool checked)
{
Q_UNUSED(checked)
int index = this->currentIndex() - 1;
if (index >= 0) {
this->setCurrentIndex(index);
}
}
/**
* @brief “开始备份”“下一步”按钮响应槽
* @param checked
*/
void GhostImage::on_next_clicked(bool checked)
{
Q_UNUSED(checked)
int index = this->currentIndex() + 1;
if (index < this->count()) {
this->setCurrentIndex(index);
}
}
/**
* @brief 初始化第二个页面
*/
void GhostImage::initSecondWidget()
{
QWidget *second = new QWidget;
// 请选择存储位置
MyLabel* labelSelect = new MyLabel(second);
labelSelect->setDeplayText(tr("Please select storage location"));
labelSelect->setFixedWidth(700);
labelSelect->setFixedHeight(27);
labelSelect->move(41, 41);
QFont font;
font.setBold(true);
font.setPixelSize(18);
labelSelect->setFont(font);
labelSelect->setScaledContents(true);
labelSelect->adjustSize();
// 备份路径选择框
QComboBox* comboSelect = new QComboBox(second);
comboSelect->setGeometry(41, 84, 680, 36);
// 添加本地默认路径、移动设备目录
connect(m_udector, &UdiskDetector::udiskListChanged, this, [=](QList<QStorageInfo> diskList) {
comboSelect->clear();
this->m_udiskPaths.clear();
QIcon iconFolder = QIcon::fromTheme("insync-folder.png", QIcon(":/images/folder.png"));
// 如果有备份分区,则将本地默认分区备份路径放在第一个
if (GlobelBackupInfo::inst().hasBackupPartition()) {
QString qsLocalDefaultPath = Utils::getSysRootPath() + GHOST_PATH;
qsLocalDefaultPath.replace("//", "/");
this->m_prefixDestPath = "";
this->m_udiskPaths << "";
comboSelect->addItem(iconFolder, tr("local default path : ") + qsLocalDefaultPath);
}
QString qsPreDevPath(tr("removable devices path : "));
for (QStorageInfo& disk : diskList) {
this->m_udiskPaths << disk.rootPath();
comboSelect->addItem(iconFolder, qsPreDevPath + disk.rootPath() + GHOST_PATH);
}
});
m_udector->getStorageInfo();
// 上一步按钮
MyPushButton *preStep = new MyPushButton(second);
preStep->setGeometry(271, 176, 97, 36);
preStep->setText(tr("back"));
preStep->setEnabled(true);
preStep->setAutoRepeat(true);
connect(preStep, &MyPushButton::clicked, this, &GhostImage::on_pre_clicked);
// 下一步按钮
MyPushButton *nextStep = new MyPushButton(second);
nextStep->setGeometry(389, 176, 97, 36);
nextStep->setText(tr("next"));
nextStep->setEnabled(true);
nextStep->setAutoRepeat(true);
connect(nextStep, &MyPushButton::clicked, this, [=](bool checked) {
// 备份路径选择索引
int index = comboSelect->currentIndex();
// 第一个选项是本地系统备份
this->m_isLocal = GlobelBackupInfo::inst().hasBackupPartition() && (index == 0);
this->m_prefixDestPath = this->m_udiskPaths.at(index);
this->on_next_clicked(checked);
emit this->startCheckEnv();
});
addWidget(second);
}
/**
* @brief 初始化第三个页面
*/
void GhostImage::initThirdWidget()
{
QWidget *third = new QWidget;
// 流程进度提示栏
CircleLable *one = new CircleLable("1", third, 24, QColor(COLOR_BLUE));
LineLabel *line1 = new LineLabel(third, QColor(COLOR_BLUE), QSize(200, 24));
CircleLable *two = new CircleLable("2", third);
LineLabel *line2 = new LineLabel(third, QColor(COLOR_GRAY), QSize(200, 24));
CircleLable *three = new CircleLable("3", third);
QHBoxLayout *layoutLine1 = new QHBoxLayout;
layoutLine1->addStretch();
layoutLine1->addWidget(one);
layoutLine1->addWidget(line1);
layoutLine1->addWidget(two);
layoutLine1->addWidget(line2);
layoutLine1->addWidget(three);
layoutLine1->addStretch();
MyLabel *label1 = new MyLabel(tr("checking"), third);
label1->setIsOriginal(true);
label1->setFontColor(QColor(COLOR_BLUE));
MyLabel *label2 = new MyLabel(tr("ghosting"), third);
label2->setIsOriginal(true);
MyLabel *label3 = new MyLabel(tr("finished"), third);
label3->setIsOriginal(true);
QHBoxLayout *layoutLine2 = new QHBoxLayout;
layoutLine2->addSpacing(100);
layoutLine2->addWidget(label1);
layoutLine2->addStretch();
layoutLine2->addWidget(label2);
layoutLine2->addStretch();
layoutLine2->addWidget(label3);
layoutLine2->addSpacing(100);
// ------------ 中部布局begin-------------
QWidget *centerFont = new QWidget(third);
QVBoxLayout *vlayoutCenterFont = new QVBoxLayout;
// 第一行
QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout;
// 检测等待图标
QLabel *loadingGif = new QLabel(centerFont);
loadingGif->setFixedSize(20,20);
// 环境检测等待动画
QMovie *movie = new QMovie(":/images/loading.gif", QByteArray(), centerFont);
loadingGif->setMovie(movie);
hlayoutCenterFont1->addWidget(loadingGif);
// 检测结果对错图标
QLabel *resultLogo = new QLabel(centerFont);
resultLogo->setFixedSize(20,20);
hlayoutCenterFont1->addWidget(resultLogo);
// 检测中大标题
MyLabel *bigTitle = new MyLabel(centerFont);
bigTitle->setFontSize(24);
bigTitle->setMaximumWidth(550);
bigTitle->setIsOriginal(true);
hlayoutCenterFont1->addWidget(bigTitle);
hlayoutCenterFont1->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont1);
// 第二行
QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout;
hlayoutCenterFont2->addSpacing(10);
// 检测中的记录黑点1和文字1
CircleLable *dot1 = new CircleLable(QString(""), centerFont, 6, Qt::black);
hlayoutCenterFont2->addWidget(dot1);
hlayoutCenterFont2->addSpacing(5);
MyLabel *labelCheck1 = new MyLabel(centerFont);
labelCheck1->setMinimumWidth(400);
labelCheck1->setMaximumWidth(500);
labelCheck1->setIsOriginal(true);
labelCheck1->setWordWrap(true);
labelCheck1->adjustSize();
hlayoutCenterFont2->addWidget(labelCheck1);
hlayoutCenterFont2->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont2);
// 第三行
QHBoxLayout *hlayoutCenterFont3 = new QHBoxLayout;
hlayoutCenterFont3->addSpacing(10);
// 检测中的记录黑点2和文字2
CircleLable *dot2 = new CircleLable(QString(""), centerFont, 6, Qt::black);
hlayoutCenterFont3->addWidget(dot2);
hlayoutCenterFont3->addSpacing(5);
MyLabel *labelCheck2 = new MyLabel(centerFont);
labelCheck2->setMinimumWidth(400);
labelCheck2->setMaximumWidth(500);
labelCheck2->setIsOriginal(true);
labelCheck2->setWordWrap(true);
labelCheck2->adjustSize();
hlayoutCenterFont3->addWidget(labelCheck2);
hlayoutCenterFont3->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont3);
// 第四行
vlayoutCenterFont->addSpacing(30);
// 第五行
QHBoxLayout *hlayoutCenterFont5 = new QHBoxLayout;
// hlayoutCenterFont5->addStretch();
hlayoutCenterFont5->addSpacing(30);
// 上一步按钮
MyPushButton *preStep = new MyPushButton(centerFont);
preStep->setFixedSize(97, 36);
preStep->setText(tr("back"));
preStep->setEnabled(true);
preStep->setAutoRepeat(true);
connect(preStep, &MyPushButton::clicked, this, &GhostImage::on_pre_clicked);
hlayoutCenterFont5->addWidget(preStep);
hlayoutCenterFont5->addSpacing(20);
// 下一步按钮
MyPushButton *nextStep = new MyPushButton(centerFont);
nextStep->setFixedSize(97, 36);
nextStep->setText(tr("next"));
nextStep->setEnabled(true);
nextStep->setAutoRepeat(true);
connect(nextStep, &MyPushButton::clicked, this, [=](bool checked) {
this->on_next_clicked(checked);
emit this->startGhost();
});
hlayoutCenterFont5->addWidget(nextStep);
// 重新检测按钮
MyPushButton *recheck = new MyPushButton(centerFont);
recheck->setFixedSize(97, 36);
recheck->setText(tr("recheck"));
recheck->setEnabled(true);
recheck->setAutoRepeat(true);
hlayoutCenterFont5->addWidget(recheck);
hlayoutCenterFont5->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont5);
centerFont->setLayout(vlayoutCenterFont);
// ------------ 中部布局end-------------
QHBoxLayout *layoutLine3 = new QHBoxLayout;
layoutLine3->addStretch();
layoutLine3->addWidget(centerFont);
layoutLine3->addStretch();
// 布局
QVBoxLayout *vlayout = new QVBoxLayout;
vlayout->addSpacing(40);
vlayout->addLayout(layoutLine1);
vlayout->addLayout(layoutLine2);
vlayout->addSpacing(50);
vlayout->addLayout(layoutLine3);
vlayout->addStretch();
third->setLayout(vlayout);
// 开始检测
connect(this, &GhostImage::startCheckEnv, this, [=]() {
this->m_ghostImageState = GhostImageState::CHECKING;
loadingGif->setVisible(true);
movie->start();
resultLogo->setVisible(false);
// 环境检测中,请等待
bigTitle->setDeplayText(tr("Checking, wait a moment ..."));
dot1->setBackgroundColor(Qt::black);
dot2->setBackgroundColor(Qt::black);
labelCheck1->setFontColor(Qt::black);
labelCheck2->setFontColor(Qt::black);
// 还原过程中不要做其它操作,以防数据丢失
labelCheck1->setDeplayText(tr("Check whether the restore environment meets the requirements"));
// 检测还原环境是否满足
labelCheck2->setDeplayText(tr("Do not perform other operations during restore to avoid data loss"));
preStep->setVisible(false);
nextStep->setVisible(false);
recheck->setVisible(false);
this->on_checkEnv_start();
});
// 检测结果
connect(this, &GhostImage::checkEnvResult, this, [=](bool result, const QString &errMsg, const QString &errTip) {
loadingGif->setVisible(false);
movie->stop();
if (result) {
QIcon icon = QIcon::fromTheme("ukui-dialog-success", QIcon(":/symbos/ukui-dialog-success.png"));
resultLogo->setPixmap(icon.pixmap(QSize(20,20)));
resultLogo->setVisible(true);
// 检测成功
bigTitle->setDeplayText(tr("Check success"));
// 存储空间充足
labelCheck1->setDeplayText(tr("The storage space is enough"));
dot2->setBackgroundColor(COLOR_YELLOW);
labelCheck2->setFontColor(COLOR_YELLOW);
labelCheck2->setFontWordWrap(true);
// 请确保电脑已连接电源或电量超过60%
labelCheck2->setDeplayText(tr("Make sure the computer is plugged in or the battery level is above 60%"));
dot1->setVisible(true);
dot2->setVisible(true);
labelCheck1->setVisible(true);
labelCheck2->setVisible(true);
nextStep->setVisible(true);
recheck->setVisible(false);
} else {
QIcon icon = QIcon::fromTheme("dialog-error.png", QIcon(":/symbos/dialog-error.png"));
resultLogo->setPixmap(icon.pixmap(QSize(20,20)));
resultLogo->setVisible(true);
// 环境校验失败
bigTitle->setDeplayText(tr("Check failure"));
labelCheck1->setDeplayText(errMsg);
labelCheck2->setDeplayText(errTip);
if (errMsg.isEmpty()) {
dot1->setVisible(false);
labelCheck1->setVisible(false);
} else {
dot1->setVisible(true);
labelCheck1->setVisible(true);
}
if (errTip.isEmpty()) {
dot2->setVisible(false);
labelCheck2->setVisible(false);
} else {
dot2->setVisible(true);
labelCheck2->setVisible(true);
}
recheck->setVisible(true);
nextStep->setVisible(false);
}
preStep->setVisible(true);
});
// 重新检查
connect(recheck, &MyPushButton::clicked, this, [=](bool checked) {
Q_UNUSED(checked)
emit this->startCheckEnv();
});
addWidget(third);
}
/**
* @brief 开始进行环境检测
*/
void GhostImage::on_checkEnv_start()
{
GlobelBackupInfo::inst().setIsBusy(true);
m_pInterface = new ComKylinBackupManagerInterface("com.kylin.backup", "/", QDBusConnection::systemBus(), this);
connect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &GhostImage::on_checkEnv_end);
// 是否已存在备份、还原等操作
bool isActive = false;
if(int(BackupState::BACKUP_STATE_INIT) != m_pInterface->getBackupState(isActive)){
on_checkEnv_end(int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING));
return;
}
BackupWrapper backupWrapper;
backupWrapper.m_uuid = m_uuid;
backupWrapper.m_type = BackupType::GHOST_IMAGE;
backupWrapper.m_backupName = createGhostImageName(m_backupName);
backupWrapper.m_iPosition = m_isLocal ? BackupPosition::LOCAL : BackupPosition::UDISK;
backupWrapper.m_prefixDestPath = m_prefixDestPath;
backupWrapper.m_frontUid = getuid();
backupWrapper.m_frontUserName = qgetenv("USER");
backupWrapper.m_gid = getgid();
m_pInterface->checkEnv(backupWrapper);
}
/**
* @brief 环境检测结束
* @param result, 环境校验结果
*/
void GhostImage::on_checkEnv_end(int result)
{
m_ghostImageState = GhostImageState::IDEL;
bool bRst = false;
QString errMsg, errTip;
switch (result) {
case int(BackupResult::LOCK_PROGRAM_FAIL):
// 程序锁定失败,请重试
errMsg = tr("Program lock failed, please retry");
// 可能有其它备份/还原等任务在执行
errTip = tr("There may be other backups or restores being performed");
break;
case int(BackupResult::NO_FOUND_DEALCLASS):
// 不支持的任务类型
errMsg = tr("Unsupported task type");
// 没有找到相应的处理逻辑
errTip = tr("No processing logic was found in the service");
break;
case int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL):
// 备份分区挂载失败
errMsg = tr("Failed to mount the backup partition");
// 检查是否有备份分区
errTip = tr("Check whether there is a backup partition");
break;
case int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT):
// 移动设备的文件系统是vfat格式
errMsg = tr("The filesystem of device is vfat format");
// 请换成ext4、ntfs等格式
errTip = tr("Please change filesystem format to ext3、ext4 or ntfs");
break;
case int(BackupResult::UDISK_FILESYSTEM_IS_READONLY):
// 移动设备是只读的
errMsg = tr("The device is read only");
// 请修改为可读写权限的
errTip = tr("Please chmod to rw");
break;
case int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH):
// 镜像空间不足
errMsg = tr("The storage for ghost is not enough");
// 建议释放空间后重试
errTip = tr("Retry after release space");
break;
case int(BackupResult::BACKUP_CAPACITY_FOR_UDISKIMG_IS_NOT_ENOUGH):
// 没有足够的空间存放临时.kyimg文件
errMsg = tr("There is not enough space for temporary .kyimg file");
// 建议释放空间后重试
errTip = tr("Retry after release space");
break;
case int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING):
// 其它备份还原等操作正在执行
errMsg = tr("Other backup or restore task is being performed");
// 请稍后重试
errTip = tr("Please try again later");
break;
case int(BackupResult::GHOST_CANNOT_FIND_BACKUPPOINT):
case int(BackupResult::GHOST_SRC_DIRECTORY_IS_NOT_EXIST):
// 备份节点已不存在
errMsg = tr("The backup node does not exist");
// 请检查刚刚是否有删除备份点操作
errTip = tr("Check whether the backup point has been deleted");
break;
default:
bRst = true;
break;
}
Utils::wait(2);
emit checkEnvResult(bRst, errMsg, errTip);
GlobelBackupInfo::inst().setIsBusy(false);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &GhostImage::on_checkEnv_end);
delete m_pInterface;
m_pInterface = nullptr;
}
/**
* @brief 创建ghost镜像名称
* @param comment
* @return
*/
QString GhostImage::createGhostImageName(const QString& backupName)
{
QString localHostName = QHostInfo::localHostName();
QRegExp rx = QRegExp("([0-9a-zA-Z_\\-])+");
QString destFile = "ghost";
if (rx.exactMatch(localHostName))
destFile = localHostName;
//使用uname -m获取体系结构
QString result;
Utils::executeCMD("uname -m", result);
QString arch = result.trimmed();
//用comment
QString mycomment = backupName;
mycomment.replace("-", "");
mycomment.replace(":", "");
mycomment.replace(" ", "");
destFile = destFile + "-" + arch + "-" + mycomment + ".kyimg";
return destFile;
}
/**
* @brief 第四个页面
*/
void GhostImage::initForthWidget()
{
QWidget *forth = new QWidget;
// 流程进度提示栏
CircleLable *one = new CircleLable("1", forth, 24, QColor(COLOR_BLUE));
LineLabel *line1 = new LineLabel(forth, QColor(COLOR_BLUE), QSize(200, 24));
CircleLable *two = new CircleLable("2", forth, 24, QColor(COLOR_BLUE));
LineLabel *line2 = new LineLabel(forth, QColor(COLOR_BLUE), QSize(200, 24));
CircleLable *three = new CircleLable("3", forth);
QHBoxLayout *layoutLine1 = new QHBoxLayout;
layoutLine1->addStretch();
layoutLine1->addWidget(one);
layoutLine1->addWidget(line1);
layoutLine1->addWidget(two);
layoutLine1->addWidget(line2);
layoutLine1->addWidget(three);
layoutLine1->addStretch();
MyLabel *label1 = new MyLabel(tr("checking"), forth);
label1->setIsOriginal(true);
label1->setFontColor(QColor(COLOR_BLUE));
MyLabel *label2 = new MyLabel(tr("ghosting"), forth);
label2->setIsOriginal(true);
label2->setFontColor(QColor(COLOR_BLUE));
MyLabel *label3 = new MyLabel(tr("finished"), forth);
label3->setIsOriginal(true);
QHBoxLayout *layoutLine2 = new QHBoxLayout;
layoutLine2->addSpacing(100);
layoutLine2->addWidget(label1);
layoutLine2->addStretch();
layoutLine2->addWidget(label2);
layoutLine2->addStretch();
layoutLine2->addWidget(label3);
layoutLine2->addSpacing(100);
// ------------ 中部布局begin-------------
QWidget *centerFont = new QWidget(forth);
QVBoxLayout *vlayoutCenterFont = new QVBoxLayout;
// 中部第一行
QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout;
// 检测等待图标
QLabel *loadingGif = new QLabel(centerFont);
// 环境检测等待动画
QMovie *movie = new QMovie(":/images/loading.gif", QByteArray(), centerFont);
loadingGif->setMovie(movie);
loadingGif->setFixedSize(20,20);
// 进度条
RingsProgressbar *progressBar = new RingsProgressbar(centerFont);
progressBar->setFixedSize(100, 100);
hlayoutCenterFont1->addStretch();
hlayoutCenterFont1->addWidget(loadingGif);
hlayoutCenterFont1->addWidget(progressBar);
hlayoutCenterFont1->addSpacing(20);
hlayoutCenterFont1->addStretch();
// 第二行
QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout;
// 提醒
MyLabel *labelTip = new MyLabel(centerFont);
labelTip->setAlignment(Qt::AlignCenter);
labelTip->setIsOriginal(true);
labelTip->setFontWordWrap(true);
labelTip->setMinimumWidth(700);
hlayoutCenterFont2->addStretch();
hlayoutCenterFont2->addWidget(labelTip);
hlayoutCenterFont2->addStretch();
// 第二行
QHBoxLayout *hlayoutCenterFont2_1 = new QHBoxLayout;
// 备份过程提醒信息
MyLabel *labelTip_1 = new MyLabel(centerFont);
labelTip_1->setAlignment(Qt::AlignCenter);
labelTip_1->setIsOriginal(true);
labelTip_1->setFontWordWrap(true);
labelTip_1->setMinimumWidth(700);
labelTip_1->setDeplayText("");
hlayoutCenterFont2_1->addStretch();
hlayoutCenterFont2_1->addWidget(labelTip_1);
hlayoutCenterFont2_1->addStretch();
// 第三行
QHBoxLayout *hlayoutCenterFont3 = new QHBoxLayout;
// 取消按钮
MyPushButton *cancel = new MyPushButton(forth);
cancel->setFixedSize(97, 36);
cancel->setText(tr("cancel"));
cancel->setEnabled(true);
cancel->setAutoRepeat(true);
hlayoutCenterFont3->addStretch();
hlayoutCenterFont3->addWidget(cancel);
hlayoutCenterFont3->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont1);
vlayoutCenterFont->addLayout(hlayoutCenterFont2);
vlayoutCenterFont->addLayout(hlayoutCenterFont2_1);
vlayoutCenterFont->addSpacing(40);
vlayoutCenterFont->addLayout(hlayoutCenterFont3);
vlayoutCenterFont->addStretch();
centerFont->setLayout(vlayoutCenterFont);
// ------------ 中部布局end-------------
QHBoxLayout *layoutLine3 = new QHBoxLayout;
layoutLine3->addStretch();
layoutLine3->addWidget(centerFont);
layoutLine3->addStretch();
// 布局
QVBoxLayout *vlayout = new QVBoxLayout;
vlayout->addSpacing(40);
vlayout->addLayout(layoutLine1);
vlayout->addLayout(layoutLine2);
vlayout->addSpacing(50);
vlayout->addLayout(layoutLine3);
vlayout->addStretch();
forth->setLayout(vlayout);
// 开始制作ghost镜像
connect(this, &GhostImage::startGhost, this, [=] {
progressBar->setPersent(0);
movie->start();
// 不要使用电脑,以防数据丢失
labelTip->setDeplayText(tr("Do not use computer in case of data loss"));
labelTip_1->setVisible(false);
labelTip_1->setDeplayText("");
cancel->setEnabled(true);
// 开始备份
this->on_ghost_start();
});
connect(this, &GhostImage::backupWarnning, labelTip_1, [=](const QString& msg) {
labelTip_1->setVisible(true);
labelTip_1->setDeplayText(msg);
});
// 进度
connect(this, &GhostImage::progress, this, [=](int state, int rate) {
Q_UNUSED(state)
progressBar->setPersent(rate);
});
// 取消备份
connect(cancel, &MyPushButton::clicked, this, [=](bool checked) {
Q_UNUSED(checked)
// 确定取消当前操作?
if (!MessageBoxUtils::QMESSAGE_BOX_WARNING_CANCEL(this, QObject::tr("Warning"), QObject::tr("Are you sure to cancel the operation"), QObject::tr("Ok"), QObject::tr("Cancel"))) {
return ;
}
cancel->setEnabled(false);
if (m_pInterface)
m_pInterface->cancel();
});
addWidget(forth);
}
/**
* @brief 开始进行系统备份
*/
void GhostImage::on_ghost_start()
{
GlobelBackupInfo::inst().setIsBusy(true);
m_ghostImageState = GhostImageState::GHOSTING;
m_pInterface = new ComKylinBackupManagerInterface("com.kylin.backup", "/", QDBusConnection::systemBus(), this);
connect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &GhostImage::on_checkGhost_end);
connect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &GhostImage::progress);
connect(m_pInterface, &ComKylinBackupManagerInterface::sendGhostBackupResult, this, &GhostImage::on_ghost_end);
// 是否已存在备份、还原等操作
bool isActive = false;
if(int(BackupState::BACKUP_STATE_INIT) != m_pInterface->getBackupState(isActive)){
on_checkGhost_end(int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING));
return;
}
BackupWrapper backupWrapper;
backupWrapper.m_uuid = m_uuid;
backupWrapper.m_type = BackupType::GHOST_IMAGE;
backupWrapper.m_backupName = createGhostImageName(m_backupName);
backupWrapper.m_iPosition = m_isLocal ? BackupPosition::LOCAL : BackupPosition::UDISK;
backupWrapper.m_prefixDestPath = m_prefixDestPath;
backupWrapper.m_frontUid = getuid();
backupWrapper.m_frontUserName = qgetenv("USER");
backupWrapper.m_gid = getgid();
m_pInterface->ghostBackup(backupWrapper);
}
/**
* @brief 系统备份校验结果处理
* @param result
*/
void GhostImage::on_checkGhost_end(int result)
{
bool bRst = false;
QString errMsg, errTip;
switch (result) {
case int(BackupResult::LOCK_PROGRAM_FAIL):
// 程序锁定失败,请重试
errMsg = tr("Program lock failed, please retry");
// 可能有其它备份/还原等任务在执行
errTip = tr("There may be other backups or restores being performed");
break;
case int(BackupResult::NO_FOUND_DEALCLASS):
// 不支持的任务类型
errMsg = tr("Unsupported task type");
// 没有找到相应的处理逻辑
errTip = tr("No processing logic was found in the service");
break;
case int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL):
// 备份分区挂载失败
errMsg = tr("Failed to mount the backup partition");
// 检查是否有备份分区
errTip = tr("Check whether there is a backup partition");
break;
case int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT):
// 移动设备的文件系统是vfat格式
errMsg = tr("The filesystem of device is vfat format");
// 请换成ext4、ntfs等格式
errTip = tr("Please change filesystem format to ext3、ext4 or ntfs");
break;
case int(BackupResult::UDISK_FILESYSTEM_IS_READONLY):
// 移动设备是只读的
errMsg = tr("The device is read only");
// 请修改为可读写权限的
errTip = tr("Please chmod to rw");
break;
case int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH):
// 镜像空间不足
errMsg = tr("The storage for ghost is not enough");
// 建议释放空间后重试
errTip = tr("Retry after release space");
break;
case int(BackupResult::BACKUP_CAPACITY_FOR_UDISKIMG_IS_NOT_ENOUGH):
// 没有足够的空间存放临时.kyimg文件
errMsg = tr("There is not enough space for temporary .kyimg file");
// 建议释放空间后重试
errTip = tr("Retry after release space");
break;
case int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING):
// 其它备份还原等操作正在执行
errMsg = tr("Other backup or restore task is being performed");
// 请稍后重试
errTip = tr("Please try again later");
break;
case int(BackupResult::GHOST_CANNOT_FIND_BACKUPPOINT):
case int(BackupResult::GHOST_SRC_DIRECTORY_IS_NOT_EXIST):
// 备份节点已不存在
errMsg = tr("The backup node does not exist");
// 请检查刚刚是否有删除备份点操作
errTip = tr("Check whether the backup point has been deleted");
break;
case int(BackupResult::GHOST_START_SUCCESS):
// 正压缩数据到本地磁盘,请耐心等待...
errTip = tr("The data is being compressed to the local disk, please wait patiently...");
emit this->backupWarnning(errTip);
return;
case int(BackupResult::MKSQUASHFS_DO_SUCCESS):
// 正在传输image文件到移动设备即将完成...
errTip = tr("Transferring image file to mobile device, about to be completed...");
emit this->backupWarnning(errTip);
return;
case int(BackupResult::CANCEL_SUCCESS):
// 已经取消本次镜像制作
errMsg = tr("The image creation had been canceled");
// 如需要可重新发起镜像制作
errTip = tr("Re-initiate the image creation if necessary");
break;
default:
bRst = true;
break;
}
if (!bRst) {
GlobelBackupInfo::inst().setIsBusy(false);
m_ghostImageState = GhostImageState::IDEL;
this->on_next_clicked(true);
emit this->checkGhostResult(bRst, errMsg, errTip);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &GhostImage::on_checkEnv_end);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &GhostImage::progress);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendGhostBackupResult, this, &GhostImage::on_ghost_end);
delete m_pInterface;
m_pInterface = nullptr;
}
}
/**
* @brief 系统备份结束
* @param result-false 失败; true 成功
*/
void GhostImage::on_ghost_end(bool result)
{
m_ghostImageState = GhostImageState::IDEL;
this->on_next_clicked(true);
if (result) {
emit checkGhostResult(result);
} else {
// 备份过程中出现错误
QString errMsg = tr("An error occurred during make ghost image");
// 错误信息参考日志文件:/var/log/backup.log
QString errTip = tr("Error messages refer to log file : /var/log/backup.log");
emit checkGhostResult(result, errMsg, errTip);
}
GlobelBackupInfo::inst().setIsBusy(false);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &GhostImage::on_checkEnv_end);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &GhostImage::progress);
disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendGhostBackupResult, this, &GhostImage::on_ghost_end);
delete m_pInterface;
m_pInterface = nullptr;
}
/**
* @brief 最后备份结果界面
*/
void GhostImage::initLastWidget()
{
QWidget *last = new QWidget;
// 流程进度提示栏
CircleLable *one = new CircleLable("1", last, 24, QColor(COLOR_BLUE));
LineLabel *line1 = new LineLabel(last, QColor(COLOR_BLUE), QSize(200, 24));
CircleLable *two = new CircleLable("2", last, 24, QColor(COLOR_BLUE));
LineLabel *line2 = new LineLabel(last, QColor(COLOR_BLUE), QSize(200, 24));
CircleLable *three = new CircleLable("3", last, 24, QColor(COLOR_BLUE));
QHBoxLayout *layoutLine1 = new QHBoxLayout;
layoutLine1->addStretch();
layoutLine1->addWidget(one);
layoutLine1->addWidget(line1);
layoutLine1->addWidget(two);
layoutLine1->addWidget(line2);
layoutLine1->addWidget(three);
layoutLine1->addStretch();
MyLabel *label1 = new MyLabel(tr("checking"), last);
label1->setIsOriginal(true);
label1->setFontColor(QColor(COLOR_BLUE));
MyLabel *label2 = new MyLabel(tr("ghosting"), last);
label2->setIsOriginal(true);
label2->setFontColor(QColor(COLOR_BLUE));
MyLabel *label3 = new MyLabel(tr("finished"), last);
label3->setIsOriginal(true);
label3->setFontColor(QColor(COLOR_BLUE));
QHBoxLayout *layoutLine2 = new QHBoxLayout;
layoutLine2->addSpacing(100);
layoutLine2->addWidget(label1);
layoutLine2->addStretch();
layoutLine2->addWidget(label2);
layoutLine2->addStretch();
layoutLine2->addWidget(label3);
layoutLine2->addSpacing(100);
//------------ 中部布局begin-------------
QWidget *centerFont = new QWidget(last);
QVBoxLayout *vlayoutCenterFont = new QVBoxLayout;
// 第一行
QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout;
// 备份结果对错图标
QLabel *resultLogo = new QLabel(centerFont);
resultLogo->setFixedSize(20,20);
hlayoutCenterFont1->addWidget(resultLogo);
// 检测中大标题
MyLabel *bigTitle = new MyLabel(centerFont);
bigTitle->setFontSize(24);
bigTitle->setMaximumWidth(550);
bigTitle->setIsOriginal(true);
hlayoutCenterFont1->addWidget(bigTitle);
hlayoutCenterFont1->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont1);
// 第二行
QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout;
hlayoutCenterFont2->addSpacing(10);
// 备份结果错误提示:黑点和文字
CircleLable *dot1 = new CircleLable(QString(""), centerFont, 6, Qt::black);
hlayoutCenterFont2->addWidget(dot1);
hlayoutCenterFont2->addSpacing(5);
MyLabel *labelError1 = new MyLabel(centerFont);
labelError1->setMinimumWidth(400);
labelError1->setMaximumWidth(500);
labelError1->setIsOriginal(true);
labelError1->setWordWrap(true);
labelError1->adjustSize();
hlayoutCenterFont2->addWidget(labelError1);
hlayoutCenterFont2->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont2);
// 第三行
QHBoxLayout *hlayoutCenterFont3 = new QHBoxLayout;
hlayoutCenterFont3->addSpacing(10);
// 检测中的记录黑点2和文字2
CircleLable *dot2 = new CircleLable(QString(""), centerFont, 6, Qt::black);
hlayoutCenterFont3->addWidget(dot2);
hlayoutCenterFont3->addSpacing(5);
MyLabel *labelError2 = new MyLabel(centerFont);
labelError2->setMinimumWidth(400);
labelError2->setMaximumWidth(500);
labelError2->setIsOriginal(true);
labelError2->setWordWrap(true);
labelError2->adjustSize();
hlayoutCenterFont3->addWidget(labelError2);
hlayoutCenterFont3->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont3);
// 第四行
vlayoutCenterFont->addSpacing(30);
// 第五行
QHBoxLayout *hlayoutCenterFont5 = new QHBoxLayout;
// hlayoutCenterFont5->addStretch();
hlayoutCenterFont5->addSpacing(30);
// 返回首页
MyPushButton *homePage = new MyPushButton(centerFont);
homePage->setFixedSize(97, 36);
homePage->setText(tr("home page"));
homePage->setEnabled(true);
homePage->setAutoRepeat(true);
hlayoutCenterFont5->addWidget(homePage);
hlayoutCenterFont5->addSpacing(20);
// 再试一次
MyPushButton *retry = new MyPushButton(centerFont);
retry->setFixedSize(97, 36);
retry->setText(tr("retry"));
retry->setEnabled(true);
retry->setAutoRepeat(true);
hlayoutCenterFont5->addWidget(retry);
hlayoutCenterFont5->addStretch();
vlayoutCenterFont->addLayout(hlayoutCenterFont5);
centerFont->setLayout(vlayoutCenterFont);
//------------ 中部布局end-------------
QHBoxLayout *layoutLine3 = new QHBoxLayout;
layoutLine3->addStretch();
layoutLine3->addWidget(centerFont);
layoutLine3->addStretch();
// 布局
QVBoxLayout *vlayout = new QVBoxLayout;
vlayout->addSpacing(40);
vlayout->addLayout(layoutLine1);
vlayout->addLayout(layoutLine2);
vlayout->addSpacing(50);
vlayout->addLayout(layoutLine3);
vlayout->addStretch();
last->setLayout(vlayout);
// 检测结果
connect(this, &GhostImage::checkGhostResult, this, [=](bool result, const QString &errMsg, const QString &errTip) {
if (result) {
QIcon icon = QIcon::fromTheme("ukui-dialog-success", QIcon(":/symbos/ukui-dialog-success.png"));
resultLogo->setPixmap(icon.pixmap(QSize(20,20)));
resultLogo->setVisible(true);
// 镜像制作成功
bigTitle->setDeplayText(tr("Ghost image creation is successful"));
QString imgPath = m_prefixDestPath + GHOST_PATH;
imgPath.replace("//", "/");
labelError1->setDeplayText(tr("You can view it in the directory : ") + imgPath);
dot1->setVisible(true);
dot2->setVisible(false);
labelError1->setVisible(true);
labelError2->setVisible(false);
retry->setVisible(false);
homePage->setVisible(true);
} else {
QIcon icon = QIcon::fromTheme("dialog-error.png", QIcon(":/symbos/dialog-error.png"));
resultLogo->setPixmap(icon.pixmap(QSize(20,20)));
resultLogo->setVisible(true);
// 镜像制作失败
bigTitle->setDeplayText(tr("Ghost image creation is failed"));
dot1->setVisible(true);
dot2->setVisible(true);
labelError1->setVisible(true);
labelError2->setVisible(true);
labelError1->setDeplayText(errMsg);
labelError2->setDeplayText(errTip);
retry->setVisible(true);
homePage->setVisible(true);
}
});
// 再试一次
connect(retry, &MyPushButton::clicked, this, [=](bool checked) {
Q_UNUSED(checked)
this->setCurrentIndex(GhostImagePage::GHOSTING_PAGE);
emit this->startGhost();
});
// 返回首页
connect(homePage, &MyPushButton::clicked, this, [=](bool checked) {
Q_UNUSED(checked)
this->setCurrentIndex(GhostImagePage::HOME_PAGE);
});
addWidget(last);
}