From c3d9dd085be82fb3090a7731c50d1680bade5d83 Mon Sep 17 00:00:00 2001 From: zhaominyong Date: Sun, 26 Dec 2021 18:15:21 +0800 Subject: [PATCH] =?UTF-8?q?=E6=95=B0=E6=8D=AE=E5=A4=87=E4=BB=BD=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E9=98=B6=E6=AE=B5=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- backup-daemon/backup-daemon.pro | 4 + backup-daemon/databackupproxy.cpp | 378 ++++ backup-daemon/databackupproxy.h | 87 + .../myprocess/mountbackupprocess.cpp | 4 +- backup-daemon/parsebackuplist.cpp | 2 + backup-daemon/systembackupproxy.cpp | 1 + backup-daemon/udiskdatabackupproxy.cpp | 357 ++++ backup-daemon/udiskdatabackupproxy.h | 66 + backup-daemon/udisksystembackupproxy.cpp | 23 +- backup-daemon/udisksystembackupproxy.h | 22 +- kybackup/backuppointlistdialog.h | 1 + kybackup/component/backuplistwidget.cpp | 168 ++ kybackup/component/backuplistwidget.h | 50 + kybackup/component/myfileselect.cpp | 25 + kybackup/component/myfileselect.h | 15 + kybackup/globalbackupinfo.h | 14 + kybackup/kybackup.pro | 6 + kybackup/main.cpp | 8 +- kybackup/maindialog.cpp | 17 +- kybackup/module/databackup.cpp | 1591 +++++++++++++++++ kybackup/module/databackup.h | 94 + kybackup/module/managebackuppointlist.cpp | 4 +- kybackup/module/selectrestorepoint.cpp | 10 +- kybackup/module/systembackup.cpp | 26 +- kybackup/module/systemrestore.cpp | 14 +- 25 files changed, 2948 insertions(+), 39 deletions(-) create mode 100644 backup-daemon/databackupproxy.cpp create mode 100644 backup-daemon/databackupproxy.h create mode 100644 backup-daemon/udiskdatabackupproxy.cpp create mode 100644 backup-daemon/udiskdatabackupproxy.h create mode 100644 kybackup/component/backuplistwidget.cpp create mode 100644 kybackup/component/backuplistwidget.h create mode 100644 kybackup/component/myfileselect.cpp create mode 100644 kybackup/component/myfileselect.h create mode 100644 kybackup/module/databackup.cpp create mode 100644 kybackup/module/databackup.h diff --git a/backup-daemon/backup-daemon.pro b/backup-daemon/backup-daemon.pro index fc25d4e..8e80d52 100755 --- a/backup-daemon/backup-daemon.pro +++ b/backup-daemon/backup-daemon.pro @@ -31,6 +31,7 @@ HEADERS += \ ../common/spinlock_mutex.h \ ../common/utils.h \ backupmanager_adaptor.h \ + databackupproxy.h \ deletebackupproxy.h \ mybackupmanager.h \ mymountproxy.h \ @@ -42,6 +43,7 @@ HEADERS += \ parsebackuplist.h \ systembackupproxy.h \ systemrestoreproxy.h \ + udiskdatabackupproxy.h \ udisksystembackupproxy.h \ udisksystemrestoreproxy.h \ workerfactory.h @@ -53,6 +55,7 @@ SOURCES += \ ../common/reflect.cpp \ ../common/utils.cpp \ backupmanager_adaptor.cpp \ + databackupproxy.cpp \ deletebackupproxy.cpp \ main.cpp \ mybackupmanager.cpp \ @@ -65,6 +68,7 @@ SOURCES += \ parsebackuplist.cpp \ systembackupproxy.cpp \ systemrestoreproxy.cpp \ + udiskdatabackupproxy.cpp \ udisksystembackupproxy.cpp \ udisksystemrestoreproxy.cpp \ workerfactory.cpp diff --git a/backup-daemon/databackupproxy.cpp b/backup-daemon/databackupproxy.cpp new file mode 100644 index 0000000..23fe746 --- /dev/null +++ b/backup-daemon/databackupproxy.cpp @@ -0,0 +1,378 @@ +#include "databackupproxy.h" +#include +#include +#include +#include +#include "../common/utils.h" +#include "../common/mydusizetool.h" +#include "mymountproxy.h" +#include "myprocess/calcbackupsize.h" + +IMPLEMENT_DYNCREATE(DataBackupProxy) + +DataBackupProxy::DataBackupProxy() +{ + m_bSuccess = false; + m_p = nullptr; + m_size = 0; +} + +DataBackupProxy::~DataBackupProxy() +{ + delete m_p; + m_p = nullptr; +} + +/** + * @brief 环境检测 + * @return false,检测失败;true,检测成功 + */ +bool DataBackupProxy::checkEnvEx() +{ + qDebug() << "DataBackupProxy::checkEnv invoke begin"; + + // 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载 + MyMountProxy mountProxy; + if ( MountResult::MOUNTED != mountProxy.mountBackupPartition() ) { + emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL)); + return false; + } + + // 2、判断备份是否增量备份 + isIncBackup(); + + // 3、检测空间是否满足备份 + bool result = checkFreeCapacity(); + + qDebug() << "DataBackupProxy::checkEnv invoke end"; + return result; +} + +/** + * @brief 执行备份逻辑 + */ +void DataBackupProxy::doWorkEx() +{ + qDebug() << "DataBackupProxy::doWorkEx invoke begin"; + // 环境检测 + if (!checkEnvEx()) + return ; + + // 开始备份 + doBackup(); + qDebug() << "DataBackupProxy::doWorkEx invoke end"; +} + +void DataBackupProxy::cancelEx() +{} + +/** + * @brief 判断是否增量备份 + * @return true,增量备份; false,全量备份 + */ +bool DataBackupProxy::isIncBackup() +{ + QString backupPath; + ParseBackupList::BackupPoint point; + if (m_backupWrapper.m_uuid.isEmpty()) { + return false; + } else { + backupPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_backupWrapper.m_uuid + "/data"; + } + + backupPath.replace("//", "/"); + if (Utils::isDirExist(backupPath)) { + m_backupWrapper.m_bIncrement = true; + m_backupWrapper.m_type = BackupType::INC_BACKUP_DATA; + return true; + } + return false; +} + +/** + * @brief 校验剩余空间是否满足备份 + */ +bool DataBackupProxy::checkFreeCapacity() +{ + qDebug() << "DataBackupProxy::checkFreeCapacity invoke begin"; + + // 1、计算待备份数据的大小 + qint64 itotalSize = calcSizeForBackup(); + m_size = itotalSize; + // 备份过程中会有一些临时文件产生,会占用一部分空间,故我们预留500M的空间 + itotalSize += 5 * MB; + + // 2、计算备份分区剩余空间大小 + QString backupPath(Utils::getSysRootPath() + BACKUP_PATH); + backupPath.replace("//", "/"); + QStorageInfo backupDisk(backupPath); + qint64 freeSize = backupDisk.bytesFree(); + + // 3、校验空间是否足够 + bool result = true; + if (itotalSize > freeSize) { + emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH)); + result = false; + } else { + emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS)); + } + + qDebug() << "DataBackupProxy::checkFreeCapacity invoke end"; + return result; +} + +/** + * @brief 计算备份所需空间大小 + * @return 计算备份所需空间大小,单位字节 + */ +qint64 DataBackupProxy::calcSizeForBackup() +{ + QString destPath = Utils::getSysRootPath(); + + QStringList args; + if (m_backupWrapper.m_bIncrement) { + // 在原来的备份点上增量备份场景 + args = getRsyncArgs(DataBackupScene::TRY_INC_DATA_BACKUP); + destPath += BACKUP_SNAPSHOTS_PATH; + destPath += "/"; + destPath += m_backupWrapper.m_uuid; + destPath += "/data/"; + } else { + // 全量备份场景 + args = getRsyncArgs(DataBackupScene::TRY_DATA_BACKUP); + destPath += CHECK_PATH; + } + + // 拼接备份源路径和目标路径 + QString srcPath = Utils::getSysRootPath(); + srcPath += "/"; + srcPath.replace("//", "/"); + args << srcPath; + destPath.replace("//", "/"); + args << destPath; + Utils::mkpath(destPath); + + CalcBackupSize calcator; + return calcator.start(args); +} + +/** + * @brief 根据场景获取rsync命令参数 + * @param scene,场景 + * @return rsync的参数信息 + */ +QStringList DataBackupProxy::getRsyncArgs(DataBackupScene scene) +{ + QStringList args; + QString backupFile = "/tmp/.backup.user"; + Utils::writeFileByLines(backupFile, m_backupWrapper.m_backupPaths); + + switch (scene) { + case DataBackupScene::DATA_BACKUP : + args << "-avAHXr"; + args << "--info=progress2"; + args << "--no-inc-recursive"; + args << "--ignore-missing-args"; + args << "--delete"; + args << "--files-from" << backupFile; + break ; + case DataBackupScene::INC_DATA_BACKUP : + args << "-avAHXr"; + args << "--info=progress2"; + args << "--no-inc-recursive"; + args << "--ignore-missing-args"; + args << "--delete"; + args << "--files-from" << backupFile; + break ; + case DataBackupScene::TRY_DATA_BACKUP : + args << "-aAHXrn"; + args << "--stats"; + args << "--ignore-missing-args"; + args << "--files-from" << backupFile; + break ; + case DataBackupScene::TRY_INC_DATA_BACKUP : + args << "-aAHXrn"; + args << "--stats"; + args << "--ignore-missing-args"; + args << "--delete"; + args << "--files-from" << backupFile; + break ; + default: + return args; + } + + return args; +} + +/** + * @brief 备份 + */ +void DataBackupProxy::doBackup() +{ + qDebug() << "DataBackupProxy::doBackup invoke begin"; + + // 准备 + if (!doPrepare()) + return ; + + // 启动数据备份 + backupData(); + + qDebug() << "DataBackupProxy::doBackup invoke end"; +} + +/** + * @brief 备份准备 + * @return true,准备成功;false,准备失败 + */ +bool DataBackupProxy::doPrepare() +{ + qDebug() << "DataBackupProxy::doPrepare invoke begin"; + + m_bSuccess = false; + + // 1、设置当前备份的Uuid + if (m_backupWrapper.m_uuid.isEmpty()) { + // 新增备份点,不指定uuid的场景 + m_curUuid += Utils::createUuid(); + } else { + // 指定uuid备份的场景 + m_curUuid = m_backupWrapper.m_uuid; + } + + // 2、准备备份目录及文件 + m_destPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/data"; + m_destPath.replace("//", "/"); + if (!Utils::mkpath(m_destPath)) { + emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED)); + qCritical() << QString("mkdir %1 failed !").arg(m_destPath) ; + return false; + } + + m_userFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + PATHS_USER_FILE; + m_userFile.replace("//", "/"); + if (!Utils::writeFileByLines(m_userFile, m_backupWrapper.m_backupPaths)) { + emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED)); + qCritical() << QString("create file %1 failed !").arg(m_userFile) ; + return false; + } + + m_excludeUserFile = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + EXCLUDE_PATHS_USER_FILE; + m_excludeUserFile.replace("//", "/"); + if (!Utils::writeFileByLines(m_excludeUserFile, m_backupWrapper.m_backupExcludePaths)) { + emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED)); + qCritical() << QString("create file %1 failed !").arg(m_excludeUserFile) ; + return false; + } + + // 3、记录/backup/snapshots/backuplist.xml文件 + if (!recordBackupPoint()) { + qCritical() << "add or update item to backuplist.xml failed !"; + return false; + } + + qDebug() << "DataBackupProxy::doPrepare invoke end"; + return true; +} + +/** + * @brief 记录/backup/snapshots/backuplist.xml文件 + * @return true-成功;false-失败 + */ +bool DataBackupProxy::recordBackupPoint() +{ + m_backupPoint.m_backupName = m_backupWrapper.m_backupName; + m_backupPoint.m_uuid = m_curUuid; + m_backupPoint.m_iPosition = m_backupWrapper.m_iPosition; + m_backupPoint.m_type = m_backupWrapper.m_type; + m_backupPoint.m_size = Utils::StringBySize(m_size); + m_backupPoint.m_time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss"); + m_backupPoint.m_state = BACKUP_PARSE_STATE_FAIL_STRTING; + m_backupPoint.m_os = SystemInfo::m_os; + m_backupPoint.m_arch = SystemInfo::m_arch; + m_backupPoint.m_archdetect = SystemInfo::m_archDetect; + QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH; + xmlPath.replace("//", "/"); + ParseBackupList parse(xmlPath); + if (m_backupWrapper.m_bIncrement) { + if (parse.updateItem(m_backupPoint) != ParseBackupList::SUCCESS) { + emit checkResult(int(BackupResult::WRITE_STORAGEINFO_UPDATE_ITEM_FAIL)); + return false; + } + } else { + if (parse.addItem(m_backupPoint) != ParseBackupList::SUCCESS) { + emit checkResult(int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL)); + return false; + } + } + + return true; +} + +/** + * @brief 备份系统 + * @return true,备份成功;false,备份失败 + */ +bool DataBackupProxy::backupData() +{ + qDebug() << "DataBackupProxy::backupData invoke begin"; + + QStringList args; + if (m_backupWrapper.m_bIncrement) { + // 在原来的备份点上增量备份场景 + args = getRsyncArgs(DataBackupScene::INC_DATA_BACKUP); + } else { + // 全量备份场景 + args = getRsyncArgs(DataBackupScene::DATA_BACKUP); + } + + // 拼接备份源路径和目标路径 + QString srcPath = Utils::getSysRootPath(); + srcPath += "/"; + srcPath.replace("//", "/"); + args << srcPath; + QString destPath = m_destPath + "/"; + destPath.replace("//", "/"); + args << destPath; + + m_p = new RsyncPathToDirProcess(this); + connect(m_p, &RsyncPathToDirProcess::progress, this, &DataBackupProxy::progress); + connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) { + if (result) { + m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING; + m_backupPoint.m_size = Utils::StringBySize(Utils::getDirOrFileSize(m_destPath)); + QString xmlPath = Utils::getSysRootPath() + BACKUP_XML_PATH; + xmlPath.replace("//", "/"); + ParseBackupList parse(xmlPath); + parse.updateItem(m_backupPoint); + + // Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid)); + Utils::writeBackupLog(m_backupPoint.m_time + "," + + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + "," + + m_backupWrapper.m_note + "," + m_backupPoint.m_size + + "," + QString::number(m_backupWrapper.m_frontUid)); + Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName); + m_bSuccess = true; + } + emit this->workResult(result); + }); + m_p->start(args, false); + + do_kylin_security(m_destPath); + + qDebug() << "DataBackupProxy::backupData invoke end"; + return true; +} + +void DataBackupProxy::do_kylin_security(const QString& dstDir) +{ + int ret = 0; + ret = kysec_getstatus(); + if (ret > 0) { + QString seFilePath(dstDir + "/.exectl"); + QFile file(seFilePath); + file.open(QIODevice::WriteOnly); + file.close(); + } +} + diff --git a/backup-daemon/databackupproxy.h b/backup-daemon/databackupproxy.h new file mode 100644 index 0000000..31ba231 --- /dev/null +++ b/backup-daemon/databackupproxy.h @@ -0,0 +1,87 @@ +#ifndef DATABACKUPPROXY_H +#define DATABACKUPPROXY_H + +#include "workerfactory.h" +#include "myprocess/rsyncpathtodirprocess.h" +#include "parsebackuplist.h" + +class DataBackupProxy : public Worker +{ + Q_OBJECT + DECLARE_DYNCREATE(DataBackupProxy) +public: + // 系统备份的几种场景 + enum DataBackupScene { + DATA_BACKUP, // 系统备份 + INC_DATA_BACKUP, // 增量系统备份 + TRY_DATA_BACKUP, // 测试系统备份,可用于计算备份传输数据大小 + TRY_INC_DATA_BACKUP, // 测试增量系统备份,可用于计算备份传输数据大小 + }; + + explicit DataBackupProxy(); + virtual ~DataBackupProxy(); + +public: + // 环境检测 + virtual bool checkEnvEx(); + + // 任务处理 + virtual void doWorkEx(); + + // 任务取消 + virtual void cancelEx(); + +private: + // 校验剩余空间是否满足备份 + bool checkFreeCapacity(); + + // 计算备份所需空间大小 + qint64 calcSizeForBackup(); + + /** + * @brief 记录/backup/snapshots/backuplist.xml文件 + * @return true-成功;false-失败 + */ + bool recordBackupPoint(); + + // 备份准备 + bool doPrepare(); + + // 备份 + void doBackup(); + + // 备份系统 + bool backupData(); + +protected: + // 判断是否增量备份 + bool isIncBackup(); + + /** + * @brief 根据场景获取rsync命令参数 + * @param scene,场景 + * @return 组装好的rsync的参数信息 + */ + QStringList getRsyncArgs(DataBackupScene scene); + + void do_kylin_security(const QString& dstDir); + + // 是否完成 + bool m_bSuccess; + // 当前备份uuid + QString m_curUuid; + // 当前备份目标目录 + QString m_destPath; + // 当前备份所需空间大小 + qint64 m_size; + // 备份点用户备份路径文件 + QString m_userFile; + // 备份点排除备份路径文件 + QString m_excludeUserFile; + // 备份进程 + RsyncPathToDirProcess *m_p; + // 当前备份节点 + ParseBackupList::BackupPoint m_backupPoint; +}; + +#endif // DATABACKUPPROXY_H diff --git a/backup-daemon/myprocess/mountbackupprocess.cpp b/backup-daemon/myprocess/mountbackupprocess.cpp index dfe588d..dd58558 100755 --- a/backup-daemon/myprocess/mountbackupprocess.cpp +++ b/backup-daemon/myprocess/mountbackupprocess.cpp @@ -53,12 +53,12 @@ bool MountBackupProcess::umountBackupPartition() arguments << QString("/backup"); m_p->start("umount", arguments); if (!m_p->waitForStarted()) { - qCritical("mount ro backup process start failed!"); + qCritical("umount /backup process start failed!"); return false; } if (!m_p->waitForFinished()) { - qCritical("mount ro backup process end failed!"); + qCritical("umount /backup process end failed!"); return false; } diff --git a/backup-daemon/parsebackuplist.cpp b/backup-daemon/parsebackuplist.cpp index 0c238ed..be79023 100755 --- a/backup-daemon/parsebackuplist.cpp +++ b/backup-daemon/parsebackuplist.cpp @@ -296,6 +296,8 @@ void ParseBackupList::elementNodeToBackupPoint(const QDomElement& node, BackupPo QDomElement eleComment = node.firstChildElement(COMMENT); if (!eleComment.isNull()) backupPoint.m_backupName = eleComment.text(); + if (backupPoint.m_uuid == FACTORY_BACKUP_UUID) + backupPoint.m_backupName = QObject::tr("factory backup"); QDomElement eleTime = node.firstChildElement(TIME); if (!eleTime.isNull()) diff --git a/backup-daemon/systembackupproxy.cpp b/backup-daemon/systembackupproxy.cpp index 4815237..5bc3869 100755 --- a/backup-daemon/systembackupproxy.cpp +++ b/backup-daemon/systembackupproxy.cpp @@ -184,6 +184,7 @@ QStringList SystemBackupProxy::getRsyncArgs(SystemBackupScene scene) args << "--info=progress2"; args << "--no-inc-recursive"; args << "--ignore-missing-args"; + args << "--delete"; break ; case SystemBackupScene::INC_SYSTEM_BACKUP : args << "-avAXr"; diff --git a/backup-daemon/udiskdatabackupproxy.cpp b/backup-daemon/udiskdatabackupproxy.cpp new file mode 100644 index 0000000..d048795 --- /dev/null +++ b/backup-daemon/udiskdatabackupproxy.cpp @@ -0,0 +1,357 @@ +#include "udiskdatabackupproxy.h" +#include +#include +#include +#include +#include +#include "../common/utils.h" +#include "../common/mydusizetool.h" +#include "mymountproxy.h" +#include "myprocess/calcbackupsize.h" + +IMPLEMENT_DYNCREATE(UDiskDataBackupProxy) + +UDiskDataBackupProxy::UDiskDataBackupProxy() +{ + m_isFinished = false; + m_bSuccess = false; + m_p = nullptr; + m_size = 0; + m_calc = new CalcBackupSize(this); + m_isOnlyCheck = true; +} + +UDiskDataBackupProxy::~UDiskDataBackupProxy() +{ + delete m_p; + m_p = nullptr; + delete m_calc; + m_calc = nullptr; +} + +/** + * @brief 环境检测 + * @return false,检测失败;true,检测成功 + */ +bool UDiskDataBackupProxy::checkEnvEx() +{ + qDebug() << "UDiskDataBackupProxy::checkEnv invoke begin"; + + // 1、检查/backup分区是否挂载上(不管是本地磁盘还是u盘设备,都得保证/backup挂载上); 若没挂载,挂载 + MyMountProxy mountProxy; + if ( MountResult::MOUNTED != mountProxy.mountBackupPartition() ) { + emit checkResult(int(BackupResult::BACKUP_PARTITION_MOUNT_FAIL)); + return false; + } + + QString backupPath(m_backupWrapper.m_prefixDestPath); + backupPath.replace("//", "/"); + QStorageInfo udisk(backupPath); + QString udisk_type = udisk.fileSystemType(); + if (udisk_type == "vfat") { + qCritical() << m_backupWrapper.m_prefixDestPath + " udisk's filesystemtype is vfat"; + emit checkResult(int(BackupResult::UDISK_FILESYSTEM_TYPE_IS_VFAT)); + return false; + } + if (udisk.isReadOnly()) { + // 只读挂载的U盘 + qCritical() << QString("udisk(%s) is readonly filesystem").arg(m_backupWrapper.m_prefixDestPath); + emit checkResult(int(BackupResult::UDISK_FILESYSTEM_IS_READONLY)); + return false; + } + + QTimer::singleShot(1*1000, this, &UDiskDataBackupProxy::checkDestDirExists); + + // 2、判断备份是否增量备份 + isIncBackup(); + + // 3、检测空间是否满足备份 + calcSizeForBackupToUdisk(); + + qDebug() << "UDiskDataBackupProxy::checkEnv invoke end"; + return true; +} + +/** + * @brief 执行备份逻辑 + */ +void UDiskDataBackupProxy::doWorkEx() +{ + qDebug() << "UDiskDataBackupProxy::doWorkEx invoke begin"; + + m_isOnlyCheck = false; + // 环境检测 + checkEnvEx(); + + qDebug() << "UDiskDataBackupProxy::doWorkEx invoke end"; +} + +void UDiskDataBackupProxy::cancelEx() +{} + +/** + * @brief 校验剩余空间是否满足备份 + */ +bool UDiskDataBackupProxy::checkFreeCapacityToUdisk(qint64 itotalSize) +{ + qDebug() << "UDiskDataBackupProxy::checkFreeCapacityToUdisk invoke begin"; + + // 1、计算待备份数据的大小 + m_size = itotalSize; + // 备份过程中会有一些临时文件产生,会占用一部分空间,故我们预留500M的空间 + itotalSize += 5 * MB; + + // 2、计算备份分区剩余空间大小 + QString backupPath(m_backupWrapper.m_prefixDestPath); + backupPath.replace("//", "/"); + QStorageInfo backupDisk(backupPath); + qint64 freeSize = backupDisk.bytesFree(); + + // 3、校验空间是否足够 + bool result = true; + if (itotalSize > freeSize) { + emit checkResult(int(BackupResult::BACKUP_CAPACITY_IS_NOT_ENOUGH)); + result = false; + } else { + emit checkResult(int(BackupResult::CHECK_ENV_SUCCESS)); + } + + if (m_isOnlyCheck) + return result; + + // 开始备份 + doBackupToUdisk(); + + qDebug() << "UDiskDataBackupProxy::checkFreeCapacityToUdisk invoke end"; + return result; +} + +/** + * @brief 计算备份所需空间大小 + * @return 计算备份所需空间大小,单位字节 + */ +void UDiskDataBackupProxy::calcSizeForBackupToUdisk() +{ + QString destPath; + QStringList args; + if (m_backupWrapper.m_bIncrement) { + // 在原来的备份点上增量备份场景 + args = getRsyncArgs(DataBackupScene::TRY_INC_DATA_BACKUP); + destPath = m_backupWrapper.m_prefixDestPath; + destPath += BACKUP_SNAPSHOTS_PATH; + destPath += "/"; + destPath += m_backupWrapper.m_uuid; + destPath += "/data/"; + } else { + // 全量备份场景 + args = getRsyncArgs(DataBackupScene::TRY_DATA_BACKUP); + destPath = Utils::getSysRootPath(); + destPath += CHECK_PATH; + } + + // 拼接备份源路径和目标路径 + QString srcPath = Utils::getSysRootPath(); + srcPath += "/"; + srcPath.replace("//", "/"); + args << srcPath; + destPath.replace("//", "/"); + args << destPath; + Utils::mkpath(destPath); + + connect(m_calc, &CalcBackupSize::finished, this, &UDiskDataBackupProxy::checkFreeCapacityToUdisk); + m_calc->start(args, false); +} + +/** + * @brief 备份 + */ +void UDiskDataBackupProxy::doBackupToUdisk() +{ + qDebug() << "UDiskDataBackupProxy::doBackupToUdisk invoke begin"; + + // 准备 + if (!doPrepareToUdisk()) + return ; + + // 启动数据备份 + backupDataToUdisk(); + + qDebug() << "UDiskDataBackupProxy::doBackupToUdisk invoke end"; +} + +/** + * @brief 备份准备 + * @return true,准备成功;false,准备失败 + */ +bool UDiskDataBackupProxy::doPrepareToUdisk() +{ + qDebug() << "UDiskDataBackupProxy::doPrepareToUdisk invoke begin"; + + m_bSuccess = false; + + // 1、设置当前备份的Uuid + if (m_backupWrapper.m_uuid.isEmpty()) { + // 新增备份点,不指定uuid的场景 + m_curUuid += Utils::createUuid(); + } else { + // 指定uuid备份的场景 + m_curUuid = m_backupWrapper.m_uuid; + } + + // 2、准备备份目录及文件 + m_destPath = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/data"; + m_destPath.replace("//", "/"); + if (!Utils::mkpath(m_destPath)) { + emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED)); + qCritical() << QString("mkdir %1 failed !").arg(m_destPath) ; + return false; + } + + m_userFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + PATHS_USER_FILE; + m_userFile.replace("//", "/"); + if (!Utils::writeFileByLines(m_userFile, m_backupWrapper.m_backupPaths)) { + emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED)); + qCritical() << QString("create file %1 failed !").arg(m_userFile) ; + return false; + } + + m_excludeUserFile = m_backupWrapper.m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_curUuid + "/" + EXCLUDE_PATHS_USER_FILE; + m_excludeUserFile.replace("//", "/"); + if (!Utils::writeFileByLines(m_excludeUserFile, m_backupWrapper.m_backupExcludePaths)) { + emit checkResult(int(BackupResult::WRITE_BACKUP_PATHS_TO_USER_FAILED)); + qCritical() << QString("create file %1 failed !").arg(m_excludeUserFile) ; + return false; + } + + // 3、记录/backup/snapshots/backuplist.xml文件 + if (!recordBackupPointToUdisk()) { + qCritical() << "add or update item to backuplist.xml failed !"; + return false; + } + + qDebug() << "UDiskDataBackupProxy::doPrepareToUdisk invoke end"; + return true; +} + +/** + * @brief 记录/backup/snapshots/backuplist.xml文件 + * @return true-成功;false-失败 + */ +bool UDiskDataBackupProxy::recordBackupPointToUdisk() +{ + m_backupPoint.m_backupName = m_backupWrapper.m_backupName; + m_backupPoint.m_uuid = m_curUuid; + m_backupPoint.m_iPosition = m_backupWrapper.m_iPosition; + m_backupPoint.m_type = m_backupWrapper.m_type; + m_backupPoint.m_size = Utils::StringBySize(m_size); + m_backupPoint.m_time = QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss"); + m_backupPoint.m_state = BACKUP_PARSE_STATE_FAIL_STRTING; + m_backupPoint.m_os = SystemInfo::m_os; + m_backupPoint.m_arch = SystemInfo::m_arch; + m_backupPoint.m_archdetect = SystemInfo::m_archDetect; + QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH; + xmlPath.replace("//", "/"); + ParseBackupList parse(xmlPath); + if (!m_backupWrapper.m_bIncrement) { + if (parse.addItem(m_backupPoint) != ParseBackupList::SUCCESS) { + emit checkResult(int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL)); + return false; + } + } else { + if (parse.updateItem(m_backupPoint) != ParseBackupList::SUCCESS) { + emit checkResult(int(BackupResult::WRITE_STORAGEINFO_UPDATE_ITEM_FAIL)); + return false; + } + } + + return true; +} + +/** + * @brief 备份系统 + * @return true,备份成功;false,备份失败 + */ +bool UDiskDataBackupProxy::backupDataToUdisk() +{ + qDebug() << "UDiskDataBackupProxy::backupDataToUdisk invoke begin"; + + QStringList args; + if (m_backupWrapper.m_bIncrement) { + // 在原来的备份点上增量备份场景 + args = getRsyncArgs(DataBackupScene::INC_DATA_BACKUP); + } else { + // 全量备份场景 + args = getRsyncArgs(DataBackupScene::DATA_BACKUP); + } + + // 拼接备份源路径和目标路径 + QString srcPath = Utils::getSysRootPath(); + srcPath += "/"; + srcPath.replace("//", "/"); + args << srcPath; + QString destPath = m_destPath + "/"; + destPath.replace("//", "/"); + args << destPath; + + m_p = new RsyncPathToDirProcess(this); + connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskDataBackupProxy::progress); + connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) { + m_isFinished = true; + if (result) { + m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING; + m_backupPoint.m_size = Utils::StringBySize(Utils::getDirOrFileSize(m_destPath)); + QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH; + xmlPath.replace("//", "/"); + ParseBackupList parse(xmlPath); + if (ParseBackupList::ParseResult::SUCCESS != parse.updateItem(m_backupPoint)) { + qCritical() << "update backuplist.xml error in sendBackupResult"; + result = false; + } else { + // Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid)); + Utils::writeBackupLog(m_backupPoint.m_time + "," + + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + "," + + m_backupWrapper.m_note + "," + m_backupPoint.m_size + + "," + QString::number(m_backupWrapper.m_frontUid)); + Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName); + m_bSuccess = true; + } + } + emit this->workResult(result); + }); + m_p->start(args, false); + + do_kylin_security(m_destPath); + + qDebug() << "UDiskDataBackupProxy::backupDataToUdisk invoke end"; + return true; +} + +/** + * @brief 校验移动盘是否还在 + * @return: bool,存在返回true;不存在返回false + * @author: zhaominyong + * @since: 2021/05/24 + * @note: + * add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据 + */ +bool UDiskDataBackupProxy::checkDestDirExists() +{ + QDir dir(m_backupWrapper.m_prefixDestPath); + if (!dir.exists()) { + qCritical() << QString("dstDir %s is not exist!").arg(m_backupWrapper.m_prefixDestPath); + + if (m_p) + m_p->stop(); + + return false; + } + + if (!m_isFinished) + { + QTimer::singleShot(1*1000, this, &UDiskDataBackupProxy::checkDestDirExists); + } + + return true; +} + + diff --git a/backup-daemon/udiskdatabackupproxy.h b/backup-daemon/udiskdatabackupproxy.h new file mode 100644 index 0000000..d64b0bf --- /dev/null +++ b/backup-daemon/udiskdatabackupproxy.h @@ -0,0 +1,66 @@ +#ifndef UDISKDATABACKUPPROXY_H +#define UDISKDATABACKUPPROXY_H + +#include "databackupproxy.h" +#include "myprocess/calcbackupsize.h" + +class UDiskDataBackupProxy : public DataBackupProxy +{ + Q_OBJECT + DECLARE_DYNCREATE(UDiskDataBackupProxy) +public: + explicit UDiskDataBackupProxy(); + virtual ~UDiskDataBackupProxy(); + +public: + // 环境检测 + virtual bool checkEnvEx(); + + // 任务处理 + virtual void doWorkEx(); + + // 任务取消 + virtual void cancelEx(); + +private slots: + // 校验剩余空间是否满足备份 + bool checkFreeCapacityToUdisk(qint64 itotalSize); + + // 备份 + void doBackupToUdisk(); + + /** + * @brief 校验移动盘是否还在 + * @return: bool,存在返回true;不存在返回false + * @author: zhaominyong + * @since: 2021/05/24 + * @note: + * add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据 + */ + bool checkDestDirExists(); + +private: + // 计算备份所需空间大小 + void calcSizeForBackupToUdisk(); + + /** + * @brief 记录/backup/snapshots/backuplist.xml文件 + * @return true-成功;false-失败 + */ + bool recordBackupPointToUdisk(); + + // 备份准备 + bool doPrepareToUdisk(); + + // 备份系统 + bool backupDataToUdisk(); + + // 计算备份空间大小的进程 + CalcBackupSize *m_calc; + // 是否只是检测 + bool m_isOnlyCheck; + // 是否完成 + bool m_isFinished; +}; + +#endif // UDISKDATABACKUPPROXY_H diff --git a/backup-daemon/udisksystembackupproxy.cpp b/backup-daemon/udisksystembackupproxy.cpp index e19e433..804a3b9 100755 --- a/backup-daemon/udisksystembackupproxy.cpp +++ b/backup-daemon/udisksystembackupproxy.cpp @@ -15,6 +15,7 @@ IMPLEMENT_DYNCREATE(UDiskSystemBackupProxy) UDiskSystemBackupProxy::UDiskSystemBackupProxy() { m_bSuccess = false; + m_isFinished = false; m_p = nullptr; m_size = 0; m_calc = new CalcBackupSize(this); @@ -455,21 +456,25 @@ bool UDiskSystemBackupProxy::backup(const QStringList &args) m_p = new RsyncPathToDirProcess(this); connect(m_p, &RsyncPathToDirProcess::progress, this, &UDiskSystemBackupProxy::progress); connect(m_p, &RsyncPathToDirProcess::finished, this, [&](bool result) { + m_isFinished = true; if (result) { m_backupPoint.m_state = BACKUP_PARSE_STATE_SUCCESS_STRTING; m_backupPoint.m_size = Utils::StringBySize(Utils::getDirOrFileSize(m_destPath)); QString xmlPath = m_backupWrapper.m_prefixDestPath + BACKUP_XML_PATH; xmlPath.replace("//", "/"); ParseBackupList parse(xmlPath); - parse.updateItem(m_backupPoint); + if (ParseBackupList::ParseResult::SUCCESS != parse.updateItem(m_backupPoint)) { + qCritical() << "update backuplist.xml error in sendBackupResult"; + result = false; + } else { + // Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid)); + Utils::writeBackupLog(m_backupPoint.m_time + "," + + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + "," + + m_backupWrapper.m_note + "," + m_backupPoint.m_size); - // Utils::writeBackupLog(time + "," + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + ","+ m_backupWrapper.m_note + "," + m_backupPoint.m_size+ "," + QString::number(m_backupWrapper.m_frontUid)); - Utils::writeBackupLog(m_backupPoint.m_time + "," - + m_curUuid + "," + QString::number(m_backupWrapper.m_type) + "," - + m_backupWrapper.m_note + "," + m_backupPoint.m_size); - - Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName); - m_bSuccess = true; + Utils::update_backup_unique_settings(m_curUuid, m_backupPoint.m_backupName); + m_bSuccess = true; + } } emit this->workResult(result); }); @@ -518,7 +523,7 @@ bool UDiskSystemBackupProxy::checkDestDirExists() return false; } - if (!m_bSuccess) + if (!m_isFinished) { QTimer::singleShot(1*1000, this, &UDiskSystemBackupProxy::checkDestDirExists); } diff --git a/backup-daemon/udisksystembackupproxy.h b/backup-daemon/udisksystembackupproxy.h index dc5cf13..84fddd5 100755 --- a/backup-daemon/udisksystembackupproxy.h +++ b/backup-daemon/udisksystembackupproxy.h @@ -46,6 +46,16 @@ private slots: // 备份 void doBackup(); + /** + * @brief 校验移动盘是否还在 + * @return: bool,存在返回true;不存在返回false + * @author: zhaominyong + * @since: 2021/05/24 + * @note: + * add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据 + */ + bool checkDestDirExists(); + private: // 判断是否增量备份 bool isIncBackup(); @@ -79,21 +89,13 @@ private: void do_kylin_security(const QString& dstDir); - /** - * @brief 校验移动盘是否还在 - * @return: bool,存在返回true;不存在返回false - * @author: zhaominyong - * @since: 2021/05/24 - * @note: - * add by zhaominyong at 2021/05/24 for bug:54377 【备份还原】备份数据到U盘的过程中拔出U盘,备份还原工具仍然一直显示正在备份数据 - */ - bool checkDestDirExists(); - // 计算备份空间大小的进程 CalcBackupSize *m_calc; // 压缩进程 MkSquashFSProcess *m_mksquashfs; + // 是否完成 + bool m_isFinished; // 是否备份成功 bool m_bSuccess; // 当前备份uuid diff --git a/kybackup/backuppointlistdialog.h b/kybackup/backuppointlistdialog.h index 0568dbc..69f1211 100755 --- a/kybackup/backuppointlistdialog.h +++ b/kybackup/backuppointlistdialog.h @@ -32,6 +32,7 @@ public: QList getBackupPointList(); + void setIsOnlyShowLocal(bool onlyShowLocal) { m_onlyShowLocal = onlyShowLocal; } bool isOnlyShowLocal() const { return m_onlyShowLocal; } signals: diff --git a/kybackup/component/backuplistwidget.cpp b/kybackup/component/backuplistwidget.cpp new file mode 100644 index 0000000..c81e11a --- /dev/null +++ b/kybackup/component/backuplistwidget.cpp @@ -0,0 +1,168 @@ +#include "backuplistwidget.h" +#include +#include +#include +#include +#include +#include "mylabel.h" +#include "../messageboxutils.h" + +BackupListWidget::BackupListWidget(QWidget *parent /*= nullptr*/) : + QListWidget(parent) +{ + setSortingEnabled(false); + setAcceptDrops(true); + + // 列表为空时,展示一个“+”号图标和拖拽文件提示 + m_plusLogo = new MyIconLabel; + m_plusLogo->setFixedHeight(36); + m_plusLogo->setThemeIcon("list-add-symbolic", ":/symbos/list-add-symbolic.png"); + m_plusLogo->setDesplayText(tr("File drag and drop area")); + m_plusLogo->setEnabled(false); + + QHBoxLayout *hlayout = new QHBoxLayout; + hlayout->addStretch(); + hlayout->addWidget(m_plusLogo); + hlayout->addStretch(); + + QVBoxLayout *vlayout = new QVBoxLayout; + vlayout->addStretch(); + vlayout->addLayout(hlayout); + vlayout->addStretch(); + setLayout(vlayout); +} + +BackupListWidget::~BackupListWidget() +{} + +int BackupListWidget::findIndexOfItem(QListWidgetItem *item) +{ + int index = -1; + for (int row = 0; row < this->count(); ++row) { + if (item == this->item(row)) { + index = row; + break; + } + } + + return index; +} + +bool BackupListWidget::contains(const QString& text) +{ + // 1、针对使用addItem等的正规使用场景(展示内容在原生item上) + if (findItems(text, Qt::MatchCaseSensitive).size() > 0) + return true; + + // 2、针对使用setItemWidget添加项(展示内容在widget上)的特殊使用场景 + return m_List.contains(text); +} + +bool BackupListWidget::appendItem(const QString &text) +{ + if (!checkPathLimit(text)) + return false; + + int count = this->count(); + if (count > 0) + ++count; + + int width = this->width(); + + QListWidgetItem *item = new QListWidgetItem(this, m_type); + item->setSizeHint(QSize(width - 10, 36)); + QWidget *widget = new QWidget; + QHBoxLayout *hlayout = new QHBoxLayout; + + MyLabel *label = new MyLabel; + label->setDeplayText(text); + label->setToolTip(text); + label->setFixedSize(width - 50, 36); + label->setAlignment(Qt::AlignTop); + hlayout->addWidget(label); + m_List << text; + + QPushButton *buttonDelete = new QPushButton; + buttonDelete->setProperty("isWindowButton", 0x2); + buttonDelete->setProperty("useIconHighlightEffect", 0x8); + buttonDelete->setFlat(true); + buttonDelete->setFixedSize(20, 20); + buttonDelete->setIcon(QIcon::fromTheme("window-close-symbolic")); + hlayout->addWidget(buttonDelete); + + widget->setLayout(hlayout); + + this->setItemWidget(item, widget); + this->setCurrentItem(item); + + connect(buttonDelete, &QPushButton::clicked, [=]() { + this->m_List.removeOne(label->text()); + this->takeItem(this->findIndexOfItem(item)); + delete item; + if (this->count() == 0) + m_plusLogo->setVisible(true); + }); + + m_plusLogo->setVisible(false); + return true; +} + +void BackupListWidget::dropEvent(QDropEvent *event) +{ + if (event->mimeData()->hasUrls()) { + for (QUrl url : event->mimeData()->urls()) { + QString file = url.toString(); + if (file.startsWith("file://")) { + file.replace("file://", ""); + appendItem(file); + } + } + } +} + +bool BackupListWidget::checkPathLimit(const QString &path) +{ + // 1、列表中是否已经存在 + if (contains(path)) { + MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), + QObject::tr("Path already exists : ") + path, + QObject::tr("Ok")); + return false; + } + + // 2、路径是否存在 + QFileInfo fileInfo(path); + if (!fileInfo.exists()) { + MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), + QObject::tr("The file or directory does not exist : ") + path, + QObject::tr("Ok")); + return false; + } + + // 3、是否是限定路径及其子路径 + bool blimit = false; + QString dirCanBeSelected; + for (const QString &item : m_pathLimit) { + if (path.startsWith(item)) { + blimit = true; + break; + } + + if (dirCanBeSelected.isEmpty()) + dirCanBeSelected = item; + else { + dirCanBeSelected += ","; + dirCanBeSelected += item; + } + } + if (m_pathLimit.size() > 0 && !blimit) { + MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), + QObject::tr("Only data that exists in the follow directorys can be selected: ") + dirCanBeSelected, + QObject::tr("Ok")); + return false; + } + + return true; +} + + diff --git a/kybackup/component/backuplistwidget.h b/kybackup/component/backuplistwidget.h new file mode 100644 index 0000000..0c5fb2e --- /dev/null +++ b/kybackup/component/backuplistwidget.h @@ -0,0 +1,50 @@ +#ifndef REMOVABLELISTWIDGET_H +#define REMOVABLELISTWIDGET_H + +#include +#include +#include +#include "myiconlabel.h" + +class BackupListWidget : public QListWidget +{ + Q_OBJECT +public: + explicit BackupListWidget(QWidget *parent = nullptr); + virtual ~BackupListWidget(); + + // 添加列表项,注意使用本类的功能不能用addItem等基类添加项的方法 + bool appendItem(const QString &text); + + // 根据QListWidgetItem*查找项对应的索引序号 + int findIndexOfItem(QListWidgetItem *item); + + // 判断列表项是否包含text,注意使用时不能用findItems等基类查找方法 + bool contains(const QString &text); + + // 获取备份路径列表 + QStringList getBackupPaths() { return m_List; } + + // 设置备份路径限制为只能是pathLimit或其子路径 + void setPathLimit(const QStringList &pathLimit) { m_pathLimit.append(pathLimit); } + + // 清空 + void clearData() { + this->clear(); + m_List.clear(); + } + +protected: + void dropEvent(QDropEvent *e); + +private: + bool checkPathLimit(const QString &path); + +private: + MyIconLabel *m_plusLogo; + int m_type = QListWidgetItem::ItemType::UserType + 1; + QStringList m_List; + QStringList m_pathLimit; +}; + +#endif // REMOVABLELISTWIDGET_H diff --git a/kybackup/component/myfileselect.cpp b/kybackup/component/myfileselect.cpp new file mode 100644 index 0000000..aa7004f --- /dev/null +++ b/kybackup/component/myfileselect.cpp @@ -0,0 +1,25 @@ +#include "myfileselect.h" +#include +#include + +MyFileSelect::MyFileSelect(QWidget* parent) : + QFileDialog(parent) +{ + this->setViewMode(QFileDialog::List); + this->setFileMode(QFileDialog::ExistingFiles); + this->setFilter(QDir::System | QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); + + QDialogButtonBox* button = this->findChild("buttonBox"); + disconnect(button, SIGNAL(accepted()), this, SLOT(accept())); + connect(button, SIGNAL(accepted()), this, SLOT(goAccept())); + + QLineEdit *fileNameEdit = this->findChild("fileNameEdit"); + connect(this, &MyFileSelect::currentChanged, this, [=](const QString& path){ + fileNameEdit->setText(path.section('/', -1)); + }); +} + +void MyFileSelect::goAccept() +{ + QDialog::accept(); +} diff --git a/kybackup/component/myfileselect.h b/kybackup/component/myfileselect.h new file mode 100644 index 0000000..a626a9a --- /dev/null +++ b/kybackup/component/myfileselect.h @@ -0,0 +1,15 @@ +#ifndef MYFILESELECT_H +#define MYFILESELECT_H + +#include + +class MyFileSelect : public QFileDialog { + Q_OBJECT +public: + explicit MyFileSelect(QWidget* parent = nullptr); + +public slots: + void goAccept(); +}; + +#endif // MYFILESELECT_H diff --git a/kybackup/globalbackupinfo.h b/kybackup/globalbackupinfo.h index e60dcb9..7099a5c 100755 --- a/kybackup/globalbackupinfo.h +++ b/kybackup/globalbackupinfo.h @@ -11,6 +11,16 @@ public: GlobelBackupInfo(token) {} ~GlobelBackupInfo() {} + // 设置是否管理员用户登录 + void setIsManager(bool isManager) { m_isManager = isManager; } + // 是否管理员用户登录 + bool isManager() { return m_isManager; } + + // 设置是否以--restore参数启动的备份还原工具 + void setHasArgRestore(bool hasArg_restore) { m_hasArg_restore = hasArg_restore; } + // 是否以--restore参数启动的备份还原工具 + bool hasArgRestore() { return m_hasArg_restore; } + // 设置是否正在进行备份、还原等操作 void setIsBusy(bool isBusy) { std::lock_guard lock(m_interMutex); @@ -61,12 +71,16 @@ public: } private: + // 是否管理员 + bool m_isManager = true; // 是否正在进行备份、还原等操作 bool m_isBusy = false; // 是否有备份分区 bool m_hasBackupPartition = true; // 当前功能类型 FuncTypeConverter::FunType m_funcType = FuncTypeConverter::FunType::TOTALMODULES; + // 是否以--restore参数启动的备份还原工具 + bool m_hasArg_restore = false; // 全局信号对象 GlobalSignals m_globalSignals; diff --git a/kybackup/kybackup.pro b/kybackup/kybackup.pro index 467757b..543613f 100755 --- a/kybackup/kybackup.pro +++ b/kybackup/kybackup.pro @@ -37,12 +37,14 @@ HEADERS += \ ../common/utils.h \ backup_manager_interface.h \ backuppointlistdialog.h \ + component/backuplistwidget.h \ component/circlelabel.h \ component/clicklabel.h \ component/hoverwidget.h \ component/imageutil.h \ component/linelabel.h \ component/mycheckbox.h \ + component/myfileselect.h \ component/myiconbutton.h \ component/myiconlabel.h \ component/mylabel.h \ @@ -57,6 +59,7 @@ HEADERS += \ leftsiderbarwidget.h \ maindialog.h \ messageboxutils.h \ + module/databackup.h \ module/managebackuppointlist.h \ module/selectrestorepoint.h \ module/systembackup.h \ @@ -74,12 +77,14 @@ SOURCES += \ ../common/utils.cpp \ backup_manager_interface.cpp \ backuppointlistdialog.cpp \ + component/backuplistwidget.cpp \ component/circlelabel.cpp \ component/clicklabel.cpp \ component/hoverwidget.cpp \ component/imageutil.cpp \ component/linelabel.cpp \ component/mycheckbox.cpp \ + component/myfileselect.cpp \ component/myiconbutton.cpp \ component/myiconlabel.cpp \ component/mylabel.cpp \ @@ -93,6 +98,7 @@ SOURCES += \ main.cpp \ maindialog.cpp \ messageboxutils.cpp \ + module/databackup.cpp \ module/managebackuppointlist.cpp \ module/selectrestorepoint.cpp \ module/systembackup.cpp \ diff --git a/kybackup/main.cpp b/kybackup/main.cpp index 8dcfe2f..0ae2819 100755 --- a/kybackup/main.cpp +++ b/kybackup/main.cpp @@ -14,6 +14,7 @@ #include "qtsingleapplication/qtsingleapplication.h" #include "../common/utils.h" #include "xatom-helper.h" +#include "globalbackupinfo.h" // 声明 void initApp(QApplication& a); @@ -35,7 +36,8 @@ int main(int argc, char *argv[]) initApp(a); // 当前只支持管理员用户使用备份还原工具 - if (!isManager()) { + GlobelBackupInfo::inst().setIsManager(isManager()); + if (!GlobelBackupInfo::inst().isManager() && GlobelBackupInfo::inst().hasArgRestore()) { QMessageBox box(QMessageBox::Warning, QObject::tr("Warning"), QObject::tr("This tool can only be used by administrator.")); box.setStandardButtons(QMessageBox::Ok); box.setButtonText(QMessageBox::Ok, QObject::tr("OK")); @@ -125,7 +127,6 @@ void initApp(QApplication& a) QCoreApplication::setApplicationName(QObject::tr("kybackup")); QCoreApplication::setApplicationVersion("4.0.14"); - /* QCommandLineParser parser; parser.setApplicationDescription("kybackup helper"); parser.addHelpOption(); @@ -134,8 +135,7 @@ void initApp(QApplication& a) QCommandLineOption functionOption(QStringList() << "r" << "restore", QCoreApplication::translate("restore", "system restore")); parser.addOption(functionOption); parser.process(a); - bool isRestore = parser.isSet(functionOption); - */ + GlobelBackupInfo::inst().setHasArgRestore(parser.isSet(functionOption)); QString qsAppPath = QCoreApplication::applicationDirPath(); Utils::initSysRootPath(qsAppPath); diff --git a/kybackup/maindialog.cpp b/kybackup/maindialog.cpp index fef6c97..0273ba8 100755 --- a/kybackup/maindialog.cpp +++ b/kybackup/maindialog.cpp @@ -10,6 +10,7 @@ #include "../common/mydefine.h" #include "module/systembackup.h" #include "module/systemrestore.h" +#include "module/databackup.h" #include "backup_manager_interface.h" #include "globalbackupinfo.h" @@ -39,7 +40,10 @@ void MainDialog::initUI() m_totalHLayout->setContentsMargins(0, 0, 0, 0); ui->centralwidget->setLayout(m_totalHLayout); - m_leftSiderBarWidget = new LeftsiderbarWidget(ui->centralwidget); + if (GlobelBackupInfo::inst().isManager()) + m_leftSiderBarWidget = new LeftsiderbarWidget(ui->centralwidget); + else + m_leftSiderBarWidget = new LeftsiderbarWidget(ui->centralwidget, LeftsiderbarWidget::StartMode::std_user); m_leftSiderBarWidget->setObjectName(QString::fromUtf8("m_leftSiderBarWidget")); m_leftSiderBarWidget->setGeometry(QRect(0, 0, 200, 640)); m_leftSiderBarWidget->setFixedSize(QSize(200, 640)); @@ -55,7 +59,12 @@ void MainDialog::initUI() m_titleWidget->setGeometry(QRect(201, 0, 760, 40)); m_rightVLayout->addWidget(m_titleWidget); - selected(FuncTypeConverter::FunType::BACKUP_SYSTEM); + if (!GlobelBackupInfo::inst().isManager()) + selected(FuncTypeConverter::FunType::BACKUP_DATA); + else if (GlobelBackupInfo::inst().hasArgRestore()) + selected(FuncTypeConverter::FunType::RESTORE_SYSTEM); + else + selected(FuncTypeConverter::FunType::BACKUP_SYSTEM); m_totalHLayout->addLayout(m_rightVLayout); @@ -203,6 +212,10 @@ void MainDialog::selected(int func_type) m_stackedWidget = new SystemRestore(ui->centralwidget); GlobelBackupInfo::inst().setFuncType(FuncTypeConverter::FunType::RESTORE_SYSTEM); break; + case FuncTypeConverter::FunType::BACKUP_DATA: + m_stackedWidget = new DataBackup(ui->centralwidget); + GlobelBackupInfo::inst().setFuncType(FuncTypeConverter::FunType::BACKUP_DATA); + break; default: m_stackedWidget = new SystemBackup(ui->centralwidget); GlobelBackupInfo::inst().setFuncType(FuncTypeConverter::FunType::BACKUP_SYSTEM); diff --git a/kybackup/module/databackup.cpp b/kybackup/module/databackup.cpp new file mode 100644 index 0000000..a8db972 --- /dev/null +++ b/kybackup/module/databackup.cpp @@ -0,0 +1,1591 @@ +#include "databackup.h" + +#include +#include +#include +#include +#include +#include +#include + +#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 "managebackuppointlist.h" +#include "selectrestorepoint.h" +#include "messageboxutils.h" + +DataBackup::DataBackup(QWidget *parent /*= nullptr*/) : + QStackedWidget(parent), + m_udector(new UdiskDetector()), + m_isLocal(true), + m_DataBackupState(DataBackupState::IDEL), + m_pInterface(nullptr) +{ + // 界面手写代码创建,作为练手 + initFirstWidget(); + initSecondWidget(); + initSecondWidget_inc(); + initThirdWidget(); + initForthWidget(); + initFifthWidget(); + initLastWidget(); +} + +DataBackup::~DataBackup() +{ + delete m_udector; + m_udector = nullptr; + + delete m_pInterface; + m_pInterface = nullptr; +} + +/** + * @brief 初始化第一个页面 + */ +void DataBackup::initFirstWidget() +{ + QWidget *first = new QWidget; + + // 图片 + QLabel *imageBackup_firstPage = new QLabel(first); + imageBackup_firstPage->setGeometry(421, 120, 300, 326); + QPixmap pixmap(":/images/data_backup.svg"); + imageBackup_firstPage->setPixmap(pixmap); + imageBackup_firstPage->setScaledContents(true); + + // 系统备份大字提示 + MyLabel *labelBackup_firstPage = new MyLabel(first); + labelBackup_firstPage->setDeplayText(tr("Data Backup")); + labelBackup_firstPage->setFixedWidth(500); + labelBackup_firstPage->setFixedHeight(48); + labelBackup_firstPage->move(41, 120); + // 默认水平左对齐,上下居中对齐;故不需要设置 + // labelBackup_firstPage->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); + // labelBackup_firstPage->setText(tr("System Backup")); + QFont font; + font.setBold(true); + font.setPixelSize(36); + labelBackup_firstPage->setFont(font); + // labelBackup_firstPage->setAttribute(Qt::WA_TranslucentBackground); + labelBackup_firstPage->setScaledContents(true); + labelBackup_firstPage->adjustSize(); + + // 系统备份说明 + MyLabel *labelNote_firstPage = new MyLabel(first); + labelNote_firstPage->setFixedWidth(700); + labelNote_firstPage->setFixedHeight(24); + labelNote_firstPage->move(41, 180); + if (Utils::isHuawei990()) + labelNote_firstPage->setDeplayText(tr("Only files in the home, root, and data directories can be backed up")); + else + labelNote_firstPage->setDeplayText(tr("Only files in the home, root, and data/usershare directories can be backed up")); + font.setBold(false); + font.setPixelSize(18); + labelNote_firstPage->setFont(font); + 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 *iconSecurity_firstPage = new MyIconLabel(first); + iconSecurity_firstPage->setGeometry(206, 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 *iconDataLoss_firstPage = new MyIconLabel(first); + iconDataLoss_firstPage->setGeometry(41, 296, 180, 36); + iconDataLoss_firstPage->setThemeIcon("ukui-bf-dataloss-symbolic", ":/symbos/ukui-bf-dataloss-symbolic.png"); + iconDataLoss_firstPage->setDesplayText(tr("Protect Data")); + iconDataLoss_firstPage->setEnabled(false); + + // 方便快捷 + MyIconLabel *iconSimple_firstPage = new MyIconLabel(first); + iconSimple_firstPage->setGeometry(206, 296, 180, 36); + iconSimple_firstPage->setThemeIcon("ukui-bf-fast-symbolic", ":/symbos/ukui-bf-fast-symbolic.png"); + iconSimple_firstPage->setDesplayText(tr("Convenient")); + iconSimple_firstPage->setEnabled(false); + + // 开始备份按钮 + MyPushButton *beginBackup = new MyPushButton(first); + beginBackup->setGeometry(41, 372, 180, 52); + beginBackup->setText(tr("Start Backup")); + 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 = ""; + this->m_isIncrement = false; + this->setCurrentIndex(SELECT_PATH_PAGE); + emit this->reset(); + }); + + // 增量备份按钮 + MyPushButton *incrementBackup = new MyPushButton(first); + incrementBackup->setGeometry(241, 372, 180, 52); + incrementBackup->setText(tr("Update Backup")); + incrementBackup->setEnabled(true); + incrementBackup->setAutoRepeat(true); + font.setPixelSize(24); + incrementBackup->setFont(font); + connect(incrementBackup, &MyPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + this->m_uuid = ""; + this->m_prefixDestPath = ""; + this->m_backupName = ""; + this->m_backupPaths.clear(); + SelectRestorePoint * selectDialog = new SelectRestorePoint(this, SelectRestorePoint::DATA); + 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->m_isIncrement = true; + this->setCurrentIndex(INC_SELECT_PATH_PAGE); + emit this->initIncListWidget(); + } + selectDialog->deleteLater(); + }); + + // 底部控件布局 + QVBoxLayout *bottomVBoxLayout = new QVBoxLayout(first); + bottomVBoxLayout->addStretch(); + QHBoxLayout *bottomHBoxLayout = new QHBoxLayout(first); + bottomVBoxLayout->addLayout(bottomHBoxLayout); + bottomVBoxLayout->addSpacing(20); + bottomHBoxLayout->addStretch(); + // 备份管理 + ClickLabel * backupPointManage = new ClickLabel(tr("Backup Management >>"), first); + QPalette pal(backupPointManage->palette()); + pal.setColor(QPalette::WindowText, QColor(Qt::blue)); + backupPointManage->setPalette(pal); + backupPointManage->setToolTip(tr("Backup Management >>")); + + bottomHBoxLayout->addWidget(backupPointManage); + bottomHBoxLayout->addSpacing(20); + + connect(backupPointManage, &ClickLabel::clicked, this, [=]() { + ManageBackupPointList backupManager(first, ManageBackupPointList::DATA); + backupManager.exec(); + }); + + addWidget(first); +} + +/** + * @brief “上一步”按钮响应槽 + * @param checked + */ +void DataBackup::on_pre_clicked(bool checked) +{ + Q_UNUSED(checked) + int index = this->currentIndex() - 1; + if (index >= 0) { + this->setCurrentIndex(index); + } +} + +/** + * @brief “开始备份”“下一步”按钮响应槽 + * @param checked + */ +void DataBackup::on_next_clicked(bool checked) +{ + Q_UNUSED(checked) + int index = this->currentIndex() + 1; + if (index < this->count()) { + this->setCurrentIndex(index); + } +} + +/** + * @brief 初始化第二个页面(新建备份) + */ +void DataBackup::initSecondWidget() +{ + QWidget *second = new QWidget; + + // 纵向布局 + QVBoxLayout *vlayout = new QVBoxLayout; + vlayout->addSpacing(40); + + // 第一行 + QHBoxLayout * hlayoutLine1 = new QHBoxLayout; + hlayoutLine1->addSpacing(30); + // 备份路径选择提示(新建数据备份时显示) + MyLabel* labelPathSelect = new MyLabel(second); + labelPathSelect->setDeplayText(tr("Please select backup position")); + labelPathSelect->setFixedWidth(600); + labelPathSelect->setFixedHeight(27); + QFont font; + font.setBold(true); + font.setPixelSize(18); + labelPathSelect->setFont(font); + hlayoutLine1->addWidget(labelPathSelect); + hlayoutLine1->addStretch(); + vlayout->addLayout(hlayoutLine1); + + // 第二行 + vlayout->addSpacing(5); + QHBoxLayout * hlayoutLine2 = new QHBoxLayout; + hlayoutLine2->addSpacing(30); + // 备份路径选择框 + QComboBox* comboSelect = new QComboBox(second); + QPalette palette = comboSelect->palette(); + comboSelect->setFixedSize(680, 36); + // 添加本地默认路径、移动设备目录 + connect(m_udector, &UdiskDetector::udiskListChanged, this, [=](QList diskList) { + comboSelect->clear(); + QIcon iconFolder = QIcon::fromTheme("insync-folder.png", QIcon(":/images/folder.png")); + + // 如果有备份分区,则将本地默认分区备份路径放在第一个 + if (GlobelBackupInfo::inst().hasBackupPartition()) { + QString qsLocalDefaultPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_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() + BACKUP_SNAPSHOTS_PATH); + } + }); + m_udector->getStorageInfo(); + hlayoutLine2->addWidget(comboSelect); + hlayoutLine2->addStretch(); + vlayout->addLayout(hlayoutLine2); + vlayout->addSpacing(30); + + // 第三行 + QHBoxLayout * hlayoutLine3 = new QHBoxLayout; + hlayoutLine3->addSpacing(30); + // label:选择备份数据 + MyLabel* labelDataBackup = new MyLabel; + labelDataBackup->setDeplayText(tr("Select backup data")); + labelDataBackup->setFixedWidth(600); + labelDataBackup->setFixedHeight(27); + labelDataBackup->setFont(font); + hlayoutLine3->addWidget(labelDataBackup); + hlayoutLine3->addStretch(); + vlayout->addLayout(hlayoutLine3); + + // 第四行 + vlayout->addSpacing(5); + QHBoxLayout * hlayoutLine4 = new QHBoxLayout; + hlayoutLine4->addSpacing(30); + // 所选备份路径编辑框 + QLineEdit *editSelect = new QLineEdit; + editSelect->setFixedSize(480, 36); + editSelect->setMaxLength(255); + // 删除按钮 + QPushButton *buttonDelete = new QPushButton; + buttonDelete->setProperty("isWindowButton", 0x2); + buttonDelete->setProperty("useIconHighlightEffect", 0x8); + buttonDelete->setFlat(true); + buttonDelete->setIcon(QIcon::fromTheme("window-close-symbolic")); + connect(buttonDelete, &QPushButton::clicked, this, [=]() { + editSelect->setText(""); + }); + // 添加按钮 + MyPushButton *buttonAdd = new MyPushButton; + buttonAdd->setFixedSize(70, 36); + buttonAdd->setText(tr("Add")); + // 选择按钮 + MyPushButton *buttonSelect = new MyPushButton; + buttonSelect->setFixedSize(70, 36); + buttonSelect->setText(tr("Select")); + hlayoutLine4->addWidget(editSelect); + hlayoutLine4->addWidget(buttonDelete); + hlayoutLine4->addWidget(buttonAdd); + hlayoutLine4->addWidget(buttonSelect); + hlayoutLine4->addStretch(); + vlayout->addLayout(hlayoutLine4); + + // 第五行 + vlayout->addSpacing(15); + QHBoxLayout * hlayoutLine5 = new QHBoxLayout; + hlayoutLine5->addSpacing(30); + // 限制目录 + QStringList pathLimits; + QList siderUrls; + getPathsLimit(pathLimits, siderUrls); + + // 备份列表 + BackupListWidget *listWidget = new BackupListWidget; + listWidget->setFixedSize(680, 240); + listWidget->setPathLimit(pathLimits); + hlayoutLine5->addWidget(listWidget); + hlayoutLine5->addStretch(); + vlayout->addLayout(hlayoutLine5); + connect(buttonAdd, &QPushButton::clicked, this, [=]() { + if (editSelect->text().isEmpty()) + MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), + QObject::tr("Please select a backup file or directory"), + QObject::tr("Ok")); + else { + if (listWidget->appendItem(editSelect->text())) { + editSelect->setText(""); + } + } + }); + connect(buttonSelect, &MyPushButton::clicked, this, [=](){ + MyFileSelect *fileDialog = new MyFileSelect(this); + fileDialog->setWindowTitle(tr("Please select file to backup")); + fileDialog->setSidebarUrls(siderUrls); + + if (fileDialog->exec() == QDialog::Accepted) { + QStringList selectFiles = fileDialog->selectedFiles(); + if (!selectFiles.isEmpty()) { + QString fileName = selectFiles.at(0); + editSelect->setText(fileName); + } + } + + delete fileDialog; + }); + + // 最后一行 + vlayout->addSpacing(25); + QHBoxLayout * hlayoutLastLine = new QHBoxLayout; + hlayoutLastLine->addStretch(); + // 上一步按钮 + 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, [=]() { + this->setCurrentIndex(HOME_PAGE); + emit this->reset(); + }); + // 下一步按钮 + 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, [=]() { + // 备份路径选择索引 + int index = comboSelect->currentIndex(); + // 第一个选项是本地系统备份 + this->m_isLocal = GlobelBackupInfo::inst().hasBackupPartition() && (index == 0); + this->m_prefixDestPath = this->m_udiskPaths.at(index); + this->m_backupPaths.clear(); + this->m_backupPaths.append(listWidget->getBackupPaths()); + this->setCurrentIndex(CHECK_ENV_PAGE); + emit this->startCheckEnv(); + }); + hlayoutLastLine->addWidget(preStep); + hlayoutLastLine->addSpacing(20); + hlayoutLastLine->addWidget(nextStep); + hlayoutLastLine->addStretch(); + vlayout->addLayout(hlayoutLastLine); + + vlayout->addStretch(); + second->setLayout(vlayout); + + connect(this, &DataBackup::reset, this, [=]() { + editSelect->setText(""); + this->m_backupPaths.clear(); + listWidget->clearData(); + comboSelect->setCurrentIndex(0); + }); + + addWidget(second); +} + +/** + * @brief 文件选择框中左边栏展示用 + * @param pathLimits + * @param siderUrls + */ +void DataBackup::getPathsLimit(QStringList &pathLimits, QList &siderUrls) +{ + QString curPath = QDir::homePath(); //用户家目录 + pathLimits << curPath; + siderUrls << QUrl::fromLocalFile(curPath); + if (GlobelBackupInfo::inst().isManager()) { + QString root = Utils::getSysRootPath() + "/root"; + root.replace("//", "/"); + pathLimits << root; + siderUrls << QUrl::fromLocalFile(root); + if (Utils::isHuawei990()) { + QString data = Utils::getSysRootPath() + "/data"; + data.replace("//", "/"); + pathLimits << data; + siderUrls << QUrl::fromLocalFile(data); + } else { + QString data = Utils::getSysRootPath() + "/data/usershare"; + data.replace("//", "/"); + pathLimits << data; + siderUrls << QUrl::fromLocalFile(data); + } + } +} + +/** + * @brief 初始化第二个页面(增量备份) + */ +void DataBackup::initSecondWidget_inc() +{ + QWidget *second = new QWidget; + + // 纵向布局 + QVBoxLayout *vlayout = new QVBoxLayout; + vlayout->addSpacing(40); + + // 第一行 + QHBoxLayout * hlayoutLine1 = new QHBoxLayout; + hlayoutLine1->addSpacing(30); + // 默认备份位置 + MyLabel* labelPathSelect = new MyLabel(second); + labelPathSelect->setDeplayText(tr("Default backup location")); + labelPathSelect->setFixedWidth(600); + labelPathSelect->setFixedHeight(27); + QFont font; + font.setBold(true); + font.setPixelSize(18); + labelPathSelect->setFont(font); + hlayoutLine1->addWidget(labelPathSelect); + hlayoutLine1->addStretch(); + vlayout->addLayout(hlayoutLine1); + + // 第二行 + vlayout->addSpacing(5); + QHBoxLayout * hlayoutLine2 = new QHBoxLayout; + hlayoutLine2->addSpacing(30); + // 默认备份位置展示 + MyLabel* labelBackupPosition = new MyLabel(second); + labelBackupPosition->setFixedWidth(700); + if (m_isLocal) { + QString qsLocalDefaultPath = Utils::getSysRootPath() + BACKUP_SNAPSHOTS_PATH; + qsLocalDefaultPath.replace("//", "/"); + QString defaultPath = tr("local default path : ") + qsLocalDefaultPath; + labelBackupPosition->setDeplayText(defaultPath); + } else { + QString defaultPath = tr("removable devices path : ") + m_prefixDestPath; + labelBackupPosition->setDeplayText(defaultPath); + } + labelBackupPosition->setEnabled(false); + hlayoutLine2->addWidget(labelBackupPosition); + hlayoutLine2->addStretch(); + vlayout->addLayout(hlayoutLine2); + vlayout->addSpacing(30); + + // 第三行 + QHBoxLayout * hlayoutLine3 = new QHBoxLayout; + hlayoutLine3->addSpacing(30); + // label:选择备份数据 + MyLabel* labelDataBackup = new MyLabel; + labelDataBackup->setDeplayText(tr("Select backup data")); + labelDataBackup->setFixedWidth(600); + labelDataBackup->setFixedHeight(27); + labelDataBackup->setFont(font); + hlayoutLine3->addWidget(labelDataBackup); + hlayoutLine3->addStretch(); + vlayout->addLayout(hlayoutLine3); + + // 第四行 + vlayout->addSpacing(5); + QHBoxLayout * hlayoutLine4 = new QHBoxLayout; + hlayoutLine4->addSpacing(30); + // 所选备份路径编辑框 + QLineEdit *editSelect = new QLineEdit; + editSelect->setFixedSize(480, 36); + editSelect->setMaxLength(255); + // 删除按钮 + QPushButton *buttonDelete = new QPushButton; + buttonDelete->setProperty("isWindowButton", 0x2); + buttonDelete->setProperty("useIconHighlightEffect", 0x8); + buttonDelete->setFlat(true); + buttonDelete->setIcon(QIcon::fromTheme("window-close-symbolic")); + connect(buttonDelete, &QPushButton::clicked, this, [=]() { + editSelect->setText(""); + }); + // 添加按钮 + MyPushButton *buttonAdd = new MyPushButton; + buttonAdd->setFixedSize(70, 36); + buttonAdd->setText(tr("Add")); + // 选择按钮 + MyPushButton *buttonSelect = new MyPushButton; + buttonSelect->setFixedSize(70, 36); + buttonSelect->setText(tr("Select")); + hlayoutLine4->addWidget(editSelect); + hlayoutLine4->addWidget(buttonDelete); + hlayoutLine4->addWidget(buttonAdd); + hlayoutLine4->addWidget(buttonSelect); + hlayoutLine4->addStretch(); + vlayout->addLayout(hlayoutLine4); + + // 第五行 + vlayout->addSpacing(15); + QHBoxLayout * hlayoutLine5 = new QHBoxLayout; + hlayoutLine5->addSpacing(30); + // 限制目录 + QStringList pathLimits; + QList siderUrls; + getPathsLimit(pathLimits, siderUrls); + // 备份列表 + BackupListWidget *listWidget = new BackupListWidget; + listWidget->setFixedSize(680, 240); + listWidget->setPathLimit(pathLimits); + hlayoutLine5->addWidget(listWidget); + hlayoutLine5->addStretch(); + vlayout->addLayout(hlayoutLine5); + connect(buttonAdd, &QPushButton::clicked, this, [=]() { + if (editSelect->text().isEmpty()) + MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), + QObject::tr("Please select a backup file or directory"), + QObject::tr("Ok")); + else { + if (listWidget->appendItem(editSelect->text())) + editSelect->setText(""); + } + }); + connect(buttonSelect, &MyPushButton::clicked, this, [=](){ + QFileDialog *fileDialog = new QFileDialog(this); + fileDialog->setViewMode(QFileDialog::List); + fileDialog->setWindowTitle(tr("Please select file to backup")); + fileDialog->setSidebarUrls(siderUrls); + fileDialog->setFilter(QDir::System | QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); + + if (fileDialog->exec() == QDialog::Accepted) { + QStringList selectFiles = fileDialog->selectedFiles(); + if (!selectFiles.isEmpty()) { + QString fileName = selectFiles.at(0); + editSelect->setText(fileName); + } + } + + delete fileDialog; + }); + // 增量备份初始化备份路径列表 + connect(this, &DataBackup::initIncListWidget, this, [=]() { + emit this->reset(); + this->addOldBackupPaths(listWidget); + }); + + // 最后一行 + vlayout->addSpacing(25); + QHBoxLayout * hlayoutLastLine = new QHBoxLayout; + hlayoutLastLine->addStretch(); + // 上一步按钮 + 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, [=]() { + this->setCurrentIndex(HOME_PAGE); + emit this->reset(); + }); + // 下一步按钮 + 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, [=]() { + this->m_backupPaths.clear(); + this->m_backupPaths.append(listWidget->getBackupPaths()); + this->setCurrentIndex(CHECK_ENV_PAGE); + emit this->startCheckEnv(); + }); + hlayoutLastLine->addWidget(preStep); + hlayoutLastLine->addSpacing(20); + hlayoutLastLine->addWidget(nextStep); + hlayoutLastLine->addStretch(); + vlayout->addLayout(hlayoutLastLine); + + vlayout->addStretch(); + second->setLayout(vlayout); + + connect(this, &DataBackup::reset, this, [=]() { + editSelect->setText(""); + this->m_backupPaths.clear(); + listWidget->clearData(); + }); + + addWidget(second); +} + +/** + * @brief 将源备份点的备份路径列表添加到当前列表控件 + * @param listWidget + */ +void DataBackup::addOldBackupPaths(BackupListWidget *listWidget) +{ + QString pathUserFile = m_prefixDestPath + BACKUP_SNAPSHOTS_PATH + "/" + m_uuid + "/" + PATHS_USER_FILE; + QFile file(pathUserFile); + if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { + QTextStream in(&file); + while (!in.atEnd()) { + QString line = in.readLine(); + if (line.isEmpty()) + continue; + + listWidget->appendItem(line); + } + } +} + +/** + * @brief 初始化第三个页面 + */ +void DataBackup::initThirdWidget() +{ + QWidget *third = new QWidget; + + // 流程进度提示栏 + CircleLable *one = new CircleLable("1", third, 24, QColor(COLOR_BLUE)); + one->move(QPoint(81, 41)); + LineLabel *line1 = new LineLabel(third, QColor(COLOR_BLUE)); + line1->move(QPoint(108, 41)); + CircleLable *two = new CircleLable("2", third); + two->move(QPoint(261, 41)); + LineLabel *line2 = new LineLabel(third); + line2->move(QPoint(288, 41)); + CircleLable *three = new CircleLable("3", third); + three->move(QPoint(441, 41)); + LineLabel *line3 = new LineLabel(third); + line3->move(QPoint(468, 41)); + CircleLable *four = new CircleLable("4", third); + four->move(QPoint(621, 41)); + MyLabel *label1 = new MyLabel(tr("checking"), third); + label1->setFontColor(QColor(COLOR_BLUE)); + label1->setGeometry(11, 72, 164, 30); + MyLabel *label2 = new MyLabel(tr("preparing"), third); + label2->setGeometry(191, 72, 164, 30); + MyLabel *label3 = new MyLabel(tr("backuping"), third); + label3->setGeometry(371, 72, 164, 30); + MyLabel *label4 = new MyLabel(tr("finished"), third); + label4->setGeometry(551, 72, 164, 30); + + // ------------ 中部布局begin------------- + QVBoxLayout *vlayout = new QVBoxLayout(third); + vlayout->addSpacing(180); + QHBoxLayout *hlayout = new QHBoxLayout; + hlayout->addStretch(); + + 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(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, [=]() { + if (this->m_isIncrement) + this->setCurrentIndex(INC_SELECT_PATH_PAGE); + else + this->setCurrentIndex(SELECT_PATH_PAGE); + }); + 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->clearBackupName(); + }); + hlayoutCenterFont5->addWidget(nextStep); + // 重新检测按钮 + MyPushButton *recheck = new MyPushButton(centerFont); + recheck->setFixedSize(97, 36); + recheck->setText(tr("recheck")); + recheck->setEnabled(true); + recheck->setAutoRepeat(true); + connect(recheck, &MyPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + emit this->startCheckEnv(); + }); + hlayoutCenterFont5->addWidget(recheck); + hlayoutCenterFont5->addStretch(); + vlayoutCenterFont->addLayout(hlayoutCenterFont5); + + + centerFont->setLayout(vlayoutCenterFont); + hlayout->addWidget(centerFont); + hlayout->addStretch(); + vlayout->addLayout(hlayout); + vlayout->addStretch(); + third->setLayout(vlayout); + // ------------ 中部布局end------------- + + // 开始检测 + connect(this, &DataBackup::startCheckEnv, this, [=]() { + this->m_DataBackupState = DataBackupState::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("Do not perform other operations during backup to avoid data loss")); + if (this->m_isLocal) { + // 检测备份分区空间是否充足··· + labelCheck2->setDeplayText(tr("Check whether the remaining capacity of the backup partition is sufficient")); + } else { + // 检测移动设备空间是否充足··· + labelCheck2->setDeplayText(tr("Check whether the remaining capacity of the removable device is sufficient")); + } + preStep->setVisible(false); + nextStep->setVisible(false); + recheck->setVisible(false); + + this->on_checkEnv_start(); + }); + + // 检测结果 + connect(this, &DataBackup::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 storage for backup 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("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); + }); + + addWidget(third); +} + +/** + * @brief 开始进行环境检测 + */ +void DataBackup::on_checkEnv_start() +{ + GlobelBackupInfo::inst().setIsBusy(true); + m_pInterface = new ComKylinBackupManagerInterface("com.kylin.backup", "/", QDBusConnection::systemBus(), this); + connect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataBackup::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 = m_isIncrement ? BackupType::INC_BACKUP_DATA : BackupType::BACKUP_DATA; + backupWrapper.m_iPosition = m_isLocal ? BackupPosition::LOCAL : BackupPosition::UDISK; + backupWrapper.m_backupPaths << m_backupPaths; + backupWrapper.m_prefixDestPath = m_prefixDestPath; + backupWrapper.m_frontUid = getuid(); + backupWrapper.m_gid = getgid(); + m_pInterface->checkEnv(backupWrapper); +} + +/** + * @brief 环境检测结束 + * @param result, 环境校验结果 + */ +void DataBackup::on_checkEnv_end(int result) +{ + m_DataBackupState = DataBackupState::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 backup is not enough"); + // 建议释放空间后重试 + 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; + default: + bRst = true; + break; + } + + emit checkEnvResult(bRst, errMsg, errTip); + GlobelBackupInfo::inst().setIsBusy(false); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataBackup::on_checkEnv_end); + delete m_pInterface; + m_pInterface = nullptr; +} + +/** + * @brief 初始化第四个页面 + */ +void DataBackup::initForthWidget() +{ + QWidget *forth = new QWidget; + + // 流程进度提示栏 + CircleLable *one = new CircleLable("1", forth, 24, QColor(COLOR_BLUE)); + one->move(QPoint(81, 41)); + LineLabel *line1 = new LineLabel(forth, QColor(COLOR_BLUE)); + line1->move(QPoint(108, 41)); + CircleLable *two = new CircleLable("2", forth, 24, QColor(COLOR_BLUE)); + two->move(QPoint(261, 41)); + LineLabel *line2 = new LineLabel(forth, QColor(COLOR_BLUE)); + line2->move(QPoint(288, 41)); + CircleLable *three = new CircleLable("3", forth); + three->move(QPoint(441, 41)); + LineLabel *line3 = new LineLabel(forth); + line3->move(QPoint(468, 41)); + CircleLable *four = new CircleLable("4", forth); + four->move(QPoint(621, 41)); + MyLabel *label1 = new MyLabel(tr("checking"), forth); + label1->setFontColor(QColor(COLOR_BLUE)); + label1->setGeometry(11, 72, 164, 30); + MyLabel *label2 = new MyLabel(tr("preparing"), forth); + label2->setFontColor(QColor(COLOR_BLUE)); + label2->setGeometry(191, 72, 164, 30); + MyLabel *label3 = new MyLabel(tr("backuping"), forth); + label3->setGeometry(371, 72, 164, 30); + MyLabel *label4 = new MyLabel(tr("finished"), forth); + label4->setGeometry(551, 72, 164, 30); + + // 备份名称 + MyLabel *labelBackupName = new MyLabel(forth); + labelBackupName->setGeometry(81, 178, 150, 30); + labelBackupName->setAlignment(Qt::AlignRight); + labelBackupName->setDeplayText(tr("Backup Name")); + MyLineEdit *editBackupName = new MyLineEdit(forth); + editBackupName->setGeometry(238, 172, 350, 40); + editBackupName->setMaxLength(100); + if (m_backupName.isEmpty()) + editBackupName->setPlaceholderText(QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss")); + else { + editBackupName->setText(m_backupName); + } + // 支持输入中英文数字和部分字符 + QRegExp regx("^[\u4e00-\u9fa5a-zA-Z0-9~!@#$%^&*()-_+={}':;'\\[\\].<>/? ¥()——;《》‘’:“”、?]+$"); //其中匹配中文[\u4e00-\u9fa5] + QValidator *validator = new QRegExpValidator(regx); + editBackupName->setValidator(validator); + // 备份名称错误提示 + MyLabel *labelError = new MyLabel(forth); + labelError->setGeometry(238, 215, 500, 30); + labelError->setFontSize(14); + labelError->setFontColor(Qt::red); + labelError->setVisible(false); + connect(editBackupName, &MyLineEdit::textChanged, this, [=](const QString &text) { + if (!text.isEmpty() && text != this->m_backupName && this->isExistsBackupName(text)) { + labelError->setDeplayText(tr("Name already exists")); + labelError->setVisible(true); + } else { + labelError->setDeplayText(""); + labelError->setVisible(false); + } + }); + connect(this, &DataBackup::clearBackupName, this, [=]() { + editBackupName->setText(""); + if (this->m_backupName.isEmpty()) + editBackupName->setPlaceholderText(QDateTime::currentDateTime().toString("yy-MM-dd hh:mm:ss")); + else + editBackupName->setText(this->m_backupName); + editBackupName->setFocus(); + labelError->setDeplayText(""); + labelError->setVisible(false); + }); + + // 上一步按钮 + MyPushButton *preStep = new MyPushButton(forth); + preStep->setGeometry(271, 268, 97, 36); + preStep->setText(tr("back")); + preStep->setEnabled(true); + preStep->setAutoRepeat(true); + connect(preStep, &MyPushButton::clicked, this, &DataBackup::on_pre_clicked); + + // 下一步按钮 + MyPushButton *nextStep = new MyPushButton(forth); + nextStep->setGeometry(389, 268, 97, 36); + nextStep->setText(tr("next")); + nextStep->setEnabled(true); + nextStep->setAutoRepeat(true); + connect(nextStep, &MyPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + if (labelError->isVisible()) { + editBackupName->setFocus(); + } else { + QString backupName = editBackupName->text(); + if (backupName.isEmpty()) { + backupName = editBackupName->placeholderText(); + } + + if (this->m_backupName != backupName && this->isExistsBackupName(backupName)) { + labelError->setDeplayText(tr("Name already exists")); + labelError->setVisible(true); + editBackupName->setFocus(); + } else { + this->m_backupName = backupName; + this->on_next_clicked(checked); + emit this->startBackup(); + } + } + }); + + addWidget(forth); +} + +/** + * @brief 获取本地和移动设备中的备份点 + * @return + */ +QList DataBackup::getBackupPointList() +{ + QList list; + for (QString backupPath : m_udiskPaths) { + if (backupPath.isEmpty()) + backupPath = Utils::getSysRootPath(); + backupPath += BACKUP_XML_PATH; + + QFile xmlFile(backupPath); + if (!xmlFile.exists() || 0 == xmlFile.size()) { + continue; + } + + ParseBackupList parse(backupPath); + list.append(parse.getBackupPointList()); + } + + return list; +} + +/** + * @brief DataBackup::isExistsBackupName + * @param backupName + * @return bool true-已存在;false-不存在 + */ +bool DataBackup::isExistsBackupName(const QString & backupName) +{ + // 首先,校验唯一性文件中 + QString settingPath = Utils::getSysRootPath() + UDISK_UNIQUE_SETTINGS; + settingPath.replace("//", "/"); + QSettings udisk_setting(settingPath, QSettings::IniFormat); + udisk_setting.setIniCodec(QTextCodec::codecForName("utf-8")); + udisk_setting.beginGroup(backupName); + QString uuidFound = udisk_setting.value("uuid").toString(); + udisk_setting.endGroup(); + if (!uuidFound.isEmpty()) + return true; + + // 然后,校验xml和log中的备份记录(这一步只是为了保险而兼容老版本的备份,以前的唯一性文件中只有U盘的备份) + QList backupPointList = getBackupPointList(); + QList list = Utils::getBackupLogList(); + QSet setName; + for (BackupWrapper& wraper : list) { + if (wraper.m_backupName == wraper.m_uuid) { + // 如果在xml中不存在,则说明是此备份点是之前存在的备份点,现在已经删除 + for (const ParseBackupList::BackupPoint & backupPonit : backupPointList) { + if (backupPonit.m_uuid == wraper.m_uuid) { + wraper.m_backupName = backupPonit.m_backupName; + } + } + } + + // type==8为删除备份点操作 + if (BackupType::DELETE_BACKUP == wraper.m_type) + setName.remove(wraper.m_backupName); + else + setName.insert(wraper.m_backupName); + } + + return setName.contains(backupName); +} + +/** + * @brief 第五个页面 + */ +void DataBackup::initFifthWidget() +{ + QWidget *fifth = new QWidget; + + // 流程进度提示栏 + CircleLable *one = new CircleLable("1", fifth, 24, QColor(COLOR_BLUE)); + one->move(QPoint(81, 41)); + LineLabel *line1 = new LineLabel(fifth, QColor(COLOR_BLUE)); + line1->move(QPoint(108, 41)); + CircleLable *two = new CircleLable("2", fifth, 24, QColor(COLOR_BLUE)); + two->move(QPoint(261, 41)); + LineLabel *line2 = new LineLabel(fifth, QColor(COLOR_BLUE)); + line2->move(QPoint(288, 41)); + CircleLable *three = new CircleLable("3", fifth, 24, QColor(COLOR_BLUE)); + three->move(QPoint(441, 41)); + LineLabel *line3 = new LineLabel(fifth, QColor(COLOR_BLUE)); + line3->move(QPoint(468, 41)); + CircleLable *four = new CircleLable("4", fifth); + four->move(QPoint(621, 41)); + MyLabel *label1 = new MyLabel(tr("checking"), fifth); + label1->setFontColor(QColor(COLOR_BLUE)); + label1->setGeometry(11, 72, 164, 30); + MyLabel *label2 = new MyLabel(tr("preparing"), fifth); + label2->setFontColor(QColor(COLOR_BLUE)); + label2->setGeometry(191, 72, 164, 30); + MyLabel *label3 = new MyLabel(tr("backuping"), fifth); + label3->setFontColor(QColor(COLOR_BLUE)); + label3->setGeometry(371, 72, 164, 30); + MyLabel *label4 = new MyLabel(tr("finished"), fifth); + label4->setGeometry(551, 72, 164, 30); + + // ------------ 中部布局begin------------- + QVBoxLayout *vlayout = new QVBoxLayout; + vlayout->addSpacing(180); + QHBoxLayout *hlayout = new QHBoxLayout; + hlayout->addStretch(); + + QWidget *centerFont = new QWidget(fifth); + 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->addStretch(); + + // 第二行 + QHBoxLayout *hlayoutCenterFont2 = new QHBoxLayout; + // 提醒 + MyLabel *labelTip = new MyLabel(centerFont); + labelTip->setAlignment(Qt::AlignCenter); + labelTip->setIsOriginal(true); + labelTip->setFontWordWrap(true); + labelTip->setMinimumWidth(700); + // 不要使用电脑,以防数据丢失 + labelTip->setDeplayText(tr("Do not use computers in case of data loss")); + hlayoutCenterFont2->addStretch(); + hlayoutCenterFont2->addWidget(labelTip); + hlayoutCenterFont2->addStretch(); + + // 第三行 + QHBoxLayout *hlayoutCenterFont3 = new QHBoxLayout; + // 取消按钮 + MyPushButton *cancel = new MyPushButton(fifth); + 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->addSpacing(40); + vlayoutCenterFont->addLayout(hlayoutCenterFont3); + vlayoutCenterFont->addStretch(); + centerFont->setLayout(vlayoutCenterFont); + + centerFont->setLayout(vlayoutCenterFont); + hlayout->addWidget(centerFont); + hlayout->addStretch(); + vlayout->addLayout(hlayout); + vlayout->addStretch(); + fifth->setLayout(vlayout); + + // ------------ 中部布局end------------- + + connect(this, &DataBackup::backupWarnning, labelTip, [=](const QString& msg) { + labelTip->setDeplayText(msg); + }); + + // 开始备份 + connect(this, &DataBackup::startBackup, this, [=] { + progressBar->setPersent(0); + movie->start(); + + // 开始备份 + this->on_backup_start(); + }); + + // 进度 + connect(this, &DataBackup::progress, this, [=](int state, int rate) { + Q_UNUSED(state) + progressBar->setPersent(rate); + }); + + // 取消备份 + connect(cancel, &MyPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + // TODO + }); + + addWidget(fifth); +} + +/** + * @brief 开始进行系统备份 + */ +void DataBackup::on_backup_start() +{ + GlobelBackupInfo::inst().setIsBusy(true); + m_DataBackupState = DataBackupState::BACKUPING; + m_pInterface = new ComKylinBackupManagerInterface("com.kylin.backup", "/", QDBusConnection::systemBus(), this); + connect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataBackup::on_checkBackup_end); + connect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &DataBackup::progress); + connect(m_pInterface, &ComKylinBackupManagerInterface::backupFinished, this, &DataBackup::on_backup_end); + + // 是否已存在备份、还原等操作 + bool isActive = false; + if(int(BackupState::BACKUP_STATE_INIT) != m_pInterface->getBackupState(isActive)){ + on_checkBackup_end(int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING)); + + return; + } + + BackupWrapper backupWrapper; + backupWrapper.m_backupName = m_backupName; + backupWrapper.m_uuid = m_uuid; + backupWrapper.m_type = m_isIncrement ? BackupType::INC_BACKUP_DATA : BackupType::BACKUP_DATA; + backupWrapper.m_iPosition = m_isLocal ? BackupPosition::LOCAL : BackupPosition::UDISK; + backupWrapper.m_backupPaths << m_backupPaths; + backupWrapper.m_prefixDestPath = m_prefixDestPath; + backupWrapper.m_frontUid = getuid(); + backupWrapper.m_gid = getgid(); + m_pInterface->goBackup(backupWrapper); +} + +/** + * @brief 系统备份校验结果处理 + * @param result + */ +void DataBackup::on_checkBackup_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::BACKUP_CAPACITY_IS_NOT_ENOUGH): + // 备份空间不足 + errMsg = tr("The storage for backup is not enough."); + // 建议释放空间后重试 + 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::WRITE_BACKUP_PATHS_TO_USER_FAILED): + case int(BackupResult::WRITE_STORAGEINFO_ADD_ITEM_FAIL): + case int(BackupResult::WRITE_STORAGEINFO_UPDATE_ITEM_FAIL): + // 创建备份点目录失败 + errMsg = tr("Failed to create the backup point directory."); + // 请检查备份目录是否有写权限 + errTip = tr("Please check backup partition permissions"); + break; + default: + bRst = true; + break; + } + + if (!bRst) { + GlobelBackupInfo::inst().setIsBusy(false); + m_DataBackupState = DataBackupState::IDEL; + this->on_next_clicked(true); + emit this->checkBackupResult(bRst, errMsg, errTip); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataBackup::on_checkEnv_end); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &DataBackup::progress); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::backupFinished, this, &DataBackup::on_backup_end); + delete m_pInterface; + m_pInterface = nullptr; + } +} + +/** + * @brief 系统备份结束 + * @param result-false 失败; true 成功 + */ +void DataBackup::on_backup_end(bool result) +{ + m_DataBackupState = DataBackupState::IDEL; + + this->on_next_clicked(true); + if (result) { + emit checkBackupResult(result); + } else { + // 备份过程中出现错误 + QString errMsg = tr("An error occurred during backup"); + // 错误信息参考日志文件:/var/log/backup.log + QString errTip = tr("Error messages refer to log file : /var/log/backup.log"); + emit checkBackupResult(result, errMsg, errTip); + } + + GlobelBackupInfo::inst().setIsBusy(false); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::sendEnvCheckResult, this, &DataBackup::on_checkEnv_end); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::progress, this, &DataBackup::progress); + disconnect(m_pInterface, &ComKylinBackupManagerInterface::backupFinished, this, &DataBackup::on_backup_end); + delete m_pInterface; + m_pInterface = nullptr; +} + +/** + * @brief 最后备份结果界面 + */ +void DataBackup::initLastWidget() +{ + QWidget *last = new QWidget; + + // 流程进度提示栏 + CircleLable *one = new CircleLable("1", last, 24, QColor(COLOR_BLUE)); + one->move(QPoint(81, 41)); + LineLabel *line1 = new LineLabel(last, QColor(COLOR_BLUE)); + line1->move(QPoint(108, 41)); + CircleLable *two = new CircleLable("2", last, 24, QColor(COLOR_BLUE)); + two->move(QPoint(261, 41)); + LineLabel *line2 = new LineLabel(last, QColor(COLOR_BLUE)); + line2->move(QPoint(288, 41)); + CircleLable *three = new CircleLable("3", last, 24, QColor(COLOR_BLUE)); + three->move(QPoint(441, 41)); + LineLabel *line3 = new LineLabel(last, QColor(COLOR_BLUE)); + line3->move(QPoint(468, 41)); + CircleLable *four = new CircleLable("4", last, 24, QColor(COLOR_BLUE)); + four->move(QPoint(621, 41)); + MyLabel *label1 = new MyLabel(tr("checking"), last); + label1->setFontColor(QColor(COLOR_BLUE)); + label1->setGeometry(11, 72, 164, 30); + MyLabel *label2 = new MyLabel(tr("preparing"), last); + label2->setFontColor(QColor(COLOR_BLUE)); + label2->setGeometry(191, 72, 164, 30); + MyLabel *label3 = new MyLabel(tr("backuping"), last); + label3->setFontColor(QColor(COLOR_BLUE)); + label3->setGeometry(371, 72, 164, 30); + MyLabel *label4 = new MyLabel(tr("finished"), last); + label4->setFontColor(QColor(COLOR_BLUE)); + label4->setGeometry(551, 72, 164, 30); + + //------------ 中部布局begin------------- + QVBoxLayout *vlayout = new QVBoxLayout(last); + vlayout->addSpacing(180); + QHBoxLayout *hlayout = new QHBoxLayout; + hlayout->addStretch(); + + 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->addStretch(); + // 再试一次 + MyPushButton *retry = new MyPushButton(centerFont); + retry->setFixedSize(97, 36); + retry->setText(tr("retry")); + retry->setEnabled(true); + retry->setAutoRepeat(true); + hlayoutCenterFont5->addWidget(retry); + hlayoutCenterFont5->addSpacing(20); + // 返回首页 + MyPushButton *homePage = new MyPushButton(last); + homePage->setFixedSize(97, 36); + homePage->setText(tr("home page")); + homePage->setEnabled(true); + homePage->setAutoRepeat(true); + hlayoutCenterFont5->addWidget(homePage); + hlayoutCenterFont5->addStretch(); + vlayoutCenterFont->addLayout(hlayoutCenterFont5); + + centerFont->setLayout(vlayoutCenterFont); + hlayout->addWidget(centerFont); + hlayout->addStretch(); + vlayout->addLayout(hlayout); + vlayout->addStretch(); + last->setLayout(vlayout); + //------------ 中部布局end------------- + + // 备份检测结果 + connect(this, &DataBackup::checkBackupResult, 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("The backup is successful")); + + dot1->setVisible(false); + dot2->setVisible(false); + labelError1->setVisible(false); + 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("The backup is failed")); + dot1->setVisible(true); + dot2->setVisible(true); + labelError1->setDeplayText(errMsg); + labelError2->setDeplayText(errTip); + retry->setVisible(true); + + homePage->setVisible(false); + } + }); + + // 再试一次 + connect(retry, &MyPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + this->setCurrentIndex(DataBackupPage::NAME_BACKUP_PAGE); + }); + + // 返回首页 + connect(homePage, &MyPushButton::clicked, this, [=](bool checked) { + Q_UNUSED(checked) + this->setCurrentIndex(DataBackupPage::HOME_PAGE); + }); + + addWidget(last); +} + diff --git a/kybackup/module/databackup.h b/kybackup/module/databackup.h new file mode 100644 index 0000000..fa0bb7f --- /dev/null +++ b/kybackup/module/databackup.h @@ -0,0 +1,94 @@ +#ifndef DATABACKUP_H +#define DATABACKUP_H + +#include +#include "udiskdetector.h" +#include "../backup_manager_interface.h" +#include "../backup-daemon/parsebackuplist.h" +#include "../component/backuplistwidget.h" + +class DataBackup : public QStackedWidget +{ + Q_OBJECT +public: + enum DataBackupState + { + IDEL = 0, // 空闲 + CHECKING, // 环境校验中 + BACKUPING // 备份中 + }; + + enum DataBackupPage + { + HOME_PAGE, // 首页 + SELECT_PATH_PAGE, // 选择备份路径页 + INC_SELECT_PATH_PAGE, // 增量备份选择路径页 + CHECK_ENV_PAGE, // 环境检测页 + NAME_BACKUP_PAGE, // 备份命名页 + BACKUP_PAGE, // 备份中页 + LAST_PAGE, // 结束页 + }; +public: + explicit DataBackup(QWidget *parent = nullptr); + ~DataBackup(); + +private: + void initFirstWidget(); + void initSecondWidget(); + void initSecondWidget_inc(); + void initThirdWidget(); + void initForthWidget(); + void initFifthWidget(); + void initLastWidget(); + + QList getBackupPointList(); + bool isExistsBackupName(const QString & backupName); + +signals: + void reset(); + void initIncListWidget(); + + void startCheckEnv(); + void checkEnvResult(bool result, const QString &errMsg = "", const QString &errTip = ""); + void backupWarnning(const QString &warnning); + void checkBackupResult(bool result, const QString &errMsg = "", const QString &errTip = ""); + void startBackup(); + void progress(int state, int rate); + void clearBackupName(); + +public slots: + void on_pre_clicked(bool checked = false); + void on_next_clicked(bool checked = false); + void on_checkEnv_start(); + void on_checkEnv_end(int result); + void on_backup_start(); + void on_checkBackup_end(int result); + void on_backup_end(bool result); + +private: + void getPathsLimit(QStringList &pathLimits, QList &siderUrls); + void addOldBackupPaths(BackupListWidget *listWidget); + + // 是否增量备份 + bool m_isIncrement; + // U盘探测 + UdiskDetector* m_udector; + // U盘挂载路径列表 + QStringList m_udiskPaths; + // 是否本地备份 + bool m_isLocal; + // 备份路径列表 + QStringList m_backupPaths; + // 数据备份状态 + int m_DataBackupState; + // 增量备份选择的备份点uuid + QString m_uuid; + // 选中的备份目标路径前缀(暂指udisk挂载路径) + QString m_prefixDestPath; + // dbus接口 + ComKylinBackupManagerInterface *m_pInterface; + // 备份点名称 + QString m_backupName; +}; + +#endif // DATABACKUP_H diff --git a/kybackup/module/managebackuppointlist.cpp b/kybackup/module/managebackuppointlist.cpp index 5d552eb..220402d 100644 --- a/kybackup/module/managebackuppointlist.cpp +++ b/kybackup/module/managebackuppointlist.cpp @@ -120,8 +120,8 @@ void ManageBackupPointList::insertLines(const QListsetText(tr("Ok")); + this->setResult(QDialog::Rejected); m_bottomLayout->addStretch(); m_bottomLayout->addWidget(buttonRefresh); @@ -40,6 +41,7 @@ SelectRestorePoint::SelectRestorePoint(QWidget *parent, BackupPointType backupTy QList selectList = this->m_tableWidget->selectedItems(); if (selectList.isEmpty()) { MessageBoxUtils::QMESSAGE_BOX_WARNING(this, QObject::tr("Warning"), QObject::tr("Please select one backup to continue."), QObject::tr("Ok")); + this->reject(); return; } @@ -55,8 +57,8 @@ SelectRestorePoint::SelectRestorePoint(QWidget *parent, BackupPointType backupTy if (dev.startsWith(tr("Udisk Device:"))) backupPoint.m_iPosition = BackupPosition::OTHER; - emit selected(backupPoint); - this->close(); + emit this->selected(backupPoint); + this->accept(); } }); } @@ -134,8 +136,8 @@ void SelectRestorePoint::insertLines(const QList & QString prefixPath_to_device; if (backupPoint.m_path.startsWith(preDevPath)) { - QStringList ql = backupPoint.m_path.split("/"); - QString udiskName = ql.last(); + QStorageInfo storage(backupPoint.m_path); + QString udiskName = storage.displayName(); if (isOther) prefixPath_to_device = QObject::tr("Other machine:") + " " + udiskName; else diff --git a/kybackup/module/systembackup.cpp b/kybackup/module/systembackup.cpp index 7af65c3..88bf87b 100755 --- a/kybackup/module/systembackup.cpp +++ b/kybackup/module/systembackup.cpp @@ -724,6 +724,10 @@ bool SystemBackup::isExistsBackupName(const QString & backupName) if (!uuidFound.isEmpty()) return true; + // 不能取名为出厂备份 + if (backupName == tr("factory backup")) + return true; + // 然后,校验xml和log中的备份记录(这一步只是为了保险而兼容老版本的备份,以前的唯一性文件中只有U盘的备份) QList backupPointList = getBackupPointList(); QList list = Utils::getBackupLogList(); @@ -820,6 +824,18 @@ void SystemBackup::initFifthWidget() 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; @@ -835,6 +851,7 @@ void SystemBackup::initFifthWidget() vlayoutCenterFont->addLayout(hlayoutCenterFont1); vlayoutCenterFont->addLayout(hlayoutCenterFont2); + vlayoutCenterFont->addLayout(hlayoutCenterFont2_1); vlayoutCenterFont->addSpacing(40); vlayoutCenterFont->addLayout(hlayoutCenterFont3); vlayoutCenterFont->addStretch(); @@ -849,14 +866,17 @@ void SystemBackup::initFifthWidget() // ------------ 中部布局end------------- - connect(this, &SystemBackup::backupWarnning, labelTip, [=](const QString& msg) { - labelTip->setDeplayText(msg); + connect(this, &SystemBackup::backupWarnning, labelTip_1, [=](const QString& msg) { + labelTip_1->setVisible(true); + labelTip_1->setDeplayText(msg); }); // 开始备份 connect(this, &SystemBackup::startBackup, this, [=] { progressBar->setPersent(0); movie->start(); + labelTip_1->setVisible(false); + labelTip_1->setDeplayText(""); // 开始备份 this->on_backup_start(); @@ -892,7 +912,7 @@ void SystemBackup::on_backup_start() // 是否已存在备份、还原等操作 bool isActive = false; if(int(BackupState::BACKUP_STATE_INIT) != m_pInterface->getBackupState(isActive)){ - on_checkEnv_end(int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING)); + on_checkBackup_end(int(BackupResult::OTHER_BACKUP_OR_RESTORE_RUNNING)); return; } diff --git a/kybackup/module/systemrestore.cpp b/kybackup/module/systemrestore.cpp index dbb1267..de46285 100755 --- a/kybackup/module/systemrestore.cpp +++ b/kybackup/module/systemrestore.cpp @@ -129,8 +129,8 @@ void SystemRestore::initFirstWidget() bottomHBoxLayout->addStretch(); // 恢复出厂复选框 MyCheckBox * checkFactoryRestore = new MyCheckBox(tr("Factory Restore"), first); -// if (!Utils::isHuawei990()) -// checkFactoryRestore->setVisible(false); + if (!Utils::isHuawei990()) + checkFactoryRestore->setVisible(false); // 保留用户数据复选框 MyCheckBox * retainUserData = new MyCheckBox(tr("Retaining User Data"), first); bottomHBoxLayout->addWidget(checkFactoryRestore); @@ -188,6 +188,10 @@ void SystemRestore::on_button_beginRestore_clicked(bool checked) { Q_UNUSED(checked) + this->m_uuid = ""; + this->m_devPath = ""; + this->m_isOtherMachine = ""; + // 出厂还原,不用去选择备份点 if (m_isFactoryRestore) { // 出厂还原后,用户数据将会丢失 @@ -209,7 +213,11 @@ void SystemRestore::on_button_beginRestore_clicked(bool checked) this->m_devPath = backupPoint.m_path; this->m_isOtherMachine = backupPoint.m_iPosition == BackupPosition::OTHER ? true : false; }); - selectRestoreDialog->exec(); + + if (QDialog::Rejected == selectRestoreDialog->exec()) { + selectRestoreDialog->deleteLater(); + return ; + } selectRestoreDialog->deleteLater(); }