#include "datarestore.h" #include #include #include #include #include #include #include #include #include "../component/circlelabel.h" #include "../component/mycheckbox.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/pixmaplabel.h" #include "../../common/utils.h" #include "../globalbackupinfo.h" #include "../gsettingswrapper.h" #include "messageboxutils.h" #include "selectrestorepoint.h" #include "kborderbutton.h" using namespace kdk; // bigTitle控件前面的宽度:24+spacing #define LEN_TITLE_PRE 50 // labelCheck1、labelCheck2控件前面的宽度:10+6+5 #define LEN_DOT_PRE 50 DataRestore::DataRestore(QWidget *parent) : QStackedWidget(parent) { m_pInterface = nullptr; // 界面手写代码创建,作为练手 initFirstWidget(); initSecondWidget(); initThirdWidget(); initLastWidget(); } DataRestore::~DataRestore() { delete m_pInterface; m_pInterface = nullptr; } /** * @brief 初始化第一个页面 */ void DataRestore::initFirstWidget() { QWidget *first = new QWidget; QVBoxLayout *vLayout = new QVBoxLayout; vLayout->addStretch(); // 中部布局包含一个独立的窗口,用于大小变化时局部相对不变 QWidget *center = new QWidget; center->setFixedSize(760, 540); QHBoxLayout *centerHBoxLayout = new QHBoxLayout; centerHBoxLayout->addStretch(); centerHBoxLayout->addWidget(center); centerHBoxLayout->addStretch(); vLayout->addLayout(centerHBoxLayout); vLayout->addStretch(); vLayout->addSpacing(60); first->setLayout(vLayout); // 图片 PixmapLabel *imageRestore_firstPage = new PixmapLabel(center); imageRestore_firstPage->setGeometry(421, 120, 300, 326); imageRestore_firstPage->setScaledContents(true); imageRestore_firstPage->setLightAndDarkPixmap(":/images/data_restore.png", ":/images/data_restore_dark.png"); // 数据还原大字提示 MyLabel *labelRestore_firstPage = new MyLabel(center); labelRestore_firstPage->setDeplayText(tr("Data Restore")); labelRestore_firstPage->setFixedWidth(500); labelRestore_firstPage->setFixedHeight(48); labelRestore_firstPage->move(41, 120); QFont font; font.setBold(true); font.setPixelSize(36); labelRestore_firstPage->setFont(font); // labelRestore_firstPage->setAttribute(Qt::WA_TranslucentBackground); labelRestore_firstPage->setScaledContents(true); labelRestore_firstPage->adjustSize(); // 数据还原说明 MyLabel *labelNote_firstPage = new MyLabel(center); labelNote_firstPage->setFixedWidth(700); labelNote_firstPage->setFixedHeight(24); labelNote_firstPage->move(41, 180); // 必须先进行数据备份,否则无法进行数据还原操作 labelNote_firstPage->setDeplayText(tr("Backed up first, then can be restored")); font.setBold(false); font.setPixelSize(18); labelNote_firstPage->setFont(font); labelNote_firstPage->setScaledContents(true); labelNote_firstPage->adjustSize(); // 快速恢复 MyIconLabel *iconSimple_firstPage = new MyIconLabel(center); iconSimple_firstPage->setGeometry(41, 244, 210, 36); iconSimple_firstPage->setThemeIcon("object-rotate-left-symbolic", ":/symbos/object-rotate-left-symbolic"); iconSimple_firstPage->setDesplayText(tr("Fast Recovery")); iconSimple_firstPage->setEnabled(false); // 安全可靠 MyIconLabel *iconSecurity_firstPage = new MyIconLabel(center); iconSecurity_firstPage->setGeometry(231, 244, 180, 36); iconSecurity_firstPage->setThemeIcon("ukui-bf-security-symbolic", ":/symbos/ukui-bf-security-symbolic"); iconSecurity_firstPage->setDesplayText(tr("Security")); iconSecurity_firstPage->setEnabled(false); // 防止数据丢失 MyIconLabel *iconMultiBackup_firstPage = new MyIconLabel(center); iconMultiBackup_firstPage->setGeometry(41, 296, 210, 36); iconMultiBackup_firstPage->setThemeIcon("ukui-bf-dataloss-symbolic", ":/symbos/ukui-bf-dataloss-symbolic"); iconMultiBackup_firstPage->setDesplayText(tr("Protect Data")); iconMultiBackup_firstPage->setEnabled(false); // 自主操作 MyIconLabel *iconSmallSize_firstPage = new MyIconLabel(center); iconSmallSize_firstPage->setGeometry(231, 296, 180, 36); iconSmallSize_firstPage->setThemeIcon("ukui-self-help-symbolic", ":/symbos/ukui-self-help-symbolic"); iconSmallSize_firstPage->setDesplayText(tr("Independent")); iconSmallSize_firstPage->setEnabled(false); // 开始还原按钮 MyPushButton *beginRestore = new MyPushButton(center); beginRestore->setGeometry(41, 372, 180, 52); beginRestore->setText(tr("Start Restore")); beginRestore->setEnabled(true); beginRestore->setAutoRepeat(true); beginRestore->setProperty("isImportant", true); font.setPixelSize(24); beginRestore->setFont(font); connect(beginRestore, &MyPushButton::clicked, this, &DataRestore::on_button_beginRestore_clicked); addWidget(first); } /** * @brief “上一步”按钮响应槽 * @param checked */ void DataRestore::on_pre_clicked(bool checked) { Q_UNUSED(checked) int index = this->currentIndex() - 1; if (index >= 0) { this->setCurrentIndex(index); } } /** * @brief “下一步”按钮响应槽 * @param checked */ void DataRestore::on_next_clicked(bool checked) { Q_UNUSED(checked) int index = this->currentIndex() + 1; if (index < this->count()) { this->setCurrentIndex(index); } } /** * @brief “开始还原”按钮响应槽 * @param checked */ void DataRestore::on_button_beginRestore_clicked(bool checked) { Q_UNUSED(checked) this->m_uuid = ""; this->m_devPath = ""; m_bNeedReboot = false; // 系统备份点列表中选择备份点 SelectRestorePoint *selectRestoreDialog = new SelectRestorePoint(this, SelectRestorePoint::BackupPointType::DATA); connect(selectRestoreDialog, &SelectRestorePoint::selected, this, [=](ParseBackupList::BackupPoint backupPoint){ this->m_uuid = backupPoint.m_uuid; this->m_devPath = backupPoint.m_path; this->m_iPosition = backupPoint.m_iPosition; }); if (QDialog::Rejected == selectRestoreDialog->exec()) { selectRestoreDialog->deleteLater(); return ; } else if (checkIsNeedReboot()){ // 包含用户家目录,还原完成后需要重启 if (!MessageBoxUtils::QMESSAGE_BOX_WARNING_CANCEL(this, QObject::tr("Information"), QObject::tr("Contains the user's home directory, which need to reboot after restoration. Are you sure to continue?"), QObject::tr("Continue"), QObject::tr("Cancel"))) { selectRestoreDialog->deleteLater(); return ; } m_bNeedReboot = true; } selectRestoreDialog->deleteLater(); on_next_clicked(); emit this->startCheckEnv(); } /** * @brief 校验还原的目录中是否包含用户家目录,如果包含的话后面需要自动重启 */ bool DataRestore::checkIsNeedReboot() { QString pathUserFile; if (this->m_devPath.isEmpty()) pathUserFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_uuid + "/" + PATHS_USER_FILE; else pathUserFile = this->m_devPath + BACKUP_SNAPSHOTS_PATH + "/" + m_uuid + "/" + PATHS_USER_FILE; pathUserFile.replace("//", "/"); QFile file(pathUserFile); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QString home = QDir::homePath(); QTextStream in(&file); while (!in.atEnd()) { QString line = in.readLine(); if (line.isEmpty()) continue; if (line == home) return true; } } return false; } /** * @brief 初始化第二界面--检测中 */ void DataRestore::initSecondWidget() { QWidget *second = new QWidget; // 流程进度提示栏 CircleLable *one = new CircleLable("1", second, 24, QColor(COLOR_BLUE)); LineLabel *line1 = new LineLabel(second, QColor(COLOR_BLUE)); CircleLable *two = new CircleLable("2", second); LineLabel *line2 = new LineLabel(second, QColor(COLOR_GRAY)); CircleLable *three = new CircleLable("3", second); QHBoxLayout *layoutLine1 = new QHBoxLayout; layoutLine1->addSpacing(128); layoutLine1->addWidget(one); layoutLine1->addWidget(line1); layoutLine1->addWidget(two); layoutLine1->addWidget(line2); layoutLine1->addWidget(three); layoutLine1->addSpacing(128); MyLabel *label1 = new MyLabel(tr("checking"), second); label1->setIsOriginal(true); label1->setFontColor(QColor(COLOR_BLUE)); label1->setFixedWidth(164); MyLabel *label2 = new MyLabel(tr("restoring"), second); label2->setIsOriginal(true); label2->setEnabled(false); label2->setFixedWidth(164); MyLabel *label3 = new MyLabel(tr("finished"), second); label3->setIsOriginal(true); label3->setEnabled(false); label3->setFixedWidth(164); QHBoxLayout *layoutLine2 = new QHBoxLayout; layoutLine2->addSpacing(54); layoutLine2->addWidget(label1); layoutLine2->addStretch(); layoutLine2->addWidget(label2); layoutLine2->addStretch(); layoutLine2->addWidget(label3); layoutLine2->addSpacing(54); // ------------ 中部布局begin------------- QWidget *centerFont = new QWidget(second); centerFont->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); QVBoxLayout *vlayoutCenterFont = new QVBoxLayout; // 第一行 QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout; // 检测等待图标 QLabel *loadingGif = new QLabel(centerFont); loadingGif->setFixedSize(24,24); // 环境检测等待动画 QMovie *movie = new QMovie(":/images/loading.gif", QByteArray(), centerFont); loadingGif->setMovie(movie); hlayoutCenterFont1->addWidget(loadingGif); // 检测结果对错图标 PixmapLabel *resultLogo = new PixmapLabel(centerFont); resultLogo->setFixedSize(24,24); hlayoutCenterFont1->addWidget(resultLogo); // 检测中大标题 MyLabel *bigTitle = new MyLabel(centerFont); bigTitle->setFontSize(24); bigTitle->setIsOriginal(true); bigTitle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); hlayoutCenterFont1->addWidget(bigTitle); hlayoutCenterFont1->setAlignment(Qt::AlignLeft); vlayoutCenterFont->addLayout(hlayoutCenterFont1); vlayoutCenterFont->addSpacing(16); // 第二行 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->setIsOriginal(true); labelCheck1->setWordWrap(true); labelCheck1->adjustSize(); labelCheck1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); hlayoutCenterFont2->addWidget(labelCheck1); hlayoutCenterFont2->setAlignment(Qt::AlignLeft); 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->setIsOriginal(true); labelCheck2->setWordWrap(true); labelCheck2->adjustSize(); labelCheck2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); hlayoutCenterFont3->addWidget(labelCheck2); hlayoutCenterFont3->setAlignment(Qt::AlignLeft); vlayoutCenterFont->addLayout(hlayoutCenterFont3); // 第四行 vlayoutCenterFont->addSpacing(56); // 第五行 QHBoxLayout *hlayoutCenterFont5 = new QHBoxLayout; hlayoutCenterFont5->setSpacing(16); hlayoutCenterFont5->addStretch(); // 上一步按钮 KBorderButton *preStep = new KBorderButton(centerFont); preStep->setText(tr("Back")); preStep->setEnabled(true); preStep->setAutoRepeat(true); connect(preStep, &KBorderButton::clicked, preStep, &KBorderButton::clearFocus); connect(preStep, &KBorderButton::clicked, this, &DataRestore::on_pre_clicked); hlayoutCenterFont5->addWidget(preStep); // 下一步按钮 MyPushButton *nextStep = new MyPushButton(centerFont); nextStep->setText(tr("Next")); nextStep->setEnabled(true); nextStep->setAutoRepeat(true); nextStep->setProperty("isImportant", true); connect(nextStep, &MyPushButton::clicked, this, [=](bool checked) { this->on_next_clicked(checked); emit this->startRestore(); }); hlayoutCenterFont5->addWidget(nextStep); // 重新检测按钮 MyPushButton *recheck = new MyPushButton(centerFont); recheck->setText(tr("Recheck")); recheck->setEnabled(true); recheck->setAutoRepeat(true); recheck->setProperty("isImportant", true); hlayoutCenterFont5->addWidget(recheck); hlayoutCenterFont5->addStretch(); hlayoutCenterFont5->setAlignment(Qt::AlignCenter); vlayoutCenterFont->addLayout(hlayoutCenterFont5); centerFont->setLayout(vlayoutCenterFont); QHBoxLayout *layoutLine3 = new QHBoxLayout; layoutLine3->addStretch(); layoutLine3->addSpacing(80); layoutLine3->addWidget(centerFont); layoutLine3->addSpacing(80); layoutLine3->addStretch(); layoutLine3->setAlignment(Qt::AlignCenter); // ------------ 中部布局end------------- // 布局 QVBoxLayout *vlayout = new QVBoxLayout; vlayout->addSpacing(40); vlayout->addLayout(layoutLine1); vlayout->addLayout(layoutLine2); vlayout->addSpacing(80); vlayout->addLayout(layoutLine3); vlayout->addStretch(); second->setLayout(vlayout); // 开始检测 connect(this, &DataRestore::startCheckEnv, this, [=]() { this->m_dataRestoreState = DataRestoreState::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(); emit GlobelBackupInfo::inst().getGlobalSignals()->widthChanged(); }); // 检测结果 connect(this, &DataRestore::checkEnvResult, this, [=](bool result, const QString &errMsg, const QString &errTip) { loadingGif->setVisible(false); movie->stop(); if (result) { resultLogo->setThemeIconSchema("ukui-dialog-success", ":/symbos/ukui-dialog-success"); resultLogo->setVisible(true); // 检测成功 bigTitle->setDeplayText(tr("Check success")); // 不要使用电脑,以防数据丢失 labelCheck1->setDeplayText(tr("Do not use computer in case of data loss")); 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 { resultLogo->setThemeIconSchema("dialog-error", ":/symbos/dialog-error"); 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); emit GlobelBackupInfo::inst().getGlobalSignals()->widthChanged(); }); // 调整中部控件大小 connect(GlobelBackupInfo::inst().getGlobalSignals(), &GlobalSignals::widthChanged, this, [=](){ // 控件bigTitle的宽度 int len_title = 0; if (bigTitle->isVisible()) { QFontMetrics fontMetrics(bigTitle->font()); len_title = fontMetrics.width(bigTitle->getOriginalText()); len_title += LEN_TITLE_PRE; } // 控件labelCheck1的宽度 int len_labelCheck1 = 0; if (labelCheck1->isVisible()) { QFontMetrics fontMetrics(labelCheck1->font()); len_labelCheck1 = fontMetrics.width(labelCheck1->getOriginalText()); len_labelCheck1 += LEN_DOT_PRE; } // 控件labelCheck2的宽度 int len_labelCheck2 = 0; if (labelCheck2->isVisible()) { QFontMetrics fontMetrics(labelCheck2->font()); len_labelCheck2 = fontMetrics.width(labelCheck2->getOriginalText()); len_labelCheck2 += LEN_DOT_PRE; } int len_max = len_title > len_labelCheck1 ? len_title : len_labelCheck1; len_max = len_max > len_labelCheck2 ? len_max : len_labelCheck2; if (len_max >= this->width()) len_max = this->width(); centerFont->setFixedWidth(len_max); }); // 重新检查 connect(recheck, &MyPushButton::clicked, this, [=](bool checked) { Q_UNUSED(checked) emit this->startCheckEnv(); }); addWidget(second); } /** * @brief 开始进行环境检测 */ void DataRestore::on_checkEnv_start() { GlobelBackupInfo::inst().setIsBusy(true); m_pInterface = new ComKylinBackupManagerInterface("com.kylin.backup", "/", QDBusConnection::systemBus(), this); connect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataRestore::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_type = BackupType::RESTORE_DATA; backupWrapper.m_iPosition = m_iPosition; backupWrapper.m_uuid = m_uuid; backupWrapper.m_prefixDestPath = m_devPath; backupWrapper.m_frontUid = getuid(); backupWrapper.m_frontUserName = qgetenv("USER"); backupWrapper.m_gid = getgid(); m_pInterface->checkEnv(backupWrapper); } /** * @brief 环境检测结束 * @param result, 环境校验结果 */ void DataRestore::on_checkEnv_end(int result) { m_dataRestoreState = DataRestoreState::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::WRITE_BACKUP_PATHS_TO_USER_FAILED): // ".user.txt文件不存在" errMsg = tr("The .user.txt file does not exist"); // 备份点可能被损坏 errTip = tr("Backup points may be corrupted"); break; case int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED): // .exclude.user.txt文件不存在 errMsg = tr("The .exclude.user.txt file does not exist"); // 备份点可能被损坏 errTip = tr("Backup points may be corrupted"); break; case int(BackupResult::INC_NOT_FOUND_DIR): // 备份点数据目录不存在 errMsg = tr("The backup point data directory does not exist"); // 备份点可能被损坏 errTip = tr("Backup points may be corrupted"); break; default: bRst = true; break; } Utils::wait(2); emit checkEnvResult(bRst, errMsg, errTip); GlobelBackupInfo::inst().setIsBusy(false); disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataRestore::on_checkEnv_end); delete m_pInterface; m_pInterface = nullptr; } /** * @brief 第三个页面-还原中 */ void DataRestore::initThirdWidget() { QWidget *third = new QWidget; // 流程进度提示栏 CircleLable *one = new CircleLable("1", third, 24, QColor(COLOR_BLUE)); LineLabel *line1 = new LineLabel(third, QColor(COLOR_BLUE)); CircleLable *two = new CircleLable("2", third, 24, QColor(COLOR_BLUE)); LineLabel *line2 = new LineLabel(third, QColor(COLOR_GRAY)); CircleLable *three = new CircleLable("3", third); QHBoxLayout *layoutLine1 = new QHBoxLayout; layoutLine1->addSpacing(128); layoutLine1->addWidget(one); layoutLine1->addWidget(line1); layoutLine1->addWidget(two); layoutLine1->addWidget(line2); layoutLine1->addWidget(three); layoutLine1->addSpacing(128); MyLabel *label1 = new MyLabel(tr("checking"), third); label1->setIsOriginal(true); label1->setFontColor(QColor(COLOR_BLUE)); label1->setFixedWidth(164); MyLabel *label2 = new MyLabel(tr("restoring"), third); label2->setIsOriginal(true); label2->setFontColor(QColor(COLOR_BLUE)); label2->setFixedWidth(164); MyLabel *label3 = new MyLabel(tr("finished"), third); label3->setIsOriginal(true); label3->setEnabled(false); label3->setFixedWidth(164); QHBoxLayout *layoutLine2 = new QHBoxLayout; layoutLine2->addSpacing(54); layoutLine2->addWidget(label1); layoutLine2->addStretch(); layoutLine2->addWidget(label2); layoutLine2->addStretch(); layoutLine2->addWidget(label3); layoutLine2->addSpacing(54); // ------------ 中部布局begin------------- // 中部第一行 QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout; // 检测等待图标 QLabel *loadingGif = new QLabel(third); // 环境检测等待动画 QMovie *movie = new QMovie(":/images/loading.gif", QByteArray(), third); loadingGif->setMovie(movie); loadingGif->setVisible(false); // 进度条 RingsProgressbar *progressBar = new RingsProgressbar(third); progressBar->setFixedSize(100, 100); hlayoutCenterFont1->addStretch(); hlayoutCenterFont1->addWidget(loadingGif); hlayoutCenterFont1->addWidget(progressBar); hlayoutCenterFont1->addStretch(); hlayoutCenterFont1->setAlignment(Qt::AlignCenter); // 第二行 QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout; // 提醒 MyLabel *labelTip = new MyLabel(third); labelTip->setAlignment(Qt::AlignCenter); labelTip->setIsOriginal(true); labelTip->setFontWordWrap(true); labelTip->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); // 不要使用电脑,以防数据丢失 labelTip->setDeplayText(tr("Do not use computer in case of data loss")); hlayoutCenterFont2->addStretch(); hlayoutCenterFont2->addWidget(labelTip); hlayoutCenterFont2->addStretch(); hlayoutCenterFont2->setAlignment(Qt::AlignCenter); // ------------ 中部布局end------------- // 布局 QVBoxLayout *vlayout = new QVBoxLayout; vlayout->addSpacing(40); vlayout->addLayout(layoutLine1); vlayout->addLayout(layoutLine2); vlayout->addSpacing(80); vlayout->addLayout(hlayoutCenterFont1); vlayout->addSpacing(16); vlayout->addLayout(hlayoutCenterFont2); vlayout->addStretch(); third->setLayout(vlayout); // 开始还原 connect(this, &DataRestore::startRestore, this, [=] { progressBar->setPersent(0); movie->start(); // 开始还原 this->on_restore_start(); }); // 进度 connect(this, &DataRestore::progress, this, [=](int state, int rate) { Q_UNUSED(state) progressBar->setPersent(rate); }); addWidget(third); } /** * @brief 开始还原 */ void DataRestore::on_restore_start() { GlobelBackupInfo::inst().setIsBusy(true); Utils::wait(2); m_dataRestoreState = DataRestoreState::RESTORING; m_pInterface = new ComKylinBackupManagerInterface("com.kylin.backup", "/", QDBusConnection::systemBus(), this); connect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataRestore::on_checkRestore_end); connect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &DataRestore::progress); connect(m_pInterface, &ComKylinBackupManagerInterface::sendRestoreResult, this, &DataRestore::on_restore_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_type = BackupType::RESTORE_DATA; backupWrapper.m_iPosition = m_iPosition; backupWrapper.m_uuid = m_uuid; backupWrapper.m_prefixDestPath = m_devPath; backupWrapper.m_frontUid = getuid(); backupWrapper.m_frontUserName = qgetenv("USER"); backupWrapper.m_gid = getgid(); m_pInterface->goRestore(backupWrapper); } /** * @brief 系统还原校验结果处理 * @param result */ void DataRestore::on_checkRestore_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::WRITE_BACKUP_PATHS_TO_USER_FAILED): // ".user.txt文件不存在" errMsg = tr("The .user.txt file does not exist"); // 备份点可能被损坏 errTip = tr("Backup points may be corrupted"); break; case int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED): // .exclude.user.txt文件不存在 errMsg = tr("The .exclude.user.txt file does not exist"); // 备份点可能被损坏 errTip = tr("Backup points may be corrupted"); break; case int(BackupResult::INC_NOT_FOUND_DIR): // 备份点数据目录不存在 errMsg = tr("The backup point data directory does not exist"); // 备份点可能被损坏 errTip = tr("Backup points may be corrupted"); break; case int(BackupResult::EFI_RSYNC_FAIL): // 同步/boot/efi失败 errMsg = tr("Failed to rsync /boot/efi"); // 请检查/boot/efi分区挂载方式 errTip = tr("Check the mounting mode of the /boot/efi partition"); break; case int(BackupResult::RESTOREDIR_PREPARE_FAILED): // 还原目录准备失败 errMsg = tr("Failed to prepare the restore directory"); // 更多信息请参考日志/var/log/backup.log errTip = tr("Refer to log :/var/log/backup.log for more information"); break; default: bRst = true; break; } if (!bRst) { GlobelBackupInfo::inst().setIsBusy(false); m_dataRestoreState = DataRestoreState::IDEL; this->on_next_clicked(true); emit this->checkRestoreResult(bRst, errMsg, errTip); disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataRestore::on_checkRestore_end); disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &DataRestore::progress); disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendRestoreResult, this, &DataRestore::on_restore_end); delete m_pInterface; m_pInterface = nullptr; } } /** * @brief 系统还原结束 * @param result-false 失败; true 成功 */ void DataRestore::on_restore_end(bool result) { m_dataRestoreState = DataRestoreState::IDEL; this->on_next_clicked(true); if (result) { emit checkRestoreResult(result); } else { // 还原过程中出现错误 QString errMsg = tr("An error occurred during restore"); // 错误信息参考日志文件:/var/log/backup.log QString errTip = tr("Error messages refer to log file : /var/log/backup.log"); emit checkRestoreResult(result, errMsg, errTip); } GlobelBackupInfo::inst().setIsBusy(false); disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataRestore::on_checkRestore_end); disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &DataRestore::progress); disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendRestoreResult, this, &DataRestore::on_restore_end); delete m_pInterface; m_pInterface = nullptr; } /** * @brief 初始化最后一页 */ void DataRestore::initLastWidget() { QWidget *last = new QWidget; // 流程进度提示栏 CircleLable *one = new CircleLable("1", last, 24, QColor(COLOR_BLUE)); LineLabel *line1 = new LineLabel(last, QColor(COLOR_BLUE)); CircleLable *two = new CircleLable("2", last, 24, QColor(COLOR_BLUE)); LineLabel *line2 = new LineLabel(last, QColor(COLOR_BLUE)); CircleLable *three = new CircleLable("3", last, 24, QColor(COLOR_BLUE)); QHBoxLayout *layoutLine1 = new QHBoxLayout; layoutLine1->addSpacing(128); layoutLine1->addWidget(one); layoutLine1->addWidget(line1); layoutLine1->addWidget(two); layoutLine1->addWidget(line2); layoutLine1->addWidget(three); layoutLine1->addSpacing(128); MyLabel *label1 = new MyLabel(tr("checking"), last); label1->setIsOriginal(true); label1->setFontColor(QColor(COLOR_BLUE)); label1->setFixedWidth(164); MyLabel *label2 = new MyLabel(tr("restoring"), last); label2->setIsOriginal(true); label2->setFontColor(QColor(COLOR_BLUE)); label2->setFixedWidth(164); MyLabel *label3 = new MyLabel(tr("finished"), last); label3->setIsOriginal(true); label3->setFontColor(QColor(COLOR_BLUE)); label3->setFixedWidth(164); QHBoxLayout *layoutLine2 = new QHBoxLayout; layoutLine2->addSpacing(54); layoutLine2->addWidget(label1); layoutLine2->addStretch(); layoutLine2->addWidget(label2); layoutLine2->addStretch(); layoutLine2->addWidget(label3); layoutLine2->addSpacing(54); // ------------ 中部布局begin------------- QWidget *centerFont = new QWidget(last); centerFont->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); QVBoxLayout *vlayoutCenterFont = new QVBoxLayout; // 中部第一行 QHBoxLayout *hlayoutCenterFont1 = new QHBoxLayout; // 备份结果对错图标 PixmapLabel *resultLogo = new PixmapLabel(centerFont); resultLogo->setFixedSize(24,24); hlayoutCenterFont1->addWidget(resultLogo); // 检测中大标题 MyLabel *bigTitle = new MyLabel(centerFont); bigTitle->setFontSize(24); bigTitle->setIsOriginal(true); bigTitle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); hlayoutCenterFont1->addWidget(bigTitle); hlayoutCenterFont1->setAlignment(Qt::AlignLeft); vlayoutCenterFont->addLayout(hlayoutCenterFont1); vlayoutCenterFont->addSpacing(16); // 第二行 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->setIsOriginal(true); labelError1->setWordWrap(true); labelError1->adjustSize(); labelError1->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); hlayoutCenterFont2->addWidget(labelError1); hlayoutCenterFont2->setAlignment(Qt::AlignLeft); 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->setIsOriginal(true); labelError2->setWordWrap(true); labelError2->adjustSize(); labelError2->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); hlayoutCenterFont3->addWidget(labelError2); hlayoutCenterFont3->setAlignment(Qt::AlignLeft); vlayoutCenterFont->addLayout(hlayoutCenterFont3); // 第四行 vlayoutCenterFont->addSpacing(56); // 第五行 QHBoxLayout *hlayoutCenterFont5 = new QHBoxLayout; hlayoutCenterFont5->setSpacing(16); hlayoutCenterFont5->addStretch(); // 返回首页 MyPushButton *homePage = new MyPushButton(centerFont); homePage->setText(tr("Home Page")); homePage->setEnabled(true); homePage->setAutoRepeat(true); homePage->setProperty("isImportant", true); hlayoutCenterFont5->addWidget(homePage); // 再试一次 KBorderButton *retry = new KBorderButton(centerFont); retry->setText(tr("Retry")); retry->setEnabled(true); retry->setAutoRepeat(true); hlayoutCenterFont5->addWidget(retry); // 重启 KBorderButton *reboot = new KBorderButton(centerFont); reboot->setText(tr("Reboot System")); reboot->setEnabled(true); reboot->setAutoRepeat(true); hlayoutCenterFont5->addWidget(reboot); hlayoutCenterFont5->addStretch(); hlayoutCenterFont5->setAlignment(Qt::AlignCenter); vlayoutCenterFont->addLayout(hlayoutCenterFont5); centerFont->setLayout(vlayoutCenterFont); QHBoxLayout *layoutLine3 = new QHBoxLayout; layoutLine3->addStretch(); layoutLine3->addSpacing(80); layoutLine3->addWidget(centerFont); layoutLine3->addSpacing(80); layoutLine3->addStretch(); // ------------ 中部布局end------------- // 布局 QVBoxLayout *vlayout = new QVBoxLayout; vlayout->addSpacing(40); vlayout->addLayout(layoutLine1); vlayout->addLayout(layoutLine2); vlayout->addSpacing(80); vlayout->addLayout(layoutLine3); vlayout->addStretch(); last->setLayout(vlayout); // 还原检测结果 connect(this, &DataRestore::checkRestoreResult, this, [=](bool result, const QString &errMsg, const QString &errTip) { if (result) { resultLogo->setThemeIconSchema("ukui-dialog-success", ":/symbos/ukui-dialog-success"); resultLogo->setVisible(true); // 数据还原成功 bigTitle->setDeplayText(tr("Successfully restoring the data")); dot2->setVisible(false); labelError2->setVisible(false); homePage->setVisible(true); retry->setVisible(false); if (m_bNeedReboot) { dot1->setVisible(true); // 系统需要重启,否则某些工具可能无法使用。 labelError1->setDeplayText(tr("The system needs to reboot. Otherwise, some tools cannot be used.")); labelError1->setVisible(true); reboot->setVisible(true); hlayoutCenterFont1->setAlignment(Qt::AlignLeft); } else { dot1->setVisible(false); labelError1->setVisible(false); reboot->setVisible(false); QFontMetrics fontMetrics(bigTitle->font()); int fontSize = fontMetrics.width(bigTitle->getOriginalText()); bigTitle->setFixedWidth(fontSize); hlayoutCenterFont1->setAlignment(Qt::AlignCenter); } } else { resultLogo->setThemeIconSchema("dialog-error", ":/symbos/dialog-error"); resultLogo->setVisible(true); // 数据还原失败 bigTitle->setDeplayText(tr("Restoring the data failed")); bigTitle->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred); dot1->setVisible(true); dot2->setVisible(true); labelError1->setVisible(true); labelError2->setVisible(true); labelError1->setDeplayText(errMsg); labelError2->setDeplayText(errTip); homePage->setVisible(true); retry->setVisible(true); reboot->setVisible(false); hlayoutCenterFont1->setAlignment(Qt::AlignLeft); } emit GlobelBackupInfo::inst().getGlobalSignals()->widthChanged(); }); // 调整中部控件大小 connect(GlobelBackupInfo::inst().getGlobalSignals(), &GlobalSignals::widthChanged, this, [=](){ // 控件bigTitle的宽度 int len_title = 0; if (bigTitle->isVisible()) { QFontMetrics fontMetrics(bigTitle->font()); len_title = fontMetrics.width(bigTitle->getOriginalText()); len_title += LEN_TITLE_PRE; } // 控件labelError1的宽度 int len_labelError1 = 0; if (labelError1->isVisible()) { QFontMetrics fontMetrics(labelError1->font()); len_labelError1 = fontMetrics.width(labelError1->getOriginalText()); len_labelError1 += LEN_DOT_PRE; } // 控件labelError2的宽度 int len_labelError2 = 0; if (labelError2->isVisible()) { QFontMetrics fontMetrics(labelError2->font()); len_labelError2 = fontMetrics.width(labelError2->getOriginalText()); len_labelError2 += LEN_DOT_PRE; } int len_max = len_title > len_labelError1 ? len_title : len_labelError1; len_max = len_max > len_labelError2 ? len_max : len_labelError2; if (len_max >= this->width()) len_max = this->width(); centerFont->setFixedWidth(len_max); }); // 再试一次 connect(retry, &KBorderButton::clicked, this, [=](bool checked) { Q_UNUSED(checked) retry->clearFocus(); this->setCurrentIndex(DataRestorePage::RESTORE_PAGE); emit this->startRestore(); }); // 返回首页 connect(homePage, &MyPushButton::clicked, this, [=](bool checked) { Q_UNUSED(checked) this->setCurrentIndex(DataRestorePage::HOME_PAGE); }); // 重启 connect(reboot, &KBorderButton::clicked, this, &DataRestore::reboot); addWidget(last); } /** * @brief 重启系统 */ void DataRestore::reboot() { GlobelBackupInfo::inst().setIsBusy(true); m_pInterface = new ComKylinBackupManagerInterface("com.kylin.backup", "/", QDBusConnection::systemBus(), this); // 是否已存在备份、还原等操作 bool isActive = false; if(int(BackupState::BACKUP_STATE_INIT) != m_pInterface->getBackupState(isActive)){ // 系统正忙,请稍等 MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), QObject::tr("It's busy, please wait"), QObject::tr("Ok")); GlobelBackupInfo::inst().setIsBusy(false); delete m_pInterface; m_pInterface = nullptr; return ; } m_pInterface->reboot(); GlobelBackupInfo::inst().setIsBusy(false); delete m_pInterface; m_pInterface = nullptr; qApp->quit(); return ; }