From 31a86f8b19e5b5a5e7815a15af840ee56a7aec9c Mon Sep 17 00:00:00 2001 From: zhaominyong Date: Tue, 28 Dec 2021 16:51:35 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9C=AC=E5=9C=B0=E5=A4=87=E4=BB=BD=E6=95=B0?= =?UTF-8?q?=E6=8D=AE=E8=BF=98=E5=8E=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backup-daemon/backup-daemon.pro | 2 + backup-daemon/backupmanager_adaptor.cpp | 14 +- backup-daemon/backupmanager_adaptor.h | 5 +- backup-daemon/datarestoreproxy.cpp | 139 ++++ backup-daemon/datarestoreproxy.h | 59 ++ backup-daemon/mybackupmanager.cpp | 20 +- backup-daemon/mybackupmanager.h | 4 +- kybackup/backup_manager_interface.h | 5 + kybackup/kybackup.pro | 2 + kybackup/maindialog.cpp | 42 +- kybackup/module/databackup.cpp | 2 +- kybackup/module/datarestore.cpp | 1005 +++++++++++++++++++++++ kybackup/module/datarestore.h | 69 ++ kybackup/module/selectrestorepoint.cpp | 8 +- kybackup/module/systembackup.cpp | 2 +- kybackup/module/systemrestore.cpp | 48 +- 16 files changed, 1359 insertions(+), 67 deletions(-) create mode 100644 backup-daemon/datarestoreproxy.cpp create mode 100644 backup-daemon/datarestoreproxy.h create mode 100644 kybackup/module/datarestore.cpp create mode 100644 kybackup/module/datarestore.h diff --git a/backup-daemon/backup-daemon.pro b/backup-daemon/backup-daemon.pro index 8e80d52..dcefe97 100755 --- a/backup-daemon/backup-daemon.pro +++ b/backup-daemon/backup-daemon.pro @@ -32,6 +32,7 @@ HEADERS += \ ../common/utils.h \ backupmanager_adaptor.h \ databackupproxy.h \ + datarestoreproxy.h \ deletebackupproxy.h \ mybackupmanager.h \ mymountproxy.h \ @@ -56,6 +57,7 @@ SOURCES += \ ../common/utils.cpp \ backupmanager_adaptor.cpp \ databackupproxy.cpp \ + datarestoreproxy.cpp \ deletebackupproxy.cpp \ main.cpp \ mybackupmanager.cpp \ diff --git a/backup-daemon/backupmanager_adaptor.cpp b/backup-daemon/backupmanager_adaptor.cpp index f873ba7..061f8b1 100755 --- a/backup-daemon/backupmanager_adaptor.cpp +++ b/backup-daemon/backupmanager_adaptor.cpp @@ -113,11 +113,19 @@ int ManagerAdaptor::goRestore(BackupWrapper backupWrapper) return out0; } -int ManagerAdaptor::cancel(BackupWrapper backupWrapper) +int ManagerAdaptor::cancel() { - // handle method call com.kylin.backup.manager.goRestore + // handle method call com.kylin.backup.manager.cancel int out0; - QMetaObject::invokeMethod(parent(), "cancel", Q_RETURN_ARG(int, out0), Q_ARG(BackupWrapper, backupWrapper)); + QMetaObject::invokeMethod(parent(), "cancel", Q_RETURN_ARG(int, out0)); + return out0; +} + +int ManagerAdaptor::reboot() +{ + // handle method call com.kylin.backup.manager.reboot + int out0; + QMetaObject::invokeMethod(parent(), "reboot", Q_RETURN_ARG(int, out0)); return out0; } diff --git a/backup-daemon/backupmanager_adaptor.h b/backup-daemon/backupmanager_adaptor.h index c066f48..c800d57 100755 --- a/backup-daemon/backupmanager_adaptor.h +++ b/backup-daemon/backupmanager_adaptor.h @@ -110,8 +110,6 @@ class ManagerAdaptor: public QDBusAbstractAdaptor " \n" " \n" " \n" -" \n" -" \n" " \n" " \n" "") @@ -131,7 +129,8 @@ public Q_SLOTS: // METHODS int ghostBackup(BackupWrapper backupWrapper); int goBackup(BackupWrapper backupWrapper); int goRestore(BackupWrapper backupWrapper); - int cancel(BackupWrapper backupWrapper); + int cancel(); + int reboot(); Q_SIGNALS: // SIGNALS void backupFinished(bool result); void progress(int in0, int in1); diff --git a/backup-daemon/datarestoreproxy.cpp b/backup-daemon/datarestoreproxy.cpp new file mode 100644 index 0000000..d35976e --- /dev/null +++ b/backup-daemon/datarestoreproxy.cpp @@ -0,0 +1,139 @@ +#include "datarestoreproxy.h" +#include +#include +#include +#include +#include +#include "../common/utils.h" +#include "mymountproxy.h" + +IMPLEMENT_DYNCREATE(DataRestoreProxy) + +/** + * @brief 构造函数 + */ +DataRestoreProxy::DataRestoreProxy() +{ + m_bSuccess = false; + m_p = nullptr; +} + +/** + * @brief 析构函数 + */ +DataRestoreProxy::~DataRestoreProxy() +{ + delete m_p; +} + +/** + * @brief 环境检测 + * @return false,检测失败;true,检测成功 + */ +bool DataRestoreProxy::checkEnvEx() +{ + qDebug() << "DataRestoreProxy::checkEnvEx invoke begin"; + + // 1、检测.user.txt是否存在 + m_userFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + PATHS_USER_FILE; + m_userFile.replace("//", "/"); + if (!Utils::filsExists(m_userFile)) { + qCritical(".user.txt文件不存在"); + emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED)); + return false; + } + + // 2、检测.exclude.user.txt是否存在 + m_excludeUserFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/" + EXCLUDE_PATHS_USER_FILE; + m_excludeUserFile.replace("//", "/"); + if (!Utils::filsExists(m_excludeUserFile)) { + qCritical(".exclude.user.txt文件不存在"); + emit checkResult(int(BackupResult::WRITE_EXCLUDE_BACKUP_PATHS_TO_USER_FAILED)); + return false; + } + + // 3、检测还原点是否存在 + m_backupPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data"; + m_backupPath.replace("//", "/"); + if (Utils::isDirEmpty(m_backupPath)) { + qCritical("还原点{uuid}/data目录不存在"); + emit checkResult(int(BackupResult::INC_NOT_FOUND_DIR)); + return false; + } + + emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS)); + + qDebug() << "DataRestoreProxy::checkEnvEx invoke end"; + return true; +} + +/** + * @brief 执行还原逻辑 + */ +void DataRestoreProxy::doWorkEx() +{ + qDebug() << "DataRestoreProxy::doWorkEx invoke begin"; + + // 1、校验 + if (!checkEnvEx()) + return ; + + // 2、还原数据 + restoreData(); + + qDebug() << "DataRestoreProxy::doWorkEx invoke end"; +} + +/** + * @brief 根据场景获取rsync命令参数 + * @param scene,场景 + * @return 组装好的rsync的参数信息 + */ +QStringList DataRestoreProxy::getRsyncArgs(DataRestoreScene scene) +{ + QStringList args; + args << "-avAHXr"; + args << "--info=progress2"; + args << "--no-inc-recursive"; + args << "--ignore-missing-args"; + args << "--delete"; + + switch (scene) { + case DataRestoreScene::DATA_RESTORE : + args << "--files-from" << m_userFile; + + break ; + default: + return args; + } + + return args; +} + +/** + * @brief 数据还原 + */ +void DataRestoreProxy::restoreData() +{ + m_srcPath = m_backupPath; + QString destPath = Utils::getSysRootPath(); + + QStringList args = getRsyncArgs(DataRestoreScene::DATA_RESTORE); + + args << m_srcPath + "/"; + args << destPath + "/"; + + m_p = new RsyncPathToDirProcess(this); + connect(m_p, &RsyncPathToDirProcess::progress, this, &DataRestoreProxy::progress); + connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) { + if (result) { + QString time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss"); + Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ",,," + QString::number(m_backupWrapper.m_frontUid)); + } + emit this->workResult(result); + }); + + m_p->start(args, false); +} + + diff --git a/backup-daemon/datarestoreproxy.h b/backup-daemon/datarestoreproxy.h new file mode 100644 index 0000000..cbb1125 --- /dev/null +++ b/backup-daemon/datarestoreproxy.h @@ -0,0 +1,59 @@ +#ifndef DATARESTOREPROXY_H +#define DATARESTOREPROXY_H + +#include "workerfactory.h" +#include "myprocess/rsyncpathtodirprocess.h" +#include "parsebackuplist.h" + +class DataRestoreProxy : public Worker +{ + Q_OBJECT + DECLARE_DYNCREATE(DataRestoreProxy) +public: + // 数据还原的几种场景 + enum DataRestoreScene { + DATA_RESTORE, // 数据还原 + }; + + explicit DataRestoreProxy(); + virtual ~DataRestoreProxy(); + +public: + // 环境检测 + virtual bool checkEnvEx(); + + // 任务处理 + virtual void doWorkEx(); + +private: + // 数据还原 + void restoreData(); + + /** + * @brief 根据场景获取rsync命令参数 + * @param scene,场景 + * @return 组装好的rsync的参数信息 + */ + QStringList getRsyncArgs(DataRestoreScene scene); + + // .user.txt文件路径 + QString m_userFile; + // .exclude.user.txt文件路径 + QString m_excludeUserFile; + // 备份数据所在的data目录 + QString m_backupPath; + + // 是否还原成功 + bool m_bSuccess; + // 当前备份uuid + QString m_curUuid; + // 当前还原源目录 + QString m_srcPath; + // 还原进程 + RsyncPathToDirProcess *m_p; + // 当前备份节点 + ParseBackupList::BackupPoint m_backupPoint; + +}; + +#endif // DATARESTOREPROXY_H diff --git a/backup-daemon/mybackupmanager.cpp b/backup-daemon/mybackupmanager.cpp index 4c08b97..2329a42 100755 --- a/backup-daemon/mybackupmanager.cpp +++ b/backup-daemon/mybackupmanager.cpp @@ -4,6 +4,7 @@ #include #include +#include #include #include "mybackupmanager.h" #include "../common/utils.h" @@ -179,8 +180,7 @@ int MyBackupManager::goRestore(const BackupWrapper& backupWrapper) switch (result) { case int(BackupResult::CHECK_ENV_SUCCESS) : - case int(BackupResult::MKSQUASHFS_START_SUCCESS) : - case int(BackupResult::BACKUP_START_SUCCESS) : + case int(BackupResult::RESTORE_START_SUCCESS) : break; default: this->finished(); @@ -191,13 +191,12 @@ int MyBackupManager::goRestore(const BackupWrapper& backupWrapper) emit this->progress(int(BackupState::WORKING), rate); }); connect(worker, &Worker::workResult, this, [&] (bool result) { - emit this->backupFinished(result); + emit this->sendRestoreResult(result); this->finished(); }); worker->moveToThread(&workerThread); connect(&workerThread, &MyThread::started, worker, &Worker::doWork); connect(&workerThread, &MyThread::finished, worker, &Worker::deleteLater); - connect(&workerThread, &MyThread::cancelWork, worker, &Worker::cancel); workerThread.start(); @@ -294,16 +293,23 @@ int MyBackupManager::getBackupState(bool& isActive) /** * @brief 取消操作 */ -int MyBackupManager::cancel(const BackupWrapper& backupWrapper) +int MyBackupManager::cancel() { - Q_UNUSED(backupWrapper) - if (workerThread.isRunning()) emit workerThread.cancelWork(); return 0; } +/** + * @brief 重启操作 + * @return + */ +int MyBackupManager::reboot() +{ + return ::reboot(RB_AUTOBOOT);; +} + /** * @brief 任务结束 */ diff --git a/backup-daemon/mybackupmanager.h b/backup-daemon/mybackupmanager.h index edd02ca..4277f36 100755 --- a/backup-daemon/mybackupmanager.h +++ b/backup-daemon/mybackupmanager.h @@ -61,7 +61,9 @@ public slots: // 获取备份状态 int getBackupState(bool& isActive); // 取消操作 - int cancel(const BackupWrapper& backupWrapper); + int cancel(); + // 重启操作 + int reboot(); // 任务结束 void finished(); diff --git a/kybackup/backup_manager_interface.h b/kybackup/backup_manager_interface.h index 6cd511c..a735a92 100755 --- a/kybackup/backup_manager_interface.h +++ b/kybackup/backup_manager_interface.h @@ -126,6 +126,11 @@ public Q_SLOTS: // METHODS return asyncCall(QStringLiteral("cancel")); } + inline QDBusPendingReply<> reboot() + { + return asyncCall(QStringLiteral("reboot")); + } + Q_SIGNALS: // SIGNALS void backupFinished(bool result); void progress(int in0, int in1); diff --git a/kybackup/kybackup.pro b/kybackup/kybackup.pro index 543613f..99b6d58 100755 --- a/kybackup/kybackup.pro +++ b/kybackup/kybackup.pro @@ -60,6 +60,7 @@ HEADERS += \ maindialog.h \ messageboxutils.h \ module/databackup.h \ + module/datarestore.h \ module/managebackuppointlist.h \ module/selectrestorepoint.h \ module/systembackup.h \ @@ -99,6 +100,7 @@ SOURCES += \ maindialog.cpp \ messageboxutils.cpp \ module/databackup.cpp \ + module/datarestore.cpp \ module/managebackuppointlist.cpp \ module/selectrestorepoint.cpp \ module/systembackup.cpp \ diff --git a/kybackup/maindialog.cpp b/kybackup/maindialog.cpp index 0273ba8..c761dc1 100755 --- a/kybackup/maindialog.cpp +++ b/kybackup/maindialog.cpp @@ -11,8 +11,10 @@ #include "module/systembackup.h" #include "module/systemrestore.h" #include "module/databackup.h" +#include "module/datarestore.h" #include "backup_manager_interface.h" #include "globalbackupinfo.h" +#include "messageboxutils.h" MainDialog::MainDialog(QWidget *parent) : QMainWindow(parent) @@ -216,6 +218,10 @@ void MainDialog::selected(int func_type) m_stackedWidget = new DataBackup(ui->centralwidget); GlobelBackupInfo::inst().setFuncType(FuncTypeConverter::FunType::BACKUP_DATA); break; + case FuncTypeConverter::FunType::RESTORE_DATA: + m_stackedWidget = new DataRestore(ui->centralwidget); + GlobelBackupInfo::inst().setFuncType(FuncTypeConverter::FunType::RESTORE_DATA); + break; default: m_stackedWidget = new SystemBackup(ui->centralwidget); GlobelBackupInfo::inst().setFuncType(FuncTypeConverter::FunType::BACKUP_SYSTEM); @@ -257,31 +263,23 @@ void MainDialog::mountBackupPartition() reply.waitForFinished(); if (reply.isError()) { // 挂载分区时出现异常 - QMessageBox box(QMessageBox::Critical, QObject::tr("Error"), QObject::tr("An exception occurred when mounting backup partition."), QMessageBox::Ok, this); - // box.setStandardButtons(QMessageBox::Ok); - box.setButtonText(QMessageBox::Ok, QObject::tr("OK")); - QIcon titleIcon = QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS); - box.setWindowIcon(titleIcon); - box.exec(); + MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), + QObject::tr("An exception occurred when mounting backup partition."), + QObject::tr("Ok")); closeBtn(); } else if (int(MountResult::CANNOT_GET_BACKUPUUID) == reply.value()) { // 没有找到备份分区,只能备份到移动设备中 - QMessageBox box(QMessageBox::Critical, QObject::tr("Error"), QObject::tr("There's no backup partition, can only backup to removable device."), QMessageBox::Ok, this); - box.setButtonText(QMessageBox::Ok, QObject::tr("OK")); - QIcon titleIcon = QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS); - box.setWindowIcon(titleIcon); - box.exec(); + MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), + QObject::tr("There's no backup partition, can only backup to removable device."), + QObject::tr("Ok")); GlobelBackupInfo::inst().setHasBackupPartition(false); } else if (int(MountResult::MOUNTED) != reply.value()) { // 挂载备份分区失败 - QMessageBox box(QMessageBox::Critical, QObject::tr("Error"), QObject::tr("Failed to mount backup partition."), QMessageBox::Ok, this); - // box.setStandardButtons(QMessageBox::Ok); - box.setButtonText(QMessageBox::Ok, QObject::tr("OK")); - QIcon titleIcon = QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS); - box.setWindowIcon(titleIcon); - box.exec(); + MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), + QObject::tr("Failed to mount backup partition."), + QObject::tr("Ok")); closeBtn(); } @@ -297,12 +295,10 @@ void MainDialog::umountBackupPartition() void MainDialog::closeBtn() { if (GlobelBackupInfo::inst().isBusy()) { - QMessageBox box(QMessageBox::Critical, QObject::tr("Error"), QObject::tr("It's busy, please wait"), QMessageBox::Ok, this); - // box.setStandardButtons(QMessageBox::Ok); - box.setButtonText(QMessageBox::Ok, QObject::tr("OK")); - QIcon titleIcon = QIcon::fromTheme(THEME_YHKYLIN_BACKUP_TOOLS); - box.setWindowIcon(titleIcon); - box.exec(); + // 系统正忙,请稍等 + MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), + QObject::tr("It's busy, please wait"), + QObject::tr("Ok")); return; } diff --git a/kybackup/module/databackup.cpp b/kybackup/module/databackup.cpp index 34f33e6..64f8799 100644 --- a/kybackup/module/databackup.cpp +++ b/kybackup/module/databackup.cpp @@ -1024,7 +1024,7 @@ void DataBackup::initForthWidget() labelBackupName->setDeplayText(tr("Backup Name")); MyLineEdit *editBackupName = new MyLineEdit(forth); editBackupName->setGeometry(238, 172, 350, 40); - editBackupName->setMaxLength(100); + editBackupName->setMaxLength(64); if (m_backupName.isEmpty()) editBackupName->setPlaceholderText(QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss")); else { diff --git a/kybackup/module/datarestore.cpp b/kybackup/module/datarestore.cpp new file mode 100644 index 0000000..70cc6da --- /dev/null +++ b/kybackup/module/datarestore.cpp @@ -0,0 +1,1005 @@ +#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 "../../common/utils.h" +#include "../globalbackupinfo.h" +#include "messageboxutils.h" +#include "selectrestorepoint.h" + +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; + + // 图片 + QLabel *imageRestore_firstPage = new QLabel(first); + imageRestore_firstPage->setGeometry(421, 120, 300, 326); + QPixmap pixmap(":/images/data_restore.svg"); + imageRestore_firstPage->setPixmap(pixmap); + imageRestore_firstPage->setScaledContents(true); + + // 数据还原大字提示 + MyLabel *labelRestore_firstPage = new MyLabel(first); + 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(first); + 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(first); + iconSimple_firstPage->setGeometry(41, 244, 210, 36); + iconSimple_firstPage->setThemeIcon("object-rotate-left-symbolic", ":/symbos/object-rotate-left-symbolic.png"); + iconSimple_firstPage->setDesplayText(tr("Fast Recovery")); + iconSimple_firstPage->setEnabled(false); + + // 安全可靠 + MyIconLabel *iconSecurity_firstPage = new MyIconLabel(first); + iconSecurity_firstPage->setGeometry(231, 244, 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 *iconMultiBackup_firstPage = new MyIconLabel(first); + iconMultiBackup_firstPage->setGeometry(41, 296, 210, 36); + iconMultiBackup_firstPage->setThemeIcon("ukui-bf-dataloss-symbolic", ":/symbos/ukui-bf-dataloss-symbolic.png"); + iconMultiBackup_firstPage->setDesplayText(tr("Protect Data")); + iconMultiBackup_firstPage->setEnabled(false); + + // 自主操作 + MyIconLabel *iconSmallSize_firstPage = new MyIconLabel(first); + iconSmallSize_firstPage->setGeometry(231, 296, 180, 36); + iconSmallSize_firstPage->setThemeIcon("document-properties-symbolic", ":/symbos/document-properties-symbolic.png"); + iconSmallSize_firstPage->setDesplayText(tr("Independent")); + iconSmallSize_firstPage->setEnabled(false); + + // 开始还原按钮 + MyPushButton *beginRestore = new MyPushButton(first); + beginRestore->setGeometry(41, 372, 180, 52); + beginRestore->setText(tr("Start Restore")); + beginRestore->setEnabled(true); + beginRestore->setAutoRepeat(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; + }); + + if (QDialog::Rejected == selectRestoreDialog->exec()) { + selectRestoreDialog->deleteLater(); + return ; + } else if (checkIsNeedReboot()){ + // 包含用户家目录,还原完成后将自动重启 + if (!MessageBoxUtils::QMESSAGE_BOX_WARNING_CANCEL(this, QObject::tr("Warning"), QObject::tr("Contains the user's home directory, which will automatically reboot after restoration"), 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), QSize(200, 24)); + CircleLable *two = new CircleLable("2", second); + LineLabel *line2 = new LineLabel(second, QColor(COLOR_GRAY), QSize(200, 24)); + CircleLable *three = new CircleLable("3", second); + 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"), second); + label1->setIsOriginal(true); + label1->setFontColor(QColor(COLOR_BLUE)); + MyLabel *label2 = new MyLabel(tr("restoring"), second); + label2->setIsOriginal(true); + MyLabel *label3 = new MyLabel(tr("finished"), second); + 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(second); + 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(700); + 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(600); + 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(600); + 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(); + // 上一步按钮 + MyPushButton *preStep = new MyPushButton(centerFont); + preStep->setFixedSize(97, 36); + preStep->setText(tr("back")); + preStep->setEnabled(true); + preStep->setAutoRepeat(true); + connect(preStep, &MyPushButton::clicked, this, &DataRestore::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->startRestore(); + }); + 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(); + 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(); + }); + + // 检测结果 + connect(this, &DataRestore::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("Succeeded to check the environment")); + // 还原完成后将自动重启 + labelCheck1->setDeplayText(tr("The system will reboot automatically after the restore is successful")); + 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("Failed to check the environment")); + 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(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_devPath.isEmpty() ? BackupPosition::LOCAL : BackupPosition::UDISK; + backupWrapper.m_uuid = m_uuid; + backupWrapper.m_prefixDestPath = m_devPath; + backupWrapper.m_frontUid = getuid(); + 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; + 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; + default: + bRst = true; + break; + } + + 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), QSize(200, 24)); + CircleLable *two = new CircleLable("2", third, 24, QColor(COLOR_BLUE)); + 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("restoring"), third); + label2->setIsOriginal(true); + label2->setFontColor(QColor(COLOR_BLUE)); + 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); + // 环境检测等待动画 + QMovie *movie = new QMovie(":/images/loading.gif", QByteArray(), centerFont); + loadingGif->setMovie(movie); + // 进度条 + RingsProgressbar *progressBar = new RingsProgressbar(centerFont); + progressBar->setFixedSize(100, 100); + hlayoutCenterFont1->addStretch(); + hlayoutCenterFont1->addWidget(loadingGif); + hlayoutCenterFont1->addWidget(progressBar); + hlayoutCenterFont1->addStretch(); + + // 第二行 + QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout; + // 提醒 + MyLabel *labelTip = new MyLabel(centerFont); + labelTip->setAlignment(Qt::AlignCenter); + labelTip->setIsOriginal(true); + labelTip->setFontWordWrap(true); + // 不要使用电脑,以防数据丢失 + labelTip->setDeplayText(tr("Do not use computers in case of data loss")); + hlayoutCenterFont2->addStretch(); + hlayoutCenterFont2->addWidget(labelTip); + hlayoutCenterFont2->addStretch(); + + vlayoutCenterFont->addLayout(hlayoutCenterFont1); + vlayoutCenterFont->addLayout(hlayoutCenterFont2); + vlayoutCenterFont->addStretch(); + centerFont->setLayout(vlayoutCenterFont); + + // ------------ 中部布局end------------- + QHBoxLayout *layoutLine3 = new QHBoxLayout; + layoutLine3->addStretch(); + layoutLine3->addSpacing(80); + 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, &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); + 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_devPath.isEmpty() ? BackupPosition::LOCAL : BackupPosition::UDISK; + backupWrapper.m_uuid = m_uuid; + backupWrapper.m_prefixDestPath = m_devPath; + backupWrapper.m_frontUid = getuid(); + 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), 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("restoring"), 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(700); + 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(600); + 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(600); + labelError2->setIsOriginal(true); + labelError2->setWordWrap(true); + labelError2->adjustSize(); + hlayoutCenterFont3->addWidget(labelError2); + hlayoutCenterFont3->addStretch(); + vlayoutCenterFont->addLayout(hlayoutCenterFont3); + + // 第四行 + vlayoutCenterFont->addSpacing(30); + + // 第五行 + QHBoxLayout *hlayoutCenterFont5 = new QHBoxLayout; + // hlayoutCenterFont5->addSpacing(100); + hlayoutCenterFont5->addStretch(); + // 返回首页 + MyPushButton *homePage = new MyPushButton(last); + 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); + // 重启 + MyPushButton *reboot = new MyPushButton(centerFont); + reboot->setFixedSize(97, 36); + reboot->setText(tr("reboot system")); + reboot->setEnabled(true); + reboot->setAutoRepeat(true); + hlayoutCenterFont5->addWidget(reboot); + hlayoutCenterFont5->addStretch(); + vlayoutCenterFont->addLayout(hlayoutCenterFont5); + + 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(); + last->setLayout(vlayout); + + // 还原检测结果 + connect(this, &DataRestore::checkRestoreResult, 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("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); + } else { + dot1->setVisible(false); + labelError1->setVisible(false); + reboot->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("Restoring the data failed")); + dot1->setVisible(true); + dot2->setVisible(true); + labelError1->setDeplayText(errMsg); + labelError2->setDeplayText(errTip); + homePage->setVisible(true); + retry->setVisible(true); + reboot->setVisible(false); + } + }); + + // 再试一次 + connect(retry, &MyPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + 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, &MyPushButton::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 ; +} + + diff --git a/kybackup/module/datarestore.h b/kybackup/module/datarestore.h new file mode 100644 index 0000000..4c5f29f --- /dev/null +++ b/kybackup/module/datarestore.h @@ -0,0 +1,69 @@ +#ifndef DATARESTORE_H +#define DATARESTORE_H + +#include +#include "../backup_manager_interface.h" +#include "../backup-daemon/parsebackuplist.h" + +class DataRestore : public QStackedWidget +{ + Q_OBJECT +public: + enum DataRestoreState + { + IDEL = 0, // 空闲 + CHECKING, // 环境校验中 + RESTORING // 还原中 + }; + + enum DataRestorePage + { + HOME_PAGE, // 首页 + CHECK_ENV_PAGE, // 环境检测页 + RESTORE_PAGE, // 还原中页 + LAST_PAGE, // 结束页 + }; + +public: + explicit DataRestore(QWidget *parent = nullptr); + virtual ~DataRestore(); + +private: + void initFirstWidget(); + void initSecondWidget(); + void initThirdWidget(); + void initLastWidget(); + + bool checkIsNeedReboot(); + +signals: + void startCheckEnv(); + void checkEnvResult(bool result, const QString &errMsg = "", const QString &errTip = ""); + void startRestore(); + void progress(int state, int rate); + void checkRestoreResult(bool result, const QString &errMsg = "", const QString &errTip = ""); + +public slots: + void on_pre_clicked(bool checked = false); + void on_next_clicked(bool checked = false); + void on_button_beginRestore_clicked(bool checked = false); + void on_checkEnv_start(); + void on_checkEnv_end(int result); + void on_restore_start(); + void on_checkRestore_end(int result); + void on_restore_end(bool result); + void reboot(); + +private: + // dbus接口 + ComKylinBackupManagerInterface *m_pInterface; + + QString m_uuid; // 还原点的UUID + QString m_devPath; // 如果是从移动设备进行还原,此中保存移动设备挂载路径 + // 系统备份状态 + int m_dataRestoreState; + // 是否需要重启 + bool m_bNeedReboot; +}; + +#endif // DATARESTORE_H diff --git a/kybackup/module/selectrestorepoint.cpp b/kybackup/module/selectrestorepoint.cpp index 9c022a8..6416d64 100644 --- a/kybackup/module/selectrestorepoint.cpp +++ b/kybackup/module/selectrestorepoint.cpp @@ -20,8 +20,8 @@ SelectRestorePoint::SelectRestorePoint(QWidget *parent, BackupPointType backupTy initTableWidget(); // 刷新 - MyPushButton * buttonRefresh = new MyPushButton; - buttonRefresh->setText(tr("Refresh")); +// MyPushButton * buttonRefresh = new MyPushButton; +// buttonRefresh->setText(tr("Refresh")); // 确定按钮 MyPushButton * buttonOk = new MyPushButton; @@ -29,11 +29,11 @@ SelectRestorePoint::SelectRestorePoint(QWidget *parent, BackupPointType backupTy this->setResult(QDialog::Rejected); m_bottomLayout->addStretch(); - m_bottomLayout->addWidget(buttonRefresh); +// m_bottomLayout->addWidget(buttonRefresh); m_bottomLayout->addSpacing(10); m_bottomLayout->addWidget(buttonOk); - connect(buttonRefresh, &MyPushButton::clicked, this, &SelectRestorePoint::initTableWidget); +// connect(buttonRefresh, &MyPushButton::clicked, this, &SelectRestorePoint::initTableWidget); connect(this, &SelectRestorePoint::udiskChange, this, &SelectRestorePoint::initTableWidget); connect(buttonOk, &MyPushButton::clicked, this, [=](){ diff --git a/kybackup/module/systembackup.cpp b/kybackup/module/systembackup.cpp index b264c85..3b3a263 100755 --- a/kybackup/module/systembackup.cpp +++ b/kybackup/module/systembackup.cpp @@ -613,7 +613,7 @@ void SystemBackup::initForthWidget() labelBackupName->setDeplayText(tr("Backup Name")); MyLineEdit *editBackupName = new MyLineEdit(forth); editBackupName->setGeometry(238, 172, 350, 40); - editBackupName->setMaxLength(100); + editBackupName->setMaxLength(64); editBackupName->setPlaceholderText(QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss")); // 支持输入中英文数字和部分字符 // QRegExp regx("^[\u4e00-\u9fa5a-zA-Z0-9~!@#$%^&*()-_+={}':;'\\[\\].<>/? ¥()——;《》‘’:“”、?]+$"); //其中匹配中文[\u4e00-\u9fa5] diff --git a/kybackup/module/systemrestore.cpp b/kybackup/module/systemrestore.cpp index de46285..682ee65 100755 --- a/kybackup/module/systemrestore.cpp +++ b/kybackup/module/systemrestore.cpp @@ -82,33 +82,33 @@ void SystemRestore::initFirstWidget() labelNote_firstPage->setScaledContents(true); labelNote_firstPage->adjustSize(); - // 多点还原 - MyIconLabel *iconMultiBackup_firstPage = new MyIconLabel(first); - iconMultiBackup_firstPage->setGeometry(41, 244, 180, 36); - iconMultiBackup_firstPage->setThemeIcon("ukui-bf-many-spot-symbolic", ":/symbos/ukui-bf-many-spot-symbolic.png"); - iconMultiBackup_firstPage->setDesplayText(tr("Multi-Spot")); - iconMultiBackup_firstPage->setEnabled(false); + // 操作简单 + 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 *iconSmallSize_firstPage = new MyIconLabel(first); - iconSmallSize_firstPage->setGeometry(201, 244, 180, 36); - iconSmallSize_firstPage->setThemeIcon("ukui-bf-volume-symbolic", ":/symbos/ukui-bf-volume-symbolic.png"); - iconSmallSize_firstPage->setDesplayText(tr("Small Size")); - iconSmallSize_firstPage->setEnabled(false); - - // 安全 + // 安全可靠 MyIconLabel *iconSecurity_firstPage = new MyIconLabel(first); - iconSecurity_firstPage->setGeometry(41, 296, 180, 36); + iconSecurity_firstPage->setGeometry(201, 244, 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_firstPage = new MyIconLabel(first); - iconSimple_firstPage->setGeometry(201, 296, 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 *iconMultiBackup_firstPage = new MyIconLabel(first); + iconMultiBackup_firstPage->setGeometry(41, 296, 180, 36); + iconMultiBackup_firstPage->setThemeIcon("ukui-bf-damage-symbolic", ":/symbos/ukui-bf-damage-symbolic.png"); + iconMultiBackup_firstPage->setDesplayText(tr("Repair")); + iconMultiBackup_firstPage->setEnabled(false); + + // 自主操作 + MyIconLabel *iconSmallSize_firstPage = new MyIconLabel(first); + iconSmallSize_firstPage->setGeometry(201, 296, 180, 36); + iconSmallSize_firstPage->setThemeIcon("document-properties-symbolic", ":/symbos/document-properties-symbolic.png"); + iconSmallSize_firstPage->setDesplayText(tr("Independent")); + iconSmallSize_firstPage->setEnabled(false); // 开始还原按钮 MyPushButton *beginRestore = new MyPushButton(first); @@ -345,7 +345,7 @@ void SystemRestore::initSecondWidget() nextStep->setAutoRepeat(true); connect(nextStep, &MyPushButton::clicked, this, [=](bool checked) { this->on_next_clicked(checked); - this->startRestore(); + emit this->startRestore(); }); hlayoutCenterFont5->addWidget(nextStep); // 重新检测按钮 @@ -797,7 +797,7 @@ void SystemRestore::initLastWidget() 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_GRAY), QSize(200, 24)); + 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(); @@ -946,7 +946,7 @@ void SystemRestore::initLastWidget() connect(retry, &MyPushButton::clicked, this, [=](bool checked) { Q_UNUSED(checked) this->setCurrentIndex(SystemRestorePage::RESTORE_PAGE); - this->startRestore(); + emit this->startRestore(); }); addWidget(last);