From 7d88329263f575af28524c52f371fff694e30a94 Mon Sep 17 00:00:00 2001 From: ZhangTingan Date: Tue, 14 Apr 2026 10:56:36 +0800 Subject: [PATCH 1/3] fix: Delay archive loading in Wayland to fix dialog positioning Delay first archive loading by 200ms in Wayland to allow window positioning to complete before showing password dialogs. Prevents dialogs from appearing at (0,0) when opening encrypted archives. Log: fix bug Bug: https://pms.uniontech.com/bug-view-355681.html --- src/source/mainwindow.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/source/mainwindow.cpp b/src/source/mainwindow.cpp index f936edbd..90b581aa 100644 --- a/src/source/mainwindow.cpp +++ b/src/source/mainwindow.cpp @@ -2606,7 +2606,16 @@ bool MainWindow::handleArguments_Open(const QStringList &listParam) qInfo() << "打开文件"; m_eStartupType = StartupType::ST_Normal; // 加载单个压缩包数据 - loadArchive(listParam[0]); + static bool firstLoad = true; + if (UiTools::isWayland() && firstLoad) { + firstLoad = false; + auto path = listParam[0]; + QTimer::singleShot(200, [this, &path]() { + loadArchive(path); + }); + } else { + loadArchive(listParam[0]); + } return true; } From c532d6dd868b7875f0e7c5841f14a3e09e2e8edf Mon Sep 17 00:00:00 2001 From: ZhangTingan Date: Tue, 14 Apr 2026 17:41:32 +0800 Subject: [PATCH 2/3] Revert "fix(archive): tar.7z use QProcess pipeline instead of shell script" This reverts commit 431082247439b3dcc49bfa84f97cd051aff9a76e. --- 3rdparty/cli7zplugin/cli7zplugin.cpp | 3 - .../archiveinterface/cliinterface.cpp | 147 ++++++------------ .../interface/archiveinterface/cliinterface.h | 9 +- .../archiveinterface/cliproperties.cpp | 137 ++++++++-------- .../archiveinterface/cliproperties.h | 6 - 5 files changed, 120 insertions(+), 182 deletions(-) diff --git a/3rdparty/cli7zplugin/cli7zplugin.cpp b/3rdparty/cli7zplugin/cli7zplugin.cpp index 648eca80..0a7b8ee5 100644 --- a/3rdparty/cli7zplugin/cli7zplugin.cpp +++ b/3rdparty/cli7zplugin/cli7zplugin.cpp @@ -151,9 +151,6 @@ bool Cli7zPlugin::isOpenFileFailed(const QString &line) void Cli7zPlugin::killProcess(bool emitFinished) { Q_UNUSED(emitFinished); - if (killTar7zPipelineIfActive()) { - return; - } if (!m_process) { return; } diff --git a/3rdparty/interface/archiveinterface/cliinterface.cpp b/3rdparty/interface/archiveinterface/cliinterface.cpp index 214847c6..d5f40a16 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.cpp +++ b/3rdparty/interface/archiveinterface/cliinterface.cpp @@ -470,47 +470,23 @@ PluginFinishType CliInterface::addFiles(const QList &files, const Com QFileInfo(m_strArchiveName).path(), sRenameList); - if (options.bTar_7z) { // 压缩tar.7z:用两个 QProcess 管道,避免 shell 拼接与密码特殊字符问题 + if (options.bTar_7z) { // 压缩tar.7z文件 m_isTar7z = true; - m_filesSize = options.qTotalSize; - const QString archivePath = temp_archiveName.isEmpty() ? m_strArchiveName : temp_archiveName; - QStringList tarArgs = m_cliProps->getTar7zTarArgs(fileList, sRenameList); - QStringList sevenZArgs = m_cliProps->getTar7z7zArgs(archivePath, password, options.bHeaderEncryption, - options.iCompressionLevel, options.strCompressionMethod, - options.strEncryptionMethod, options.iVolumeSize); - QString tarPath = QStandardPaths::findExecutable(QStringLiteral("tar")); - QString sevenZPath = QStandardPaths::findExecutable(m_cliProps->property("addProgram").toString()); - if (tarPath.isEmpty() || sevenZPath.isEmpty()) { - ret = false; - } else { - m_tar7z_7z = new QProcess(); - m_tarProcess = new QProcess(); - m_tarProcess->setStandardOutputProcess(m_tar7z_7z); - m_tar7z_7z->setProcessChannelMode(QProcess::MergedChannels); - connect(m_tar7z_7z, &QProcess::readyReadStandardOutput, this, [this]() { readStdout(); }); - connect(m_tar7z_7z, QOverload::of(&QProcess::finished), this, &CliInterface::processFinished); - m_stdOutData.clear(); - m_isProcessKilled = false; - m_tarProcess->start(tarPath, tarArgs); - if (m_tarProcess->waitForStarted(5000)) { - m_tar7z_7z->start(sevenZPath, sevenZArgs); - // 不在此处 waitForStarted(7z),避免 7z 等 stdin 时阻塞主线程导致卡死 - ret = m_tar7z_7z->state() == QProcess::Starting || m_tar7z_7z->state() == QProcess::Running; - if (ret) { - m_processId = m_tar7z_7z->processId(); - m_childProcessId = QVector() << m_tarProcess->processId(); - } - connect(m_tar7z_7z, &QProcess::errorOccurred, this, [this](QProcess::ProcessError) { - if (m_tar7z_7z && m_tar7z_7z->state() == QProcess::NotRunning) { - processFinished(-1, QProcess::CrashExit); - } - }); - } else { - ret = false; - } - if (!ret) { - deleteProcess(); + m_filesSize = options.qTotalSize; // 待压缩文件总大小 + m_scriptPath = QDir::tempPath() + "/tempScript_" + QString::number(QDateTime::currentDateTime().toMSecsSinceEpoch()) + ".sh"; + QFile scriptFile(m_scriptPath); + if (scriptFile.open(QIODevice::WriteOnly | QIODevice::Text)) { + QTextStream out(&scriptFile); + out << "#!/bin/bash\n"; + for (const QString &arg : arguments) { + out << arg << "\n"; } + scriptFile.close(); + QProcess::execute("chmod", { "+x", m_scriptPath }); + ret = runProcess(m_scriptPath, QStringList()); + } else { + qWarning() << "Failed to create temporary script file."; + ret = false; } } else { QString processName = m_cliProps->property("addProgram").toString(); @@ -531,11 +507,7 @@ PluginFinishType CliInterface::addFiles(const QList &files, const Com qInfo() << "mtp 压缩完成,现在开始移动"; QStringList args_list; args_list << temp_archiveName << m_strArchiveName; - if (m_tar7z_7z) { - m_tar7z_7z->waitForFinished(-1); - } else if (m_process) { - m_process->waitForFinished(); - } + m_process->waitForFinished(); QProcess mover; ret = 0 == mover.execute("mv", args_list); ret = mover.exitCode() == QProcess::NormalExit; @@ -823,53 +795,22 @@ bool CliInterface::runProcess(const QString &programName, const QStringList &arg return true; } -bool CliInterface::killTar7zPipelineIfActive() -{ - if (!m_tar7z_7z) { - return false; - } - if (m_tarProcess && m_tarProcess->state() != QProcess::NotRunning) { - m_tarProcess->kill(); - } - if (m_tar7z_7z->state() != QProcess::NotRunning) { - m_tar7z_7z->kill(); - } - m_isProcessKilled = true; - return true; -} - void CliInterface::deleteProcess() { - if (m_tar7z_7z) { - m_tar7z_7z->blockSignals(true); - if (m_tar7z_7z->state() != QProcess::NotRunning) { - m_tar7z_7z->kill(); - m_tar7z_7z->waitForFinished(500); - } - delete m_tar7z_7z; - m_tar7z_7z = nullptr; - if (m_tarProcess) { - m_tarProcess->blockSignals(true); - if (m_tarProcess->state() != QProcess::NotRunning) { - m_tarProcess->kill(); - m_tarProcess->waitForFinished(500); - } - delete m_tarProcess; - m_tarProcess = nullptr; - } - return; - } if (m_process) { readStdout(true); m_process->blockSignals(true); // delete m_process之前需要断开所有m_process信号,防止重复处理 delete m_process; m_process = nullptr; + if(!m_scriptPath.isEmpty()) { + QFile::remove(m_scriptPath); + } } } void CliInterface::handleProgress(const QString &line) { - if (m_tar7z_7z || (m_process && m_process->program().at(0).contains("7z"))) { // 解析7z相关进度、文件名(含 tar.7z 管道) + if (m_process && m_process->program().at(0).contains("7z")) { // 解析7z相关进度、文件名 int pos = line.indexOf(QLatin1Char('%')); if (pos > 1) { int percentage = line.midRef(pos - 3, 3).toInt(); @@ -963,6 +904,24 @@ void CliInterface::handleProgress(const QString &line) emit signalCurFileName(fileName); } + } else if (m_process && m_process->program().at(0).contains("tempScript")) { + // 处理tar.7z进度 + // "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b 7M + [Content]" + // "\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b \b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b274M 1 + [Content]" + int pos = line.lastIndexOf(" + [Content]"); + if (pos > 1) { + int mPos = line.lastIndexOf("M "); + int bPos = line.lastIndexOf("\b", mPos); + QString tempLine = line.left(mPos); + // 已经压缩的文件大小 + qint64 compressedSize = tempLine.right(tempLine.size() - bPos - 1).toLongLong(); + // 计算文件大小计算百分比 + qint64 percentage = compressedSize * 1024 * 1024 * 100 / m_filesSize; + + emit signalprogress(percentage); + // 无法获取正在压缩的某个文件名 + // emit signalCurFileName(); + } } } @@ -1072,14 +1031,9 @@ PluginFinishType CliInterface::handleCorrupt() void CliInterface::writeToProcess(const QByteArray &data) { + Q_ASSERT(m_process); Q_ASSERT(!data.isNull()); - // tar.7z 管道下 stdin 为 tar 输出,不能写入,密码已通过命令行传入 - if (m_tar7z_7z) { - return; - } - if (!m_process) { - return; - } + // m_process->write(data); m_process->pty()->write(data); } @@ -1336,17 +1290,14 @@ void CliInterface::readStdout(bool handleAll) return; } - QProcess *outProcess = m_tar7z_7z ? m_tar7z_7z : m_process; - if (!outProcess) { - return; - } + Q_ASSERT(m_process); - if (!outProcess->bytesAvailable()) { // 无数据 + if (!m_process->bytesAvailable()) { // 无数据 return; } // 获取命令行输出 - QByteArray dd = outProcess->readAllStandardOutput(); + QByteArray dd = m_process->readAllStandardOutput(); m_stdOutData += dd; // 换行分割 @@ -1358,10 +1309,12 @@ void CliInterface::readStdout(bool handleAll) // } bool isWrongPwd = isWrongPasswordMsg(lines.last()); - // 7z 或 tar.7z 管道:进度行结束无 \n - bool is7zAdd = m_tar7z_7z || (m_process && m_process->program().at(0).contains("7z") && m_process->program().at(1) != "l"); - if (is7zAdd && !isWrongPwd) { - handleAll = true; + if ((m_process->program().at(0).contains("7z") && m_process->program().at(1) != "l") && !isWrongPwd) { + handleAll = true; // 7z进度行结束无\n + } + + if ((m_process->program().at(0).contains("tempScript")) && !isWrongPwd) { + handleAll = true; // compress .tar.7z progressline has no \n } bool foundErrorMessage = (isWrongPwd || isDiskFullMsg(QLatin1String(lines.last())) @@ -1378,7 +1331,7 @@ void CliInterface::readStdout(bool handleAll) // because the last line might be incomplete we leave it for now // note, this last line may be an empty string if the stdoutdata ends // with a newline - if (m_process && m_process->program().at(0).contains("unrar")) { // 针对unrar的命令行截取 + if (m_process->program().at(0).contains("unrar")) { // 针对unrar的命令行截取 m_stdOutData.clear(); if (lines.count() > 0) { if (!(lines[lines.count() - 1].endsWith("%") || lines[lines.count() - 1].endsWith("OK "))) { diff --git a/3rdparty/interface/archiveinterface/cliinterface.h b/3rdparty/interface/archiveinterface/cliinterface.h index 089dba38..64913354 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.h +++ b/3rdparty/interface/archiveinterface/cliinterface.h @@ -143,12 +143,6 @@ class CliInterface : public ReadWriteArchiveInterface */ virtual void killProcess(bool emitFinished = true) = 0; - /** - * @brief killTar7zPipelineIfActive 若当前为 tar.7z 管道则结束两个进程 - * @return 若已结束管道返回 true,否则 false - */ - bool killTar7zPipelineIfActive(); - /** * @brief handleProgress 解析进度并发送进度信号 * @param line @@ -242,8 +236,6 @@ private slots: protected: CliProperties *m_cliProps = nullptr; // 命令属性 /*KProcess*/KPtyProcess *m_process = nullptr; // 工作进程 - QProcess *m_tarProcess = nullptr; // 仅 tar.7z 管道:tar 进程 - QProcess *m_tar7z_7z = nullptr; // 仅 tar.7z 管道:7z 进程(输出来自此进程) PluginFinishType m_finishType = PFT_Nomral; // 插件结束类型 QString m_strEncryptedFileName = QString(); // 当前被解压的加密文件名 QVector m_childProcessId; // 压缩tar.7z文件的子进程Id @@ -270,6 +262,7 @@ private slots: QMap m_mapLongName; // 长文件名统计 QMap m_mapLongDirName; // 长文件夹统计 QMap m_mapRealDirValue; // 真实文件统计 + QString m_scriptPath; // 脚本路径 }; #endif // CLIINTERFACE_H diff --git a/3rdparty/interface/archiveinterface/cliproperties.cpp b/3rdparty/interface/archiveinterface/cliproperties.cpp index bff03b70..e71e8918 100644 --- a/3rdparty/interface/archiveinterface/cliproperties.cpp +++ b/3rdparty/interface/archiveinterface/cliproperties.cpp @@ -51,9 +51,76 @@ QStringList CliProperties::addArgs(const QString &archive, const QStringList &fi Q_ASSERT(!password.isEmpty()); } - // tar.7z 已改为 getTar7zTarArgs/getTar7z7zArgs + QProcess 管道,不再用脚本,此处不再拼命令串 if (isTar7z) { - return QStringList(); + // tar.7z压缩命令重命名:tar --transform='flags=r;s|oldname1|newname1|' --transform='flags=r;s|oldname2|newname3|' .... + // tar.7z压缩命令: tar cf - -C /home/username/Desktop/ 1.txt -C /home/username/Desktop/2/3/ 4K | 7z a - si new.tar.7z + const QString oneSpace = " "; //一个空格 + QVector strold = {" ", "!", "$", "&", "*", "(", ")", "<", ">", "+", "-", ";"}; + QVector strnew = {"\\ ", "\\!", "\\$", "\\&", "\\*", "\\(", "\\)", "\\<", "\\>", "\\+", "\\-", "\\;"}; + // 注意字符转意,待优化 + + QStringList args; + + QString tmp = "tar cf - "; + //重命名文件 + if(!renameList.isEmpty()) { + tmp = "tar "; + for (QString sRename: renameList) { + tmp = tmp + sRename + oneSpace; + } + tmp = tmp + "-cf - "; + } + for (QString file : files) { + for (int n = 0; n < strold.length(); ++n) { + file.replace(strold[n], strnew[n]); + } + + if (file.endsWith('/')) { + file.chop(1); + } + + int pos = file.lastIndexOf('/'); + if (pos > 0) { + //此处传进来的files是绝对路径,处理和dev分支有点区别, + tmp += "-C " + file.mid(0, pos + 1) + oneSpace + file.mid(pos + 1) + oneSpace; + } + } + + tmp += "| 7z a -si "; + if (!password.isEmpty()) { + for (QString &val : substitutePasswordSwitch(password, headerEncryption)) { + tmp += val + oneSpace; + } + } + + if (compressionLevel > -1) { + tmp += substituteCompressionLevelSwitch(compressionLevel) + oneSpace; + } + + if (!compressionMethod.isEmpty()) { + tmp += substituteCompressionMethodSwitch(compressionMethod) + oneSpace; + } + + if (!encryptionMethod.isEmpty()) { + tmp += substituteEncryptionMethodSwitch(encryptionMethod) + oneSpace; + } + if (volumeSize > 0) { + tmp += substituteMultiVolumeSwitch(volumeSize) + oneSpace; + } + + if (!m_progressarg.isEmpty()) { + tmp += m_progressarg + oneSpace; + } + + QString tmparchive = archive; + for (int n = 0; n < strold.length(); ++n) { + tmparchive.replace(strold[n], strnew[n]); + } + + tmp += tmparchive; + args << tmp; + // qInfo() << tmp; + return args; } else { QStringList args; for (const QString &s : qAsConst(m_addSwitch)) { @@ -91,72 +158,6 @@ QStringList CliProperties::addArgs(const QString &archive, const QStringList &fi } } -QStringList CliProperties::getTar7zTarArgs(const QStringList &files, const QStringList &renameList) -{ - QStringList args; - if (renameList.isEmpty()) { - args << QStringLiteral("cf") << QStringLiteral("-"); - } else { - args << renameList; - args << QStringLiteral("-cf") << QStringLiteral("-"); - } - for (QString file : files) { - if (file.endsWith(QLatin1Char('/'))) { - file.chop(1); - } - int pos = file.lastIndexOf(QLatin1Char('/')); - if (pos > 0) { - args << QStringLiteral("-C") << file.mid(0, pos) << file.mid(pos + 1); - } else if (pos == 0) { - args << QStringLiteral("-C") << QStringLiteral("/") << file.mid(1); - } else { - args << QStringLiteral("-C") << QStringLiteral(".") << file; - } - } - return args; -} - -QStringList CliProperties::getTar7z7zArgs(const QString &archive, const QString &password, bool headerEncryption, - int compressionLevel, const QString &compressionMethod, - const QString &encryptionMethod, int volumeSize) -{ - QStringList args; - args << QStringLiteral("a") << QStringLiteral("-si") << archive; - if (!password.isEmpty()) { - // 单参数 -p+密码,避免 7z 再从 stdin 提示输入导致管道卡死 - args << (QStringLiteral("-p") + password); - } - if (compressionLevel > -1) { - const QString s = substituteCompressionLevelSwitch(compressionLevel); - if (!s.isEmpty()) { - args << s; - } - } - if (!compressionMethod.isEmpty()) { - const QString s = substituteCompressionMethodSwitch(compressionMethod); - if (!s.isEmpty()) { - args << s; - } - } - if (!encryptionMethod.isEmpty()) { - const QString s = substituteEncryptionMethodSwitch(encryptionMethod); - if (!s.isEmpty()) { - args << s; - } - } - if (volumeSize > 0) { - const QString s = substituteMultiVolumeSwitch(volumeSize); - if (!s.isEmpty()) { - args << s; - } - } - if (!m_progressarg.isEmpty()) { - args << m_progressarg; - } - args.removeAll(QString()); - return args; -} - QStringList CliProperties::commentArgs(const QString &archive, const QString &commentfile) { QStringList args; diff --git a/3rdparty/interface/archiveinterface/cliproperties.h b/3rdparty/interface/archiveinterface/cliproperties.h index 7677e82f..57a363c3 100644 --- a/3rdparty/interface/archiveinterface/cliproperties.h +++ b/3rdparty/interface/archiveinterface/cliproperties.h @@ -83,12 +83,6 @@ class CliProperties : public QObject bool isTar7z, const QString &globalWorkDir, const QStringList &renameList = QStringList()); - /** tar.7z 管道:仅 tar 参数(QStringList,无 shell 拼接),供 QProcess 使用 */ - QStringList getTar7zTarArgs(const QStringList &files, const QStringList &renameList = QStringList()); - /** tar.7z 管道:仅 7z 参数(密码用 "-p" + 独立 argv,无 shell),供 QProcess 使用 */ - QStringList getTar7z7zArgs(const QString &archive, const QString &password, bool headerEncryption, - int compressionLevel, const QString &compressionMethod, - const QString &encryptionMethod, int volumeSize); QStringList commentArgs(const QString &archive, const QString &commentfile); QStringList deleteArgs(const QString &archive, const QList &files, const QString &password); QStringList extractArgs(const QString &archive, const QStringList &files, bool preservePaths, const QString &password); From fd8b3c5cce332dda11b6fa27ce2dd546a9363bb5 Mon Sep 17 00:00:00 2001 From: ZhangTingan Date: Tue, 14 Apr 2026 18:55:38 +0800 Subject: [PATCH 3/3] fix(compress): show tar filename during tar.7z compression MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Display tar filename in progress when compressing tar.7z archives, improving user experience by showing meaningful progress information. 压缩tar.7z时显示tar文件名,提升用户体验。 Log: tar.7z压缩时提示tar文件名 PMS: BUG-356753 Influence: 压缩tar.7z格式时,进度提示显示tar文件名,用户可以看到正在处理的归档文件名称 --- 3rdparty/interface/archiveinterface/cliinterface.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/3rdparty/interface/archiveinterface/cliinterface.cpp b/3rdparty/interface/archiveinterface/cliinterface.cpp index d5f40a16..2176be6a 100644 --- a/3rdparty/interface/archiveinterface/cliinterface.cpp +++ b/3rdparty/interface/archiveinterface/cliinterface.cpp @@ -919,8 +919,13 @@ void CliInterface::handleProgress(const QString &line) qint64 percentage = compressedSize * 1024 * 1024 * 100 / m_filesSize; emit signalprogress(percentage); - // 无法获取正在压缩的某个文件名 - // emit signalCurFileName(); + // tar.7z 无法获取正在压缩的单个文件名,但可以提示正在打包成 tar 文件 + // 发送 tar 文件名提示(去掉 .7z 后缀,显示正在打包的 tar 文件名) + QString tarFileName = QFileInfo(m_strArchiveName).fileName(); + if (tarFileName.endsWith(".7z", Qt::CaseInsensitive)) { + tarFileName = tarFileName.left(tarFileName.length() - 3); + } + emit signalCurFileName(tarFileName); } } }