Compare commits
13 Commits
1cfe12a861
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 7155880ff3 | |||
| 0e397ace7d | |||
| 5843332980 | |||
| 2f8b55be3b | |||
| 9f54ef60f9 | |||
| 4b6867bb76 | |||
| 2de857baeb | |||
| a0b3d4967b | |||
| e09cf859b8 | |||
| 5a659d4f01 | |||
| e3e1292455 | |||
| 152e4984a7 | |||
| 55c4bf6a8f |
120
.gitlab-ci.yml
Normal file
120
.gitlab-ci.yml
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
stages:
|
||||||
|
- build
|
||||||
|
- release
|
||||||
|
|
||||||
|
variables:
|
||||||
|
VS_DIR: "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools"
|
||||||
|
VS_ENV: "C:/Program Files (x86)/Microsoft Visual Studio/2022/BuildTools/Common7/Tools/Microsoft.VisualStudio.DevShell.dll"
|
||||||
|
CMAKE_BUILD_TYPE: Release
|
||||||
|
PROJECT_VERSION: "0.2.6"
|
||||||
|
CMAKE_GENERATOR: "Ninja"
|
||||||
|
PROJECT_NAME: "frelay"
|
||||||
|
ARCH_TYPE: x64
|
||||||
|
QT_PATH: "C:/Dev/qt6"
|
||||||
|
QT_XP: "C:/Qt/Qt5.7.1"
|
||||||
|
RELEASENAME: "$PROJECT_NAME-v$PROJECT_VERSION"
|
||||||
|
DESCRIPTION: |
|
||||||
|
|
||||||
|
# 优化
|
||||||
|
|
||||||
|
- 按照类型传输时,类型重复的问题修正。
|
||||||
|
|
||||||
|
# 关于预构建包
|
||||||
|
|
||||||
|
Windows XP系统请使用Windows-GNU-x86版本。
|
||||||
|
|
||||||
|
# Windows运行器配置
|
||||||
|
.win-template: &win
|
||||||
|
tags:
|
||||||
|
- win
|
||||||
|
before_script:
|
||||||
|
- echo "Running on Windows runner"
|
||||||
|
artifacts:
|
||||||
|
expire_in: 1 hour
|
||||||
|
|
||||||
|
# Windows构建 - 在win运行器上执行
|
||||||
|
build-xp:
|
||||||
|
<<: *win
|
||||||
|
stage: build
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_TAG
|
||||||
|
before_script:
|
||||||
|
- $env:QT_DIR = "$env:QT_XP/5.7/mingw53_32"
|
||||||
|
- $env:COMPILE_DIR = "$env:QT_XP/Tools/mingw530_32"
|
||||||
|
- $env:PATH = "$env:COMPILE_DIR/bin;$env:PATH"
|
||||||
|
script:
|
||||||
|
- Write-Host "开始Windows XP构建..."
|
||||||
|
- Write-Host "$env:QT_DIR"
|
||||||
|
- Write-Host "$env:COMPILE_DIR"
|
||||||
|
- cmake -Bbuild-xp -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" -DCMAKE_PREFIX_PATH="$env:QT_DIR" -DQT_DEFAULT_MAJOR_VERSION=5 -DCOMPILE_GUI=ON -DRELEASE_MARK=ON
|
||||||
|
- cmake --build build-xp --config "$CMAKE_BUILD_TYPE"
|
||||||
|
- Write-Host "package windows start..."
|
||||||
|
- cd build-xp
|
||||||
|
- cpack
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- build-xp/frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.exe
|
||||||
|
- build-xp/frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.zip
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
<<: *win
|
||||||
|
stage: build
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_TAG
|
||||||
|
script:
|
||||||
|
- Import-Module $VS_ENV
|
||||||
|
- Enter-VsDevShell -VsInstallPath $VS_DIR -DevCmdArguments "-arch=$ARCH_TYPE"
|
||||||
|
- cmake -Bbuild -G "$CMAKE_GENERATOR" -DCMAKE_BUILD_TYPE="$CMAKE_BUILD_TYPE" -DCMAKE_PREFIX_PATH="$QT_PATH" -DQT_DEFAULT_MAJOR_VERSION=6 -DCOMPILE_GUI=ON -DRELEASE_MARK=ON
|
||||||
|
- cmake --build build --config "$CMAKE_BUILD_TYPE"
|
||||||
|
- Write-Host "package windows start..."
|
||||||
|
- cd build
|
||||||
|
- cpack
|
||||||
|
artifacts:
|
||||||
|
paths:
|
||||||
|
- build/frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.exe
|
||||||
|
- build/frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.zip
|
||||||
|
|
||||||
|
create-release:
|
||||||
|
stage: release
|
||||||
|
needs: ["build-windows", "build-xp"]
|
||||||
|
tags:
|
||||||
|
- pi
|
||||||
|
variables:
|
||||||
|
RELEASE_TAG: "v$PROJECT_VERSION"
|
||||||
|
RELEASE_NAME: "$RELEASENAME"
|
||||||
|
RELEASE_DESCRIPTION: "$DESCRIPTION"
|
||||||
|
rules:
|
||||||
|
- if: $CI_COMMIT_TAG
|
||||||
|
script:
|
||||||
|
- echo "start release"
|
||||||
|
- >
|
||||||
|
curl --fail --show-error --header "JOB-TOKEN: $CI_JOB_TOKEN" \
|
||||||
|
--upload-file "build/frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.exe" \
|
||||||
|
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/releases/v$PROJECT_VERSION/frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.exe"
|
||||||
|
- >
|
||||||
|
curl --fail --show-error --header "JOB-TOKEN: $CI_JOB_TOKEN" \
|
||||||
|
--upload-file "build/frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.zip" \
|
||||||
|
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/releases/v$PROJECT_VERSION/frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.zip"
|
||||||
|
- >
|
||||||
|
curl --fail --show-error --header "JOB-TOKEN: $CI_JOB_TOKEN" \
|
||||||
|
--upload-file "build-xp/frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.exe" \
|
||||||
|
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/releases/v$PROJECT_VERSION/frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.exe"
|
||||||
|
- >
|
||||||
|
curl --fail --show-error --header "JOB-TOKEN: $CI_JOB_TOKEN" \
|
||||||
|
--upload-file "build-xp/frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.zip" \
|
||||||
|
"${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/releases/v$PROJECT_VERSION/frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.zip"
|
||||||
|
|
||||||
|
release:
|
||||||
|
tag_name: $RELEASE_TAG
|
||||||
|
name: $RELEASE_NAME
|
||||||
|
description: $RELEASE_DESCRIPTION
|
||||||
|
assets:
|
||||||
|
links:
|
||||||
|
- name: "frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.exe"
|
||||||
|
url: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/releases/v$PROJECT_VERSION/frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.exe"
|
||||||
|
- name: "frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.zip"
|
||||||
|
url: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/releases/v$PROJECT_VERSION/frelay-release-v$PROJECT_VERSION-Windows-MSVC-x64.zip"
|
||||||
|
- name: "frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.exe"
|
||||||
|
url: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/releases/v$PROJECT_VERSION/frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.exe"
|
||||||
|
- name: "frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.zip"
|
||||||
|
url: "${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/generic/releases/v$PROJECT_VERSION/frelay-release-v$PROJECT_VERSION-Windows-GNU-x86.zip"
|
||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@@ -13,10 +13,11 @@
|
|||||||
"ignoreFailures": true
|
"ignoreFailures": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"visualizerFile": "${workspaceRoot}/.vscode/qt6.natvis",
|
||||||
"args": []
|
"args": []
|
||||||
},
|
},
|
||||||
"cmake.configureSettings": {
|
"cmake.configureSettings": {
|
||||||
"CMAKE_PREFIX_PATH": "C:/dev/qt6",
|
"CMAKE_PREFIX_PATH": "C:/local/qt6",
|
||||||
},
|
},
|
||||||
"cmake.configureArgs": [
|
"cmake.configureArgs": [
|
||||||
"-Wno-dev",
|
"-Wno-dev",
|
||||||
|
|||||||
@@ -1,10 +1,3 @@
|
|||||||
// Zed keymap
|
|
||||||
//
|
|
||||||
// For information on binding keys, see the Zed
|
|
||||||
// documentation: https://zed.dev/docs/key-bindings
|
|
||||||
//
|
|
||||||
// To see the default key bindings run `zed: open default keymap`
|
|
||||||
// from the command palette.
|
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
"context": "Editor",
|
"context": "Editor",
|
||||||
|
|||||||
@@ -1,16 +1,3 @@
|
|||||||
// Zed settings
|
|
||||||
//
|
|
||||||
// For information on how to configure Zed, see the Zed
|
|
||||||
// documentation: https://zed.dev/docs/configuring-zed
|
|
||||||
//
|
|
||||||
// To see all of Zed's default settings without changing your
|
|
||||||
// custom settings, run `zed: open default settings` from the
|
|
||||||
// command palette (cmd-shift-p / ctrl-shift-p)
|
|
||||||
//
|
|
||||||
// 需要安装的依赖有
|
|
||||||
// 1.Nodejs
|
|
||||||
// 2.jsonnet-language-server
|
|
||||||
// 3.clangd
|
|
||||||
{
|
{
|
||||||
"tab_size": 4,
|
"tab_size": 4,
|
||||||
"vim_mode": false,
|
"vim_mode": false,
|
||||||
@@ -22,9 +9,6 @@
|
|||||||
"light": "One Light",
|
"light": "One Light",
|
||||||
"dark": "One Dark",
|
"dark": "One Dark",
|
||||||
},
|
},
|
||||||
"file_types": {
|
|
||||||
"Jsonnet": ["cfg"],
|
|
||||||
},
|
|
||||||
"lsp": {
|
"lsp": {
|
||||||
"clangd": {
|
"clangd": {
|
||||||
"binary": {
|
"binary": {
|
||||||
@@ -42,12 +26,5 @@
|
|||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"jsonnet-language-server": {
|
|
||||||
"settings": {
|
|
||||||
"formatting": {
|
|
||||||
"indent": 4,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
[
|
[
|
||||||
{
|
{
|
||||||
"label": "CmakeConfig",
|
"label": "Config",
|
||||||
"command": "cmd",
|
"command": "cmd",
|
||||||
"env": {
|
"env": {
|
||||||
"VS2026ENV": "\"C:\\Program Files\\Microsoft Visual Studio\\18\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat\"",
|
"BUILDTOOL": "\"C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat\"",
|
||||||
},
|
},
|
||||||
"args": [
|
"args": [
|
||||||
"/c",
|
"/c",
|
||||||
"$VS2026ENV && cmake -Bbuild -G Ninja -S . -DCOMPILE_GUI=ON -DCMAKE_BUILD_TYPE=Debug",
|
"\"%BUILDTOOL% && cmake -Bbuild -G Ninja -S . -DCMAKE_PREFIX_PATH=C:\\Kit\\Qt6 -DCMAKE_EXPORT_COMPILE_COMMANDS=ON\"",
|
||||||
],
|
],
|
||||||
"cwd": "$ZED_WORKTREE_ROOT",
|
"cwd": "$ZED_WORKTREE_ROOT",
|
||||||
"use_new_terminal": false,
|
"use_new_terminal": false,
|
||||||
@@ -15,12 +15,12 @@
|
|||||||
"show_summary": true,
|
"show_summary": true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"label": "CmakeBuild",
|
"label": "Build",
|
||||||
"command": "cmd",
|
"command": "cmd",
|
||||||
"env": {
|
"env": {
|
||||||
"VS2026ENV": "\"C:\\Program Files\\Microsoft Visual Studio\\18\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat\"",
|
"BUILDTOOL": "\"C:\\Program Files (x86)\\Microsoft Visual Studio\\2022\\BuildTools\\VC\\Auxiliary\\Build\\vcvars64.bat\"",
|
||||||
},
|
},
|
||||||
"args": ["/c", "$VS2026ENV && cmake --build build --config Debug"],
|
"args": ["/c", "\"%BUILDTOOL% && cmake --build build --config Debug\""],
|
||||||
"cwd": "$ZED_WORKTREE_ROOT",
|
"cwd": "$ZED_WORKTREE_ROOT",
|
||||||
"use_new_terminal": false,
|
"use_new_terminal": false,
|
||||||
"show_command": true,
|
"show_command": true,
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
project(frelay VERSION 0.2.4 LANGUAGES CXX)
|
project(frelay VERSION 0.2.7 LANGUAGES CXX)
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
@@ -76,6 +76,11 @@ set(QT_DEP_STYLES
|
|||||||
"${CMAKE_PREFIX_PATH}/plugins/styles/qmodernwindowsstyle.dll"
|
"${CMAKE_PREFIX_PATH}/plugins/styles/qmodernwindowsstyle.dll"
|
||||||
"${CMAKE_PREFIX_PATH}/plugins/styles/qwindowsvistastyle.dll"
|
"${CMAKE_PREFIX_PATH}/plugins/styles/qwindowsvistastyle.dll"
|
||||||
)
|
)
|
||||||
|
set(QT_IMG_DEP
|
||||||
|
"${CMAKE_PREFIX_PATH}/plugins/imageformats/qgif.dll"
|
||||||
|
"${CMAKE_PREFIX_PATH}/plugins/imageformats/qico.dll"
|
||||||
|
"${CMAKE_PREFIX_PATH}/plugins/imageformats/qjpeg.dll"
|
||||||
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(CMAKE_DEBUG_POSTFIX "d")
|
set(CMAKE_DEBUG_POSTFIX "d")
|
||||||
@@ -109,7 +114,7 @@ function(safe_install_files files_list destination)
|
|||||||
if(EXISTS ${file})
|
if(EXISTS ${file})
|
||||||
list(APPEND existing_files ${file})
|
list(APPEND existing_files ${file})
|
||||||
else()
|
else()
|
||||||
message(STATUS "跳过: ${file}")
|
message(STATUS "Jump: ${file}")
|
||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
if(existing_files)
|
if(existing_files)
|
||||||
@@ -129,6 +134,7 @@ if (WIN32)
|
|||||||
install(FILES ${QT_DEP_FILES} DESTINATION bin)
|
install(FILES ${QT_DEP_FILES} DESTINATION bin)
|
||||||
safe_install_files("${QT_DEP_PLATFORM}" "bin/platforms")
|
safe_install_files("${QT_DEP_PLATFORM}" "bin/platforms")
|
||||||
safe_install_files("${QT_DEP_STYLES}" "bin/styles")
|
safe_install_files("${QT_DEP_STYLES}" "bin/styles")
|
||||||
|
safe_install_files("${QT_IMG_DEP}" "bin/imageformats")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
execute_process(
|
execute_process(
|
||||||
@@ -169,5 +175,12 @@ set(CPACK_NSIS_DELETE_ICONS_EXTRA "
|
|||||||
else()
|
else()
|
||||||
set(CPACK_GENERATOR "TGZ")
|
set(CPACK_GENERATOR "TGZ")
|
||||||
endif()
|
endif()
|
||||||
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${DEVELOP_MARK}-v${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_CXX_COMPILER_ID}")
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
set(ARCH_BIT "x64")
|
||||||
|
elseif(CMAKE_SIZEOF_VOID_P EQUAL 4)
|
||||||
|
set(ARCH_BIT "x86")
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Unknown target architecture")
|
||||||
|
endif()
|
||||||
|
set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${DEVELOP_MARK}-v${CPACK_PACKAGE_VERSION}-${CMAKE_SYSTEM_NAME}-${CMAKE_CXX_COMPILER_ID}-${ARCH_BIT}")
|
||||||
include(CPack)
|
include(CPack)
|
||||||
|
|||||||
@@ -12,6 +12,9 @@ void ClientCore::Instance()
|
|||||||
socket_ = new QTcpSocket(this);
|
socket_ = new QTcpSocket(this);
|
||||||
connect(socket_, &QTcpSocket::readyRead, this, &ClientCore::onReadyRead);
|
connect(socket_, &QTcpSocket::readyRead, this, &ClientCore::onReadyRead);
|
||||||
connect(socket_, &QTcpSocket::disconnected, this, &ClientCore::onDisconnected);
|
connect(socket_, &QTcpSocket::disconnected, this, &ClientCore::onDisconnected);
|
||||||
|
clearWaitTimer_ = new QTimer(this);
|
||||||
|
clearWaitTimer_->setInterval(10000);
|
||||||
|
connect(clearWaitTimer_, &QTimer::timeout, this, [this]() { clearWaitTask(); });
|
||||||
}
|
}
|
||||||
|
|
||||||
ClientCore::~ClientCore()
|
ClientCore::~ClientCore()
|
||||||
@@ -142,10 +145,82 @@ void ClientCore::handleAsk(QSharedPointer<FrameBuffer> frame)
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// 这个请求的处理可能是耗时的,需要开线程处理。
|
||||||
|
if (msg.command == STRMSG_AC_ALL_DIRFILES) {
|
||||||
|
msg.command = STRMSG_AC_ANSWER_ALL_DIRFILES;
|
||||||
|
QMutexLocker locker(&waitTaskMut_);
|
||||||
|
if (waitTask_.contains(frame->fid)) {
|
||||||
|
msg.msg = STRMSG_ST_COMMAND_ALREADY_RUNNING;
|
||||||
|
if (!Send<InfoMsg>(msg, FBT_MSGINFO_ANSWER, frame->fid)) {
|
||||||
|
auto logMsg = tr("给") + frame->fid + tr("返回获取文件列表结果消息失败。");
|
||||||
|
qCritical() << logMsg;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
waitTask_[frame->fid] = WaitTask();
|
||||||
|
auto& wt = waitTask_[frame->fid];
|
||||||
|
QString fid = frame->fid;
|
||||||
|
wt.wo = new WaitOperOwn(this);
|
||||||
|
wt.wo->SetClient(this);
|
||||||
|
wt.wo->fid = fid;
|
||||||
|
wt.wo->infoMsg_ = msg;
|
||||||
|
wt.wo->func_ = [this, &wt, fid]() {
|
||||||
|
auto& infoMsg = wt.wo->infoMsg_;
|
||||||
|
infoMsg.command = STRMSG_AC_ANSWER_ALL_DIRFILES;
|
||||||
|
bool success = false;
|
||||||
|
//infoMsg.infos.clear();
|
||||||
|
for (auto& item : infoMsg.infos.keys()) {
|
||||||
|
auto fullDir = Util::Join(infoMsg.fst.root, item);
|
||||||
|
if (!DirFileHelper::GetAllFiles(fullDir, infoMsg.list)) {
|
||||||
|
success = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
auto& vec = infoMsg.infos[item];
|
||||||
|
for (const auto& dd : std::as_const(infoMsg.list)) {
|
||||||
|
FileStruct fst;
|
||||||
|
fst.root = infoMsg.fst.root;
|
||||||
|
fst.mid = item;
|
||||||
|
fst.relative = dd;
|
||||||
|
vec.push_back(fst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return success;
|
||||||
|
};
|
||||||
|
wt.wo->start();
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
// 未知信息
|
// 未知信息
|
||||||
qWarning() << QString(tr("未知询问信息类型:%1")).arg(msg.command);
|
qWarning() << QString(tr("未知询问信息类型:%1")).arg(msg.command);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClientCore::clearWaitTask()
|
||||||
|
{
|
||||||
|
QMutexLocker locker(&waitTaskMut_);
|
||||||
|
QList<QString> completedTasks;
|
||||||
|
|
||||||
|
for (auto it = waitTask_.begin(); it != waitTask_.end(); ++it) {
|
||||||
|
WaitTask& task = it.value();
|
||||||
|
if (task.wo && task.wo->isFinished()) {
|
||||||
|
completedTasks.append(it.key());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const QString& taskId : completedTasks) {
|
||||||
|
auto it = waitTask_.find(taskId);
|
||||||
|
if (it != waitTask_.end()) {
|
||||||
|
WaitTask& task = it.value();
|
||||||
|
if (task.wo) {
|
||||||
|
task.wo->wait();
|
||||||
|
delete task.wo;
|
||||||
|
task.wo = nullptr;
|
||||||
|
}
|
||||||
|
waitTask_.erase(it);
|
||||||
|
qDebug() << "清理完成的任务:" << taskId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ClientCore::UseFrame(QSharedPointer<FrameBuffer> frame)
|
void ClientCore::UseFrame(QSharedPointer<FrameBuffer> frame)
|
||||||
{
|
{
|
||||||
switch (frame->type) {
|
switch (frame->type) {
|
||||||
@@ -414,3 +489,107 @@ void WaitThread::interrupCheck()
|
|||||||
emit sigCheckOver();
|
emit sigCheckOver();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
WaitOper::WaitOper(QObject* parent) : WaitThread(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitOper::run()
|
||||||
|
{
|
||||||
|
isAlreadyInter_ = false;
|
||||||
|
infoMsg_.msg = STR_NONE;
|
||||||
|
isRun_ = true;
|
||||||
|
recvMsg_ = false;
|
||||||
|
|
||||||
|
infoMsg_.command = sendStrType_;
|
||||||
|
infoMsg_.fromPath = stra_;
|
||||||
|
infoMsg_.toPath = strb_;
|
||||||
|
infoMsg_.type = type_;
|
||||||
|
|
||||||
|
auto f = cli_->GetBuffer<InfoMsg>(infoMsg_, FBT_MSGINFO_ASK, cli_->GetRemoteID());
|
||||||
|
if (!ClientCore::syncInvoke(cli_, f)) {
|
||||||
|
auto errMsg = QString(tr("向%1发送%2请求失败。")).arg(cli_->GetRemoteID()).arg(sendStrType_);
|
||||||
|
emit sigCheckOver();
|
||||||
|
qCritical() << errMsg;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
while (isRun_) {
|
||||||
|
QThread::msleep(1);
|
||||||
|
if (isAlreadyInter_) {
|
||||||
|
qInfo() << tr("线程中断文件操作等待......");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!recvMsg_) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
isAlreadyInter_ = true;
|
||||||
|
emit sigCheckOver();
|
||||||
|
auto n = QString(tr("向%1的请求%2处理结束。")).arg(cli_->GetRemoteID()).arg(sendStrType_);
|
||||||
|
qInfo() << n;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitOper::SetType(const QString& sendType, const QString& ansType)
|
||||||
|
{
|
||||||
|
sendStrType_ = sendType;
|
||||||
|
ansStrType_ = ansType;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitOper::SetPath(const QString& stra, const QString& strb, const QString& type)
|
||||||
|
{
|
||||||
|
stra_ = stra;
|
||||||
|
strb_ = strb;
|
||||||
|
type_ = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoMsg WaitOper::GetMsgConst() const
|
||||||
|
{
|
||||||
|
return infoMsg_;
|
||||||
|
}
|
||||||
|
|
||||||
|
InfoMsg& WaitOper::GetMsgRef()
|
||||||
|
{
|
||||||
|
return infoMsg_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitOper::interrupCheck()
|
||||||
|
{
|
||||||
|
qWarning() << QString(tr("中断请求处理%1......")).arg(sendStrType_);
|
||||||
|
WaitThread::interrupCheck();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitOper::recvFrame(QSharedPointer<FrameBuffer> frame)
|
||||||
|
{
|
||||||
|
InfoMsg info = infoUnpack<InfoMsg>(frame->data);
|
||||||
|
if (info.command == ansStrType_) {
|
||||||
|
infoMsg_ = info;
|
||||||
|
recvMsg_ = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
auto n = tr("收到未知Oper的回复信息:") + info.command;
|
||||||
|
qInfo() << n;
|
||||||
|
}
|
||||||
|
|
||||||
|
WaitOperOwn::WaitOperOwn(QObject* parent) : WaitThread(parent)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitOperOwn::run()
|
||||||
|
{
|
||||||
|
auto execRet = false;
|
||||||
|
if (func_) {
|
||||||
|
execRet = func_();
|
||||||
|
}
|
||||||
|
if (!fid.isEmpty()) {
|
||||||
|
if (!cli_->syncInvoke(cli_, cli_->GetBuffer<InfoMsg>(infoMsg_, FBT_MSGINFO_ANSWER, fid))) {
|
||||||
|
qCritical() << QString(tr("向%1发送%2请求失败。")).arg(fid).arg(infoMsg_.command);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit sigOver();
|
||||||
|
}
|
||||||
|
|
||||||
|
void WaitOperOwn::recvFrame(QSharedPointer<FrameBuffer> frame)
|
||||||
|
{
|
||||||
|
qDebug() << "不应该被调用的地方:" << __FUNCTION__;
|
||||||
|
}
|
||||||
|
|||||||
@@ -15,8 +15,14 @@
|
|||||||
#include <QReadWriteLock>
|
#include <QReadWriteLock>
|
||||||
#include <QTcpSocket>
|
#include <QTcpSocket>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
#include <QTimer>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
|
||||||
|
class WaitOperOwn;
|
||||||
|
struct WaitTask {
|
||||||
|
QString id;
|
||||||
|
WaitOperOwn* wo;
|
||||||
|
};
|
||||||
class ClientCore : public QObject
|
class ClientCore : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -93,6 +99,7 @@ private:
|
|||||||
void onReadyRead();
|
void onReadyRead();
|
||||||
void onDisconnected();
|
void onDisconnected();
|
||||||
void handleAsk(QSharedPointer<FrameBuffer> frame);
|
void handleAsk(QSharedPointer<FrameBuffer> frame);
|
||||||
|
void clearWaitTask();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void UseFrame(QSharedPointer<FrameBuffer> frame);
|
void UseFrame(QSharedPointer<FrameBuffer> frame);
|
||||||
@@ -121,9 +128,13 @@ public:
|
|||||||
|
|
||||||
bool connected_{false};
|
bool connected_{false};
|
||||||
LocalFile localFile_;
|
LocalFile localFile_;
|
||||||
|
|
||||||
|
QTimer* clearWaitTimer_{};
|
||||||
|
QMutex waitTaskMut_;
|
||||||
|
QMap<QString, WaitTask> waitTask_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Socket Worker Thread
|
// 工作线程。
|
||||||
class SocketWorker : public QThread
|
class SocketWorker : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -139,7 +150,7 @@ private:
|
|||||||
ClientCore* core_{};
|
ClientCore* core_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
// HeatBeat to Server
|
// 心跳包线程。
|
||||||
class HeatBeat : public QThread
|
class HeatBeat : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -159,6 +170,7 @@ private:
|
|||||||
ClientCore* core_{};
|
ClientCore* core_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 耗时操作线程基本框架。
|
||||||
class WaitThread : public QThread
|
class WaitThread : public QThread
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@@ -183,4 +195,50 @@ protected:
|
|||||||
ClientCore* cli_{};
|
ClientCore* cli_{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 等待对方应答的等待线程。
|
||||||
|
class WaitOper : public WaitThread
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
WaitOper(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
public:
|
||||||
|
void run() override;
|
||||||
|
void SetType(const QString& sendType, const QString& ansType);
|
||||||
|
void SetPath(const QString& stra, const QString& strb, const QString& type);
|
||||||
|
InfoMsg GetMsgConst() const;
|
||||||
|
InfoMsg& GetMsgRef();
|
||||||
|
void interrupCheck() override;
|
||||||
|
void recvFrame(QSharedPointer<FrameBuffer> frame) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool recvMsg_{};
|
||||||
|
InfoMsg infoMsg_{};
|
||||||
|
QString sendStrType_{};
|
||||||
|
QString ansStrType_{};
|
||||||
|
QString stra_;
|
||||||
|
QString strb_;
|
||||||
|
QString type_;
|
||||||
|
};
|
||||||
|
|
||||||
|
// 等待自己耗时操作的线程。
|
||||||
|
class WaitOperOwn : public WaitThread
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
WaitOperOwn(QObject* parent = nullptr);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void sigOver();
|
||||||
|
|
||||||
|
public:
|
||||||
|
void run() override;
|
||||||
|
void recvFrame(QSharedPointer<FrameBuffer> frame) override;
|
||||||
|
|
||||||
|
public:
|
||||||
|
QString fid;
|
||||||
|
InfoMsg infoMsg_{};
|
||||||
|
std::function<bool()> func_;
|
||||||
|
};
|
||||||
|
|
||||||
#endif // CLIENTCORE_H
|
#endif // CLIENTCORE_H
|
||||||
@@ -398,7 +398,25 @@ void FileTrans::SendFile(const QSharedPointer<DoTransTask>& task)
|
|||||||
|
|
||||||
QMutexLocker locker(&sthMut_);
|
QMutexLocker locker(&sthMut_);
|
||||||
upTasks_[task->task.localId] = sendThread;
|
upTasks_[task->task.localId] = sendThread;
|
||||||
sendThread->run();
|
|
||||||
|
// 2026-03-24 找了一个可能卡顿的原因。
|
||||||
|
/*
|
||||||
|
在 Qt 的 QThread类中,start()和 run()有本质区别:
|
||||||
|
|
||||||
|
start()- 创建新线程 sendThread->start(); // ✅ 正确
|
||||||
|
|
||||||
|
启动一个新线程,在新线程中执行 run()方法,线程有自己的事件循环(如果调用 exec())
|
||||||
|
|
||||||
|
自动处理线程同步和资源管理信号/槽可以跨线程工作
|
||||||
|
|
||||||
|
run()- 只是普通方法调用 sendThread->run(); // ❌ 错误用法
|
||||||
|
|
||||||
|
在当前线程中直接调用这个方法,没有创建新线程阻塞当前线程直到 run()返回
|
||||||
|
|
||||||
|
对象的信号/槽仍然在原始线程上下文中
|
||||||
|
*/
|
||||||
|
// sendThread->run();
|
||||||
|
sendThread->start();
|
||||||
}
|
}
|
||||||
|
|
||||||
SendThread::SendThread(ClientCore* clientCore) : cliCore_(clientCore)
|
SendThread::SendThread(ClientCore* clientCore) : cliCore_(clientCore)
|
||||||
@@ -442,7 +460,7 @@ void SendThread::run()
|
|||||||
}
|
}
|
||||||
task_->tranSize += frame->data.size();
|
task_->tranSize += frame->data.size();
|
||||||
// 关键点:这里不调用,无法中途收到别人发的数据。
|
// 关键点:这里不调用,无法中途收到别人发的数据。
|
||||||
QCoreApplication::processEvents();
|
// QCoreApplication::processEvents();
|
||||||
}
|
}
|
||||||
qInfo() << QString(tr("结束发送文件:%1")).arg(task_->file.fileName());
|
qInfo() << QString(tr("结束发送文件:%1")).arg(task_->file.fileName());
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
#include "CompareControl.h"
|
#include "CompareControl.h"
|
||||||
|
|
||||||
#include <QDesktopServices>
|
#include <QDesktopServices>
|
||||||
|
#include <QDialogButtonBox>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
|
#include <QListWidget>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QXmlStreamReader>
|
#include <QXmlStreamReader>
|
||||||
#include <QXmlStreamWriter>
|
#include <QXmlStreamWriter>
|
||||||
@@ -44,17 +46,6 @@ void Compare::InitMenu()
|
|||||||
auto path = item->text();
|
auto path = item->text();
|
||||||
emit sigTryVisit(false, path);
|
emit sigTryVisit(false, path);
|
||||||
});
|
});
|
||||||
menu_->addAction(tr("添加新行"), this, [this]() {
|
|
||||||
int cnt = ui->tableWidget->rowCount();
|
|
||||||
ui->tableWidget->insertRow(cnt);
|
|
||||||
auto item1 = new QTableWidgetItem("");
|
|
||||||
auto item2 = new QTableWidgetItem("");
|
|
||||||
auto item3 = new QTableWidgetItem("");
|
|
||||||
ui->tableWidget->setItem(cnt, 0, item1);
|
|
||||||
ui->tableWidget->setItem(cnt, 1, item2);
|
|
||||||
ui->tableWidget->setItem(cnt, 2, item3);
|
|
||||||
});
|
|
||||||
menu_->addAction(tr("删除"), this, [this]() { deleteSelectedRows(); });
|
|
||||||
menu_->addAction(tr("尝试打开本地路径"), this, [this]() {
|
menu_->addAction(tr("尝试打开本地路径"), this, [this]() {
|
||||||
auto selected = ui->tableWidget->selectedItems();
|
auto selected = ui->tableWidget->selectedItems();
|
||||||
if (selected.size() != 3) {
|
if (selected.size() != 3) {
|
||||||
@@ -69,6 +60,19 @@ void Compare::InitMenu()
|
|||||||
}
|
}
|
||||||
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
QDesktopServices::openUrl(QUrl::fromLocalFile(path));
|
||||||
});
|
});
|
||||||
|
menu_->addAction(tr("添加新行"), this, [this]() {
|
||||||
|
int cnt = ui->tableWidget->rowCount();
|
||||||
|
ui->tableWidget->insertRow(cnt);
|
||||||
|
auto item1 = new QTableWidgetItem("");
|
||||||
|
auto item2 = new QTableWidgetItem("");
|
||||||
|
auto item3 = new QTableWidgetItem("");
|
||||||
|
ui->tableWidget->setItem(cnt, 0, item1);
|
||||||
|
ui->tableWidget->setItem(cnt, 1, item2);
|
||||||
|
ui->tableWidget->setItem(cnt, 2, item3);
|
||||||
|
});
|
||||||
|
menu_->addAction(tr("删除"), this, [this]() { deleteSelectedRows(); });
|
||||||
|
menu_->addAction(tr("上传"), this, [this]() { TransToRight(false); });
|
||||||
|
menu_->addAction(tr("下载"), this, [this]() { TransToLeft(false); });
|
||||||
menu_->addSeparator();
|
menu_->addSeparator();
|
||||||
connect(ui->tableWidget, &QTableWidget::customContextMenuRequested, this,
|
connect(ui->tableWidget, &QTableWidget::customContextMenuRequested, this,
|
||||||
[this](const QPoint& pos) { menu_->exec(QCursor::pos()); });
|
[this](const QPoint& pos) { menu_->exec(QCursor::pos()); });
|
||||||
@@ -80,8 +84,10 @@ void Compare::InitControl()
|
|||||||
|
|
||||||
connect(ui->btnSave, &QPushButton::clicked, this, &Compare::Save);
|
connect(ui->btnSave, &QPushButton::clicked, this, &Compare::Save);
|
||||||
connect(ui->btnLoad, &QPushButton::clicked, this, &Compare::Load);
|
connect(ui->btnLoad, &QPushButton::clicked, this, &Compare::Load);
|
||||||
connect(ui->btnLeft, &QPushButton::clicked, this, &Compare::TransToLeft);
|
// connect(ui->btnLeft, &QPushButton::clicked, this, &Compare::TransToLeft);
|
||||||
connect(ui->btnRight, &QPushButton::clicked, this, &Compare::TransToRight);
|
// connect(ui->btnRight, &QPushButton::clicked, this, &Compare::TransToRight);
|
||||||
|
connect(ui->btnTypeDown, &QPushButton::clicked, this, [this]() { FilterFiles(false); });
|
||||||
|
connect(ui->btnTypeUpload, &QPushButton::clicked, this, [this]() { FilterFiles(true); });
|
||||||
connect(ui->btnSearch, &QPushButton::clicked, this, &Compare::Search);
|
connect(ui->btnSearch, &QPushButton::clicked, this, &Compare::Search);
|
||||||
connect(ui->btnReset, &QPushButton::clicked, this, &Compare::Reset);
|
connect(ui->btnReset, &QPushButton::clicked, this, &Compare::Reset);
|
||||||
|
|
||||||
@@ -376,56 +382,148 @@ void Compare::SetResult(const QVector<CompareItem>& items)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compare::TransToLeft()
|
void Compare::FilterFiles(bool isUpload)
|
||||||
{
|
{
|
||||||
QVector<TransTask> tasks;
|
QDialog dialog(this);
|
||||||
QModelIndexList indexList = ui->tableWidget->selectionModel()->selectedRows();
|
QString title = QString("筛选文件类型(%1)").arg(isUpload ? tr("上传") : tr("下载"));
|
||||||
|
dialog.setWindowTitle(title);
|
||||||
|
dialog.resize(400, 300);
|
||||||
|
QListWidget listWidget(&dialog);
|
||||||
|
|
||||||
if (indexList.size() < 1) {
|
listWidget.setSelectionMode(QAbstractItemView::NoSelection);
|
||||||
QMessageBox::information(this, tr("提示"), tr("请选择要下载的文件。"));
|
QListWidgetItem* allItem = new QListWidgetItem("*(ALL)");
|
||||||
return;
|
allItem->setData(Qt::UserRole, "*ALL");
|
||||||
|
allItem->setCheckState(curSelectTypes_.contains("*") ? Qt::Checked : Qt::Unchecked);
|
||||||
|
listWidget.addItem(allItem);
|
||||||
|
|
||||||
|
std::map<QString, int> typeCounts;
|
||||||
|
int rows = ui->tableWidget->rowCount();
|
||||||
|
for (int i = 0; i < rows; ++i) {
|
||||||
|
QString ext = ui->tableWidget->item(i, 0)->text().split(".").last().toLower();
|
||||||
|
if (typeCounts.count(ext) < 1) {
|
||||||
|
QListWidgetItem* item = new QListWidgetItem(ext);
|
||||||
|
item->setData(Qt::UserRole, ext);
|
||||||
|
item->setCheckState(curSelectTypes_.contains(ext) ? Qt::Checked : Qt::Unchecked);
|
||||||
|
listWidget.addItem(item);
|
||||||
|
typeCounts[ext] = 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < indexList.size(); ++i) {
|
QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
|
||||||
const QTableWidgetItem* itemF = ui->tableWidget->item(indexList[i].row(), 2);
|
connect(&buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||||
const QTableWidgetItem* itemT = ui->tableWidget->item(indexList[i].row(), 1);
|
connect(&buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||||
|
|
||||||
|
QVBoxLayout layout(&dialog);
|
||||||
|
layout.addWidget(&listWidget);
|
||||||
|
layout.addWidget(&buttons);
|
||||||
|
dialog.setLayout(&layout);
|
||||||
|
|
||||||
|
if (dialog.exec() == QDialog::Accepted) {
|
||||||
|
QVector<QString> selectedTypes;
|
||||||
|
for (int i = 0; i < listWidget.count(); ++i) {
|
||||||
|
QListWidgetItem* item = listWidget.item(i);
|
||||||
|
if (item->checkState() == Qt::Checked) {
|
||||||
|
selectedTypes << item->data(Qt::UserRole).toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curSelectTypes_.clear();
|
||||||
|
for (int i = 0; i < selectedTypes.count(); ++i) {
|
||||||
|
curSelectTypes_.insert(selectedTypes[i]);
|
||||||
|
}
|
||||||
|
if (isUpload) {
|
||||||
|
TransToRight(true);
|
||||||
|
} else {
|
||||||
|
TransToLeft(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Compare::TransToLeft(bool useSelectTypes)
|
||||||
|
{
|
||||||
|
QVector<TransTask> tasks;
|
||||||
|
|
||||||
|
auto pushTask = [&](const QString& localPath, const QString& remotePath) {
|
||||||
TransTask task;
|
TransTask task;
|
||||||
task.taskUUID = Util::UUID();
|
task.taskUUID = Util::UUID();
|
||||||
task.isUpload = false;
|
task.isUpload = false;
|
||||||
task.localId = GlobalData::Ins()->GetLocalID();
|
task.localId = GlobalData::Ins()->GetLocalID();
|
||||||
task.localPath = itemT->text();
|
task.localPath = localPath;
|
||||||
task.remoteId = GlobalData::Ins()->GetRemoteID();
|
task.remoteId = GlobalData::Ins()->GetRemoteID();
|
||||||
task.remotePath = Util::Join(itemF->text(), ui->tableWidget->item(indexList[i].row(), 0)->text());
|
task.remotePath = remotePath;
|
||||||
tasks.push_back(task);
|
tasks.push_back(task);
|
||||||
}
|
};
|
||||||
|
|
||||||
emit sigTasks(tasks);
|
if (useSelectTypes) {
|
||||||
|
for (int i = 0; i < ui->tableWidget->rowCount(); ++i) {
|
||||||
|
QString ext = ui->tableWidget->item(i, 0)->text().split(".").last().toLower();
|
||||||
|
if (curSelectTypes_.contains(ext) || curSelectTypes_.contains("*ALL")) {
|
||||||
|
const QTableWidgetItem* itemF = ui->tableWidget->item(i, 1);
|
||||||
|
const QTableWidgetItem* itemT = ui->tableWidget->item(i, 2);
|
||||||
|
pushTask(itemT->text(), Util::Join(itemF->text(), ui->tableWidget->item(i, 0)->text()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tasks.size() > 0) {
|
||||||
|
emit sigTasks(tasks);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QModelIndexList indexList = ui->tableWidget->selectionModel()->selectedRows();
|
||||||
|
if (indexList.size() < 1) {
|
||||||
|
QMessageBox::information(this, tr("提示"), tr("请选择要下载的文件。"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < indexList.size(); ++i) {
|
||||||
|
const QTableWidgetItem* itemF = ui->tableWidget->item(indexList[i].row(), 2);
|
||||||
|
const QTableWidgetItem* itemT = ui->tableWidget->item(indexList[i].row(), 1);
|
||||||
|
pushTask(itemT->text(), Util::Join(itemF->text(), ui->tableWidget->item(indexList[i].row(), 0)->text()));
|
||||||
|
}
|
||||||
|
if (tasks.size() > 0) {
|
||||||
|
emit sigTasks(tasks);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compare::TransToRight()
|
void Compare::TransToRight(bool useSelectTypes)
|
||||||
{
|
{
|
||||||
QVector<TransTask> tasks;
|
QVector<TransTask> tasks;
|
||||||
QModelIndexList indexList = ui->tableWidget->selectionModel()->selectedRows();
|
|
||||||
|
|
||||||
if (indexList.size() < 1) {
|
auto pushTask = [&](const QString& localPath, const QString& remotePath) {
|
||||||
QMessageBox::information(this, tr("提示"), tr("请选择要上传的文件。"));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < indexList.size(); ++i) {
|
|
||||||
const QTableWidgetItem* itemF = ui->tableWidget->item(indexList[i].row(), 1);
|
|
||||||
const QTableWidgetItem* itemT = ui->tableWidget->item(indexList[i].row(), 2);
|
|
||||||
TransTask task;
|
TransTask task;
|
||||||
task.taskUUID = Util::UUID();
|
task.taskUUID = Util::UUID();
|
||||||
task.isUpload = true;
|
task.isUpload = true;
|
||||||
task.localId = GlobalData::Ins()->GetLocalID();
|
task.localId = GlobalData::Ins()->GetLocalID();
|
||||||
task.localPath = Util::Join(itemF->text(), ui->tableWidget->item(indexList[i].row(), 0)->text());
|
task.localPath = localPath;
|
||||||
task.remoteId = GlobalData::Ins()->GetRemoteID();
|
task.remoteId = GlobalData::Ins()->GetRemoteID();
|
||||||
task.remotePath = itemT->text();
|
task.remotePath = remotePath;
|
||||||
tasks.push_back(task);
|
tasks.push_back(task);
|
||||||
}
|
};
|
||||||
|
|
||||||
emit sigTasks(tasks);
|
if (useSelectTypes) {
|
||||||
|
for (int i = 0; i < ui->tableWidget->rowCount(); ++i) {
|
||||||
|
QString ext = ui->tableWidget->item(i, 0)->text().split(".").last().toLower();
|
||||||
|
if (curSelectTypes_.contains(ext) || curSelectTypes_.contains("*ALL")) {
|
||||||
|
const QTableWidgetItem* itemF = ui->tableWidget->item(i, 1);
|
||||||
|
const QTableWidgetItem* itemT = ui->tableWidget->item(i, 2);
|
||||||
|
pushTask(Util::Join(itemF->text(), ui->tableWidget->item(i, 0)->text()), itemT->text());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tasks.size() > 0) {
|
||||||
|
emit sigTasks(tasks);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
QModelIndexList indexList = ui->tableWidget->selectionModel()->selectedRows();
|
||||||
|
if (indexList.size() < 1) {
|
||||||
|
QMessageBox::information(this, tr("提示"), tr("请选择要上传的文件。"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < indexList.size(); ++i) {
|
||||||
|
const QTableWidgetItem* itemF = ui->tableWidget->item(indexList[i].row(), 1);
|
||||||
|
const QTableWidgetItem* itemT = ui->tableWidget->item(indexList[i].row(), 2);
|
||||||
|
pushTask(Util::Join(itemF->text(), ui->tableWidget->item(indexList[i].row(), 0)->text()), itemT->text());
|
||||||
|
}
|
||||||
|
if (tasks.size() > 0) {
|
||||||
|
emit sigTasks(tasks);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Compare::deleteSelectedRows()
|
void Compare::deleteSelectedRows()
|
||||||
|
|||||||
@@ -40,9 +40,10 @@ private:
|
|||||||
void Search();
|
void Search();
|
||||||
void Reset();
|
void Reset();
|
||||||
void SetResult(const QVector<CompareItem>& items);
|
void SetResult(const QVector<CompareItem>& items);
|
||||||
|
void FilterFiles(bool isUpload);
|
||||||
|
|
||||||
void TransToLeft();
|
void TransToLeft(bool useSelectTypes);
|
||||||
void TransToRight();
|
void TransToRight(bool useSelectTypes);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void deleteSelectedRows();
|
void deleteSelectedRows();
|
||||||
@@ -52,6 +53,7 @@ private:
|
|||||||
Ui::Compare* ui;
|
Ui::Compare* ui;
|
||||||
|
|
||||||
// 现要求,保存、删除、拖入必须重置。
|
// 现要求,保存、删除、拖入必须重置。
|
||||||
|
QSet<QString> curSelectTypes_;
|
||||||
bool isResource_{};
|
bool isResource_{};
|
||||||
QVector<CompareItem> items_;
|
QVector<CompareItem> items_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -67,9 +67,9 @@
|
|||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btnLeft">
|
<widget class="QPushButton" name="btnTypeDown">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>下载</string>
|
<string>按类型下载</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
@@ -117,9 +117,9 @@
|
|||||||
</spacer>
|
</spacer>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QPushButton" name="btnRight">
|
<widget class="QPushButton" name="btnTypeUpload">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>上传</string>
|
<string>按类型上传</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
|||||||
@@ -511,32 +511,103 @@ void FileManager::UpDown()
|
|||||||
QMessageBox::information(this, tr("提示"), tr("请选择完整的行。"));
|
QMessageBox::information(this, tr("提示"), tr("请选择完整的行。"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
QVector<TransTask> tasks;
|
/*
|
||||||
for (int i = 0; i < (datas.size() / 5); ++i) {
|
要注意这一块的逻辑,本软件的所讲的【上传】【下载】都是针对本地。
|
||||||
if (datas[i * 5 + 3]->text() != "File") {
|
这里的任务拼接和 DropEvent 有所不同,
|
||||||
qDebug() << QString(tr("暂不支持传输文件夹:%1")).arg(datas[i * 5 + 3]->text());
|
DropEvent 是接收方负责拼接任务,但是这里是发送方拼接任务。
|
||||||
continue;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
要注意这一块的逻辑,本软件的所讲的【上传】【下载】都是针对本地。
|
|
||||||
这里的任务拼接和 DropEvent 有所不同,
|
|
||||||
DropEvent 是接收方负责拼接任务,但是这里是发送方拼接任务。
|
|
||||||
|
|
||||||
所以这里的拼接逻辑需要注意。
|
所以这里的拼接逻辑需要注意。
|
||||||
*/
|
*/
|
||||||
|
QVector<FileStruct> resultFiles;
|
||||||
|
|
||||||
|
if (isRemote_) {
|
||||||
|
// 远程等待别人。
|
||||||
|
WaitOper wi(this);
|
||||||
|
wi.SetClient(cliCore_);
|
||||||
|
wi.SetType(STRMSG_AC_ALL_DIRFILES, STRMSG_AC_ANSWER_ALL_DIRFILES);
|
||||||
|
auto& infoMsg = wi.GetMsgRef();
|
||||||
|
infoMsg.infos.clear();
|
||||||
|
infoMsg.fst.root = GlobalData::Ins()->GetRemoteRoot();
|
||||||
|
|
||||||
|
for (int i = 0; i < (datas.size() / 5); ++i) {
|
||||||
|
FileStruct fst;
|
||||||
|
fst.root = GlobalData::Ins()->GetRemoteRoot();
|
||||||
|
fst.mid = datas[i * 5 + 1]->text();
|
||||||
|
const auto& curType = datas[i * 5 + 3]->text();
|
||||||
|
if (curType == "File") {
|
||||||
|
fst.relative = datas[i * 5 + 1]->text();
|
||||||
|
resultFiles << fst;
|
||||||
|
} else {
|
||||||
|
infoMsg.infos[datas[i * 5 + 1]->text()] = QVector<FileStruct>{};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadingDialog checking(this);
|
||||||
|
checking.setTipsText("正在等待对方获取文件列表...");
|
||||||
|
connect(&wi, &WaitOper::sigCheckOver, &checking, &LoadingDialog::cancelBtnClicked);
|
||||||
|
connect(cliCore_, &ClientCore::sigMsgAnswer, &wi, &WaitOper::recvFrame);
|
||||||
|
|
||||||
|
wi.start();
|
||||||
|
checking.exec();
|
||||||
|
|
||||||
|
if (!infoMsg.list.isEmpty()) {
|
||||||
|
for (const auto& item : infoMsg.infos.keys()) {
|
||||||
|
resultFiles << infoMsg.infos[item];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// 本地自己等待。
|
||||||
|
WaitOperOwn wo(this);
|
||||||
|
wo.func_ = [this, &datas, &resultFiles]() {
|
||||||
|
resultFiles.clear();
|
||||||
|
for (int i = 0; i < (datas.size() / 5); ++i) {
|
||||||
|
FileStruct fst;
|
||||||
|
fst.root = GlobalData::Ins()->GetLocalRoot();
|
||||||
|
|
||||||
|
const auto& curType = datas[i * 5 + 3]->text();
|
||||||
|
if (curType == "File") {
|
||||||
|
fst.mid = datas[i * 5 + 1]->text();
|
||||||
|
resultFiles.push_back(fst);
|
||||||
|
} else {
|
||||||
|
QVector<FileStruct> fst;
|
||||||
|
DirFileHelper::GetAllFiles(GlobalData::Ins()->GetLocalRoot(), datas[i * 5 + 1]->text(), fst);
|
||||||
|
if (!fst.isEmpty()) {
|
||||||
|
resultFiles << fst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
LoadingDialog checking(this);
|
||||||
|
checking.setTipsText("正在获取文件列表...");
|
||||||
|
checking.setCanCancel(false);
|
||||||
|
connect(&wo, &WaitOperOwn::sigOver, &checking, &LoadingDialog::cancelBtnClicked);
|
||||||
|
|
||||||
|
wo.start();
|
||||||
|
checking.exec();
|
||||||
|
}
|
||||||
|
|
||||||
|
QVector<TransTask> tasks;
|
||||||
|
|
||||||
|
// 这里的 file 是相对路径,不再是特定的文件名称。
|
||||||
|
for (const auto& file : std::as_const(resultFiles)) {
|
||||||
TransTask task;
|
TransTask task;
|
||||||
task.taskUUID = Util::UUID();
|
task.taskUUID = Util::UUID();
|
||||||
task.isUpload = !isRemote_;
|
task.isUpload = !isRemote_;
|
||||||
task.localId = cliCore_->GetOwnID();
|
task.localId = cliCore_->GetOwnID();
|
||||||
task.remoteId = cliCore_->GetRemoteID();
|
task.remoteId = cliCore_->GetRemoteID();
|
||||||
if (isRemote_) {
|
if (isRemote_) {
|
||||||
task.remotePath = Util::Join(GlobalData::Ins()->GetRemoteRoot(), datas[i * 5 + 1]->text());
|
task.remotePath = Util::Join(file.root, file.mid, file.relative);
|
||||||
task.localPath = GlobalData::Ins()->GetLocalRoot();
|
auto filePath = Util::Join(GlobalData::Ins()->GetLocalRoot(), file.mid, file.relative);
|
||||||
|
task.localPath = Util::GetFileDir(filePath);
|
||||||
} else {
|
} else {
|
||||||
task.remotePath = GlobalData::Ins()->GetRemoteRoot();
|
auto filePath = Util::Join(GlobalData::Ins()->GetRemoteRoot(), file.mid, file.relative);
|
||||||
task.localPath = Util::Join(GlobalData::Ins()->GetLocalRoot(), datas[i * 5 + 1]->text());
|
task.remotePath = Util::GetFileDir(filePath);
|
||||||
|
task.localPath = Util::Join(file.root, file.mid, file.relative);
|
||||||
}
|
}
|
||||||
tasks.push_back(task);
|
tasks.append(task);
|
||||||
}
|
}
|
||||||
if (tasks.isEmpty()) {
|
if (tasks.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
@@ -569,7 +640,7 @@ void FileManager::OperNewFolder()
|
|||||||
if (!isRemote_) {
|
if (!isRemote_) {
|
||||||
QString ret = Util::NewDir(folder);
|
QString ret = Util::NewDir(folder);
|
||||||
if (ret.isEmpty()) {
|
if (ret.isEmpty()) {
|
||||||
QMessageBox::information(this, tr("提示"), tr("创建%1成功").arg(folder));
|
// QMessageBox::information(this, tr("提示"), tr("创建%1成功").arg(folder));
|
||||||
DirFileInfo nf;
|
DirFileInfo nf;
|
||||||
nf.size = 0;
|
nf.size = 0;
|
||||||
nf.type = Dir;
|
nf.type = Dir;
|
||||||
@@ -605,17 +676,18 @@ void FileManager::OperNewFolder()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查结果
|
// 检查结果
|
||||||
auto msg = oper.GetMsg();
|
auto msg = oper.GetMsgConst();
|
||||||
if (msg.msg == STR_NONE || !msg.msg.isEmpty()) {
|
if (msg.msg == STR_NONE || !msg.msg.isEmpty()) {
|
||||||
QMessageBox::information(this, tr("提示"), QString(tr("新建失败=>%1")).arg(msg.msg));
|
QMessageBox::information(this, tr("提示"), QString(tr("新建失败=>%1")).arg(msg.msg));
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::information(this, tr("提示"), QString(tr("新建%1成功。")).arg(folder));
|
// QMessageBox::information(this, tr("提示"), QString(tr("新建%1成功。")).arg(folder));
|
||||||
DirFileInfo nf;
|
DirFileInfo nf;
|
||||||
nf.size = 0;
|
nf.size = 0;
|
||||||
nf.type = Dir;
|
nf.type = Dir;
|
||||||
nf.fullPath = folder;
|
nf.fullPath = folder;
|
||||||
nf.name = text;
|
nf.name = text;
|
||||||
nf.lastModified = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
// nf.lastModified = QDateTime::currentDateTime().toMSecsSinceEpoch();
|
||||||
|
nf.lastModified = QDateTime::currentMSecsSinceEpoch();
|
||||||
ui->tableWidget->insertRow(0);
|
ui->tableWidget->insertRow(0);
|
||||||
ShowFileItem(nf, 0);
|
ShowFileItem(nf, 0);
|
||||||
}
|
}
|
||||||
@@ -642,7 +714,7 @@ void FileManager::OperDelete()
|
|||||||
if (!isRemote_) {
|
if (!isRemote_) {
|
||||||
QString ret = Util::Delete(name);
|
QString ret = Util::Delete(name);
|
||||||
if (ret.isEmpty()) {
|
if (ret.isEmpty()) {
|
||||||
QMessageBox::information(this, tr("提示"), tr("删除成功"));
|
// QMessageBox::information(this, tr("提示"), tr("删除成功"));
|
||||||
int row = datas[0]->row();
|
int row = datas[0]->row();
|
||||||
ui->tableWidget->removeRow(row);
|
ui->tableWidget->removeRow(row);
|
||||||
} else {
|
} else {
|
||||||
@@ -672,11 +744,11 @@ void FileManager::OperDelete()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查结果
|
// 检查结果
|
||||||
auto msg = oper.GetMsg();
|
auto msg = oper.GetMsgConst();
|
||||||
if (msg.msg == STR_NONE || !msg.msg.isEmpty()) {
|
if (msg.msg == STR_NONE || !msg.msg.isEmpty()) {
|
||||||
QMessageBox::information(this, tr("提示"), QString(tr("删除失败=>%1")).arg(msg.msg));
|
QMessageBox::information(this, tr("提示"), QString(tr("删除失败=>%1")).arg(msg.msg));
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::information(this, tr("提示"), QString(tr("删除成功。")));
|
// QMessageBox::information(this, tr("提示"), QString(tr("删除成功。")));
|
||||||
ui->tableWidget->removeRow(datas[0]->row());
|
ui->tableWidget->removeRow(datas[0]->row());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -759,7 +831,7 @@ void FileManager::OperRename()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 检查结果
|
// 检查结果
|
||||||
auto msg = oper.GetMsg();
|
auto msg = oper.GetMsgConst();
|
||||||
if (msg.msg == STR_NONE || !msg.msg.isEmpty()) {
|
if (msg.msg == STR_NONE || !msg.msg.isEmpty()) {
|
||||||
QMessageBox::information(this, tr("提示"), QString(tr("重命名失败=>%1")).arg(msg.msg));
|
QMessageBox::information(this, tr("提示"), QString(tr("重命名失败=>%1")).arg(msg.msg));
|
||||||
} else {
|
} else {
|
||||||
@@ -825,80 +897,3 @@ void FileManager::doubleClick(int row, int column)
|
|||||||
QString np = dir.filePath(item->text());
|
QString np = dir.filePath(item->text());
|
||||||
fileHelper_->GetDirFile(np);
|
fileHelper_->GetDirFile(np);
|
||||||
}
|
}
|
||||||
|
|
||||||
WaitOper::WaitOper(QObject* parent) : WaitThread(parent)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitOper::run()
|
|
||||||
{
|
|
||||||
isAlreadyInter_ = false;
|
|
||||||
infoMsg_.msg = STR_NONE;
|
|
||||||
isRun_ = true;
|
|
||||||
recvMsg_ = false;
|
|
||||||
|
|
||||||
InfoMsg msg;
|
|
||||||
msg.command = sendStrType_;
|
|
||||||
msg.fromPath = stra_;
|
|
||||||
msg.toPath = strb_;
|
|
||||||
msg.type = type_;
|
|
||||||
|
|
||||||
auto f = cli_->GetBuffer<InfoMsg>(msg, FBT_MSGINFO_ASK, cli_->GetRemoteID());
|
|
||||||
if (!ClientCore::syncInvoke(cli_, f)) {
|
|
||||||
auto errMsg = QString(tr("向%1发送%2请求失败。")).arg(cli_->GetRemoteID()).arg(sendStrType_);
|
|
||||||
emit sigCheckOver();
|
|
||||||
qCritical() << errMsg;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
while (isRun_) {
|
|
||||||
QThread::msleep(1);
|
|
||||||
if (isAlreadyInter_) {
|
|
||||||
qInfo() << tr("线程中断文件操作等待......");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!recvMsg_) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
isAlreadyInter_ = true;
|
|
||||||
emit sigCheckOver();
|
|
||||||
auto n = QString(tr("向%1的请求%2处理结束。")).arg(cli_->GetRemoteID()).arg(sendStrType_);
|
|
||||||
qInfo() << n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitOper::SetType(const QString& sendType, const QString& ansType)
|
|
||||||
{
|
|
||||||
sendStrType_ = sendType;
|
|
||||||
ansStrType_ = ansType;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitOper::SetPath(const QString& stra, const QString& strb, const QString& type)
|
|
||||||
{
|
|
||||||
stra_ = stra;
|
|
||||||
strb_ = strb;
|
|
||||||
type_ = type;
|
|
||||||
}
|
|
||||||
|
|
||||||
InfoMsg WaitOper::GetMsg() const
|
|
||||||
{
|
|
||||||
return infoMsg_;
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitOper::interrupCheck()
|
|
||||||
{
|
|
||||||
qWarning() << QString(tr("中断请求处理%1......")).arg(sendStrType_);
|
|
||||||
WaitThread::interrupCheck();
|
|
||||||
}
|
|
||||||
|
|
||||||
void WaitOper::recvFrame(QSharedPointer<FrameBuffer> frame)
|
|
||||||
{
|
|
||||||
InfoMsg info = infoUnpack<InfoMsg>(frame->data);
|
|
||||||
if (info.command == ansStrType_) {
|
|
||||||
infoMsg_ = info;
|
|
||||||
recvMsg_ = true;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
auto n = tr("收到未知Oper的回复信息:") + info.command;
|
|
||||||
qInfo() << n;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -28,29 +28,6 @@ enum class SortMethod {
|
|||||||
SMD_BY_SIZE_ASC,
|
SMD_BY_SIZE_ASC,
|
||||||
};
|
};
|
||||||
|
|
||||||
class WaitOper : public WaitThread
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
WaitOper(QObject* parent = nullptr);
|
|
||||||
|
|
||||||
public:
|
|
||||||
void run() override;
|
|
||||||
void SetType(const QString& sendType, const QString& ansType);
|
|
||||||
void SetPath(const QString& stra, const QString& strb, const QString& type);
|
|
||||||
InfoMsg GetMsg() const;
|
|
||||||
void interrupCheck() override;
|
|
||||||
void recvFrame(QSharedPointer<FrameBuffer> frame) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
bool recvMsg_{};
|
|
||||||
InfoMsg infoMsg_{};
|
|
||||||
QString sendStrType_{};
|
|
||||||
QString ansStrType_{};
|
|
||||||
QString stra_;
|
|
||||||
QString strb_;
|
|
||||||
QString type_;
|
|
||||||
};
|
|
||||||
|
|
||||||
class FileManager : public QWidget
|
class FileManager : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QListWidgetItem>
|
#include <QListWidgetItem>
|
||||||
|
#include <QMessageBox>
|
||||||
#include <QStandardItem>
|
#include <QStandardItem>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
@@ -25,6 +26,15 @@ void LogPrint::InitControl()
|
|||||||
connect(styleHints_, &QStyleHints::colorSchemeChanged, this, &LogPrint::ColorChange);
|
connect(styleHints_, &QStyleHints::colorSchemeChanged, this, &LogPrint::ColorChange);
|
||||||
#endif
|
#endif
|
||||||
ui->pedText->setReadOnly(true);
|
ui->pedText->setReadOnly(true);
|
||||||
|
|
||||||
|
connect(ui->btnClear, &QPushButton::clicked, [this]() {
|
||||||
|
QMessageBox::StandardButton reply = QMessageBox::question(this, tr("确认清空"), tr("确定要清空所有内容吗?"),
|
||||||
|
QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
|
||||||
|
|
||||||
|
if (reply == QMessageBox::Yes) {
|
||||||
|
ui->pedText->clear();
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string LogPrint::now_str()
|
std::string LogPrint::now_str()
|
||||||
|
|||||||
@@ -6,8 +6,8 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>767</width>
|
<width>831</width>
|
||||||
<height>291</height>
|
<height>396</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
@@ -17,6 +17,33 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QPlainTextEdit" name="pedText"/>
|
<widget class="QPlainTextEdit" name="pedText"/>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<spacer name="verticalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Orientation::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeType">
|
||||||
|
<enum>QSizePolicy::Policy::Expanding</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>20</width>
|
||||||
|
<height>60</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QPushButton" name="btnClear">
|
||||||
|
<property name="text">
|
||||||
|
<string>清空</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|||||||
102
Note/version.md
102
Note/version.md
@@ -6,51 +6,57 @@
|
|||||||
|
|
||||||
## 问题清单:
|
## 问题清单:
|
||||||
|
|
||||||
| 序号 | 类型 | 内容 | 说明 | 基于版本 | 完成版本 |
|
| 序号 | 类型 | 内容 | 说明 | 基于版本 | 完成版本 |
|
||||||
| :--: | :--: | ------------------------------------------------------------ | :----: | :------: | :------: |
|
| :--: | :--: | ------------------------------------------------------------ | :------------: | :------: | :------: |
|
||||||
| 46 | 功能 | 需要一个压缩传输功能。 | | 0.2.4 | |
|
| 52 | 问题 | 发送大文件时,UI有不流畅现象。 | 完成版本待观察 | 0.2.6 | |
|
||||||
| 45 | 问题 | 出现过重连后无法刷新客户端列表问题。 | 偶发 | 0.2.4 | |
|
| 51 | 问题 | 按照类型传输时,类型重复的问题修正 | | 0.2.5 | 0.2.6 |
|
||||||
| 44 | 问题 | 出现过多选下载显示远程文件不存在问题,但是单个下没问题。 | 偶发 | 0.2.4 | |
|
| 50 | 功能 | 添加日志内容清空按钮。 | | 0.2.4 | 0.2.5 |
|
||||||
| 43 | 问题 | 资源占用过多问题。 | | 0.2.3 | 0.2.4 |
|
| 49 | 功能 | 对照传输支持按照类型传输。 | | 0.2.4 | 0.2.5 |
|
||||||
| 42 | 优化 | 访问文件过多时,界面有卡顿情况。 | | 0.2.3 | 0.2.4 |
|
| 48 | 优化 | 选择上传下载移动到右键菜单中。 | | 0.2.4 | 0.2.5 |
|
||||||
| 41 | 问题 | 主动中断检查等待后,软件崩溃。 | | 0.2.3 | 0.2.4 |
|
| 47 | 优化 | 删除新建文件(夹)成功时不提示。 | | 0.2.4 | 0.2.5 |
|
||||||
| 40 | 问题 | 上传方完成后,接收端未接收完毕不能退出的问题。 | | 0.2.3 | 0.2.4 |
|
| 46 | 功能 | 需要一个压缩传输功能。 | | 0.2.4 | |
|
||||||
| 39 | 优化 | Console端断联后应当自动退出。 | | 0.2.3 | 0.2.4 |
|
| 45 | 问题 | 出现过重连后无法刷新客户端列表问题。 | 偶发 | 0.2.4 | |
|
||||||
| 38 | 功能 | PE中使用没有拖拽功能,文件管理器要有下载/上传按钮。 | | 0.2.3 | 0.2.4 |
|
| 44 | 问题 | 出现过多选下载显示远程文件不存在问题,但是单个下没问题。 | 偶发 | 0.2.4 | |
|
||||||
| 37 | 问题 | 未连接对方客户端时,执行对照传输会崩溃。 | 待复现 | 0.2.3 | |
|
| 43 | 问题 | 资源占用过多问题。 | | 0.2.3 | 0.2.4 |
|
||||||
| 36 | 功能 | 备份文件功能。 | | 0.2.3 | |
|
| 42 | 优化 | 访问文件过多时,界面有卡顿情况。 | | 0.2.3 | 0.2.4 |
|
||||||
| 35 | 功能 | 完善对照功能的界面其他内容。 | | 0.2.3 | |
|
| 41 | 问题 | 主动中断检查等待后,软件崩溃。 | | 0.2.3 | 0.2.4 |
|
||||||
| 34 | 功能 | 支持删除、重命名、新建文件(夹)。 | | 0.2.3 | 0.2.4 |
|
| 40 | 问题 | 上传方完成后,接收端未接收完毕不能退出的问题。 | | 0.2.3 | 0.2.4 |
|
||||||
| 33 | 功能 | 弹窗查看文件(夹)属性窗口。 | | 0.2.3 | 0.2.4 |
|
| 39 | 优化 | Console端断联后应当自动退出。 | | 0.2.3 | 0.2.4 |
|
||||||
| 32 | 功能 | 路径选择显示驱动器。 | | 0.2.2 | 0.2.3 |
|
| 38 | 功能 | PE中使用没有拖拽功能,文件管理器要有下载/上传按钮。 | | 0.2.3 | 0.2.4 |
|
||||||
| 31 | 功能 | Server端buffer大小判断,有过多无效数据则踢出该客户端。 | | 0.2.2 | 0.2.4 |
|
| 37 | 问题 | 未连接对方客户端时,执行对照传输会崩溃。 | 待复现 | 0.2.3 | |
|
||||||
| 30 | 功能 | 传输界面的取消退出,缺失功能处理。 | | 0.2.2 | 0.2.3 |
|
| 36 | 功能 | 备份文件功能。 | | 0.2.3 | |
|
||||||
| 29 | 功能 | 根据接收端的速率限制发送端的速度。 | | 0.2.2 | 0.2.3 |
|
| 35 | 功能 | 完善对照功能的界面其他内容。 | | 0.2.3 | |
|
||||||
| 28 | 变更 | 语言简体中文。 | | 0.2.2 | 0.2.3 |
|
| 34 | 功能 | 支持删除、重命名、新建文件(夹)。 | | 0.2.3 | 0.2.4 |
|
||||||
| 27 | 功能 | 传输前检查对方或者自己是否已存在某些文件,提示是否覆盖。 | | 0.2.2 | 0.2.3 |
|
| 33 | 功能 | 弹窗查看文件(夹)属性窗口。 | | 0.2.3 | 0.2.4 |
|
||||||
| 26 | 功能 | 最好能保存关闭界面时Splitter和UI的尺寸。 | | 0.2.2 | |
|
| 32 | 功能 | 路径选择显示驱动器。 | | 0.2.2 | 0.2.3 |
|
||||||
| 25 | 功能 | 手动输入的文件夹访问路径保存历史记录,以便后续可能再次使用(10条)。 | | 0.2.2 | |
|
| 31 | 功能 | Server端buffer大小判断,有过多无效数据则踢出该客户端。 | | 0.2.2 | 0.2.4 |
|
||||||
| 24 | 问题 | 发送端如果发送的数据比较大,UI会卡住(功能是正常的)。 | | 0.2.2 | 0.2.3 |
|
| 30 | 功能 | 传输界面的取消退出,缺失功能处理。 | | 0.2.2 | 0.2.3 |
|
||||||
| 23 | 问题 | 作为接收端如果对方断联要处理这个情况。 | | 0.2.2 | 0.2.3 |
|
| 29 | 功能 | 根据接收端的速率限制发送端的速度。 | | 0.2.2 | 0.2.3 |
|
||||||
| 22 | 功能 | 配置可以切组。 | | 0.2.2 | |
|
| 28 | 变更 | 语言简体中文。 | | 0.2.2 | 0.2.3 |
|
||||||
| 21 | 功能 | 可以传输文件夹。 | | 0.2.2 | |
|
| 27 | 功能 | 传输前检查对方或者自己是否已存在某些文件,提示是否覆盖。 | | 0.2.2 | 0.2.3 |
|
||||||
| 20 | 功能 | 对照传输可以打开本地文件夹。 | | 0.2.2 | 0.2.3 |
|
| 26 | 功能 | 最好能保存关闭界面时Splitter和UI的尺寸。 | | 0.2.2 | |
|
||||||
| 19 | 问题 | 客户之间心跳包,被动/主动失联后断开,清除相关内容,终止相关任务。 | | 0.2.2 | 0.2.3 |
|
| 25 | 功能 | 手动输入的文件夹访问路径保存历史记录,以便后续可能再次使用(10条)。 | | 0.2.2 | |
|
||||||
| 18 | 问题 | 断开后重连貌似没有发送心跳包。 | | 0.1 | 0.2 |
|
| 24 | 问题 | 发送端如果发送的数据比较大,UI会卡住(功能是正常的)。 | | 0.2.2 | 0.2.3 |
|
||||||
| 17 | 问题 | 服务端主动踢出的客户端,主动重连假链接,不可用无反应。 | | 0.1 | 0.2 |
|
| 23 | 问题 | 作为接收端如果对方断联要处理这个情况。 | | 0.2.2 | 0.2.3 |
|
||||||
| 16 | 优化 | 传输完成后接收端要刷新一次。 | | 0.1 | |
|
| 22 | 功能 | 配置可以切组。 | | 0.2.2 | |
|
||||||
| 15 | 问题 | 拖动文件夹到对方,应当不处理,并日志提示。 | | 0.1 | 0.2 |
|
| 21 | 功能 | 可以传输文件夹。 | | 0.2.2 | |
|
||||||
| 14 | 功能 | 文件浏览部分添加右键复制全路径功能。 | | 0.1 | 0.2 |
|
| 20 | 功能 | 对照传输可以打开本地文件夹。 | | 0.2.2 | 0.2.3 |
|
||||||
| 13 | 功能 | IP端口部分要添加可选择历史。 | | 0.1 | 0.2 |
|
| 19 | 问题 | 客户之间心跳包,被动/主动失联后断开,清除相关内容,终止相关任务。 | | 0.2.2 | 0.2.3 |
|
||||||
| 12 | 功能 | 对照传输前要先校验文件存在性。 | | 0.1 | 0.2.3 |
|
| 18 | 问题 | 断开后重连貌似没有发送心跳包。 | | 0.1 | 0.2 |
|
||||||
| 11 | 问题 | 断连后当前远端ID要清除。 | | 0.1 | 0.2 |
|
| 17 | 问题 | 服务端主动踢出的客户端,主动重连假链接,不可用无反应。 | | 0.1 | 0.2 |
|
||||||
| 10 | 功能 | 对照传输可以支持反向下载。 | | 0.1 | 0.2 |
|
| 16 | 优化 | 传输完成后接收端要刷新一次。 | | 0.1 | |
|
||||||
| 9 | 优化 | 输入路径后可以直接回车访问。 | | 0.1 | 0.2 |
|
| 15 | 问题 | 拖动文件夹到对方,应当不处理,并日志提示。 | | 0.1 | 0.2 |
|
||||||
| 8 | 功能 | 文件浏览页面要支持按照类型排序,时间排序,和文件后缀筛选。 | | 0.1 | 0.2 |
|
| 14 | 功能 | 文件浏览部分添加右键复制全路径功能。 | | 0.1 | 0.2 |
|
||||||
| 7 | 优化 | IP和Port宽度要合理一些,IP过小,Port宽度过大。 | | 0.1 | 0.2 |
|
| 13 | 功能 | IP端口部分要添加可选择历史。 | | 0.1 | 0.2 |
|
||||||
| 6 | 功能 | 比对控件添加可尝试目录浏览控件跳转到指定目录。 | | 0.1 | 0.2 |
|
| 12 | 功能 | 对照传输前要先校验文件存在性。 | | 0.1 | 0.2.3 |
|
||||||
| 5 | 问题 | 未设置心跳包,导致超时被Server端踢出。 | 必改 | 0.1 | 0.2 |
|
| 11 | 问题 | 断连后当前远端ID要清除。 | | 0.1 | 0.2 |
|
||||||
| 4 | 问题 | 重复链接Server会崩溃。 | | 0.1 | 0.2 |
|
| 10 | 功能 | 对照传输可以支持反向下载。 | | 0.1 | 0.2 |
|
||||||
| 3 | 优化 | 首次启动时应当按照当前分辨率进行初始化大小,而不是指定大小。 | | 0.1 | 0.2 |
|
| 9 | 优化 | 输入路径后可以直接回车访问。 | | 0.1 | 0.2 |
|
||||||
| 2 | 问题 | 当某个文件传输失败的时候,关闭传输窗口,再次传输显示已经在传输中。 | | 0.1 | 0.2.3 |
|
| 8 | 功能 | 文件浏览页面要支持按照类型排序,时间排序,和文件后缀筛选。 | | 0.1 | 0.2 |
|
||||||
| 1 | 问题 | Console端显示未注册QSharedPointer\<FrameBuffer\>类型 | | 0.1 | 0.2 |
|
| 7 | 优化 | IP和Port宽度要合理一些,IP过小,Port宽度过大。 | | 0.1 | 0.2 |
|
||||||
|
| 6 | 功能 | 比对控件添加可尝试目录浏览控件跳转到指定目录。 | | 0.1 | 0.2 |
|
||||||
|
| 5 | 问题 | 未设置心跳包,导致超时被Server端踢出。 | 必改 | 0.1 | 0.2 |
|
||||||
|
| 4 | 问题 | 重复链接Server会崩溃。 | | 0.1 | 0.2 |
|
||||||
|
| 3 | 优化 | 首次启动时应当按照当前分辨率进行初始化大小,而不是指定大小。 | | 0.1 | 0.2 |
|
||||||
|
| 2 | 问题 | 当某个文件传输失败的时候,关闭传输窗口,再次传输显示已经在传输中。 | | 0.1 | 0.2.3 |
|
||||||
|
| 1 | 问题 | Console端显示未注册QSharedPointer\<FrameBuffer\>类型 | | 0.1 | 0.2 |
|
||||||
|
|||||||
@@ -102,10 +102,14 @@ enum FileCheckState {
|
|||||||
#define STRMSG_AC_UP "upAction"
|
#define STRMSG_AC_UP "upAction"
|
||||||
#define STRMSG_AC_DOWN "downAction"
|
#define STRMSG_AC_DOWN "downAction"
|
||||||
|
|
||||||
|
#define STRMSG_AC_ALL_DIRFILES "askAllDirFiles"
|
||||||
|
#define STRMSG_AC_ANSWER_ALL_DIRFILES "answerAllDirFiles"
|
||||||
|
|
||||||
#define STRMSG_ST_FILEEXIT "fileExist"
|
#define STRMSG_ST_FILEEXIT "fileExist"
|
||||||
#define STRMSG_ST_FILENOEXIT "fileNotExist"
|
#define STRMSG_ST_FILENOEXIT "fileNotExist"
|
||||||
#define STRMSG_ST_DIREXIT "dirExist"
|
#define STRMSG_ST_DIREXIT "dirExist"
|
||||||
#define STRMSG_ST_DIRNOEXIT "dirNotExist"
|
#define STRMSG_ST_DIRNOEXIT "dirNotExist"
|
||||||
|
#define STRMSG_ST_COMMAND_ALREADY_RUNNING "commandAlreadyRunning"
|
||||||
|
|
||||||
#define STR_FILE "File"
|
#define STR_FILE "File"
|
||||||
#define STR_DIR "Dir"
|
#define STR_DIR "Dir"
|
||||||
|
|||||||
@@ -19,9 +19,9 @@
|
|||||||
|
|
||||||
## 示例图
|
## 示例图
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
## 注意事项
|
## 注意事项
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
@echo on
|
@echo on
|
||||||
|
|
||||||
set QT_DIR=C:/Qt/6.8.3/mingw_64
|
set QT_DIR=C:/local/qt6
|
||||||
cd ..
|
cd ..
|
||||||
cmake -G "MinGW Makefiles" -Bbuild-qt6 -S. -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=%QT_DIR% -DQT_DEFAULT_MAJOR_VERSION=6 -DCOMPILE_GUI=ON -DRELEASE_MARK=ON
|
cmake -G "MinGW Makefiles" -Bbuild-qt6 -S. -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH=%QT_DIR% -DQT_DEFAULT_MAJOR_VERSION=6 -DCOMPILE_GUI=ON -DRELEASE_MARK=ON
|
||||||
cmake --build build-qt6 --config Release
|
cmake --build build-qt6 --config Release
|
||||||
|
|||||||
@@ -8,6 +8,12 @@
|
|||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QVector>
|
#include <QVector>
|
||||||
|
|
||||||
|
struct FileStruct {
|
||||||
|
QString root;
|
||||||
|
QString mid;
|
||||||
|
QString relative;
|
||||||
|
};
|
||||||
|
|
||||||
struct PropertyData {
|
struct PropertyData {
|
||||||
QString uuid;
|
QString uuid;
|
||||||
QString command;
|
QString command;
|
||||||
@@ -27,21 +33,40 @@ struct InfoMsg {
|
|||||||
QString type;
|
QString type;
|
||||||
quint64 size{};
|
quint64 size{};
|
||||||
quint32 permissions{};
|
quint32 permissions{};
|
||||||
|
QVector<QString> listSend;
|
||||||
QVector<QString> list;
|
QVector<QString> list;
|
||||||
QMap<QString, PropertyData> mapData;
|
QMap<QString, PropertyData> mapData;
|
||||||
|
FileStruct fst;
|
||||||
|
QMap<QString, QVector<FileStruct>> infos;
|
||||||
|
|
||||||
void serialize(QDataStream& data) const
|
void serialize(QDataStream& data) const
|
||||||
{
|
{
|
||||||
data << mark << command << msg << fromPath << toPath << type << size << permissions;
|
data << mark << command << msg << fromPath << toPath << type << size << permissions;
|
||||||
|
|
||||||
|
data << static_cast<qint32>(listSend.size());
|
||||||
|
for (const auto& item : listSend) {
|
||||||
|
data << item;
|
||||||
|
}
|
||||||
|
|
||||||
data << static_cast<qint32>(list.size());
|
data << static_cast<qint32>(list.size());
|
||||||
for (const auto& item : list) {
|
for (const auto& item : list) {
|
||||||
data << item;
|
data << item;
|
||||||
}
|
}
|
||||||
|
|
||||||
data << static_cast<qint32>(mapData.size());
|
data << static_cast<qint32>(mapData.size());
|
||||||
for (auto it = mapData.constBegin(); it != mapData.constEnd(); ++it) {
|
for (auto it = mapData.constBegin(); it != mapData.constEnd(); ++it) {
|
||||||
data << it.key();
|
data << it.key();
|
||||||
data << it.value().uuid << it.value().command << it.value().userAction
|
data << it.value().uuid << it.value().command << it.value().userAction << it.value().localPath
|
||||||
<< it.value().localPath << it.value().remotePath << it.value().state << it.value().properE;
|
<< it.value().remotePath << it.value().state << it.value().properE;
|
||||||
|
}
|
||||||
|
data << fst.root << fst.mid << fst.relative;
|
||||||
|
data << static_cast<qint32>(infos.size());
|
||||||
|
for (auto it = infos.constBegin(); it != infos.constEnd(); ++it) {
|
||||||
|
data << it.key();
|
||||||
|
data << static_cast<qint32>(it.value().size());
|
||||||
|
for (const auto& fileStruct : it.value()) {
|
||||||
|
data << fileStruct.root << fileStruct.mid << fileStruct.relative;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -50,6 +75,12 @@ struct InfoMsg {
|
|||||||
data >> mark >> command >> msg >> fromPath >> toPath >> type >> size >> permissions;
|
data >> mark >> command >> msg >> fromPath >> toPath >> type >> size >> permissions;
|
||||||
|
|
||||||
qint32 listSize;
|
qint32 listSize;
|
||||||
|
data >> listSize;
|
||||||
|
listSend.resize(listSize);
|
||||||
|
for (auto& item : listSend) {
|
||||||
|
data >> item;
|
||||||
|
}
|
||||||
|
|
||||||
data >> listSize;
|
data >> listSize;
|
||||||
list.resize(listSize);
|
list.resize(listSize);
|
||||||
for (auto& item : list) {
|
for (auto& item : list) {
|
||||||
@@ -63,10 +94,28 @@ struct InfoMsg {
|
|||||||
QString key;
|
QString key;
|
||||||
PropertyData prop;
|
PropertyData prop;
|
||||||
data >> key;
|
data >> key;
|
||||||
data >> prop.uuid >> prop.command >> prop.userAction >> prop.localPath
|
data >> prop.uuid >> prop.command >> prop.userAction >> prop.localPath >> prop.remotePath >> prop.state >>
|
||||||
>> prop.remotePath >> prop.state >> prop.properE;
|
prop.properE;
|
||||||
mapData.insert(key, prop);
|
mapData.insert(key, prop);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data >> fst.root >> fst.mid >> fst.relative;
|
||||||
|
|
||||||
|
data >> mapSize;
|
||||||
|
infos.clear();
|
||||||
|
for (int i = 0; i < mapSize; ++i) {
|
||||||
|
QString key;
|
||||||
|
data >> key;
|
||||||
|
|
||||||
|
qint32 vectorSize;
|
||||||
|
data >> vectorSize;
|
||||||
|
QVector<FileStruct> fileVector;
|
||||||
|
fileVector.resize(vectorSize);
|
||||||
|
for (int j = 0; j < vectorSize; ++j) {
|
||||||
|
data >> fileVector[j].root >> fileVector[j].mid >> fileVector[j].relative;
|
||||||
|
}
|
||||||
|
infos.insert(key, fileVector);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
QDataStream& operator<<(QDataStream& data, const InfoMsg& info);
|
QDataStream& operator<<(QDataStream& data, const InfoMsg& info);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <QCoreApplication>
|
#include <QCoreApplication>
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <Util.h>
|
||||||
|
|
||||||
void DateTimeTest()
|
void DateTimeTest()
|
||||||
{
|
{
|
||||||
@@ -14,5 +15,8 @@ int main(int argc, char** argv)
|
|||||||
qDebug() << "Running...";
|
qDebug() << "Running...";
|
||||||
DateTimeTest();
|
DateTimeTest();
|
||||||
|
|
||||||
|
QVector<QString> files;
|
||||||
|
DirFileHelper::GetAllFiles("D:/备份软件", files);
|
||||||
|
|
||||||
return app.exec();
|
return app.exec();
|
||||||
}
|
}
|
||||||
@@ -21,4 +21,4 @@ add_executable(frelayTest ${MSOURCES})
|
|||||||
target_link_libraries(frelayTest PRIVATE Protocol Util)
|
target_link_libraries(frelayTest PRIVATE Protocol Util)
|
||||||
|
|
||||||
add_executable(frelayBaseTest BaseTest.cpp)
|
add_executable(frelayBaseTest BaseTest.cpp)
|
||||||
target_link_libraries(frelayBaseTest Qt${QT_VERSION_MAJOR}::Core)
|
target_link_libraries(frelayBaseTest Qt${QT_VERSION_MAJOR}::Core Util Protocol)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QDirIterator>
|
||||||
#include <QFileDevice>
|
#include <QFileDevice>
|
||||||
#include <QFileInfo>
|
#include <QFileInfo>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
@@ -70,6 +71,11 @@ QString Util::Join(const QString& path, const QString& name)
|
|||||||
return QDir::cleanPath(path + QDir::separator() + name);
|
return QDir::cleanPath(path + QDir::separator() + name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Util::Join(const QString& path, const QString& mid, const QString& name)
|
||||||
|
{
|
||||||
|
return QDir::cleanPath(path + QDir::separator() + mid + QDir::separator() + name);
|
||||||
|
}
|
||||||
|
|
||||||
void Util::InitLogger(const QString& logPath, const QString& mark)
|
void Util::InitLogger(const QString& logPath, const QString& mark)
|
||||||
{
|
{
|
||||||
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logPath.toStdString(), 1024 * 1024 * 50, 3);
|
auto file_sink = std::make_shared<spdlog::sinks::rotating_file_sink_mt>(logPath.toStdString(), 1024 * 1024 * 50, 3);
|
||||||
@@ -82,6 +88,12 @@ void Util::InitLogger(const QString& logPath, const QString& mark)
|
|||||||
spdlog::register_logger(logger);
|
spdlog::register_logger(logger);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Util::GetFileDir(const QString& path)
|
||||||
|
{
|
||||||
|
QFileInfo fileInfo(path);
|
||||||
|
return fileInfo.absolutePath();
|
||||||
|
}
|
||||||
|
|
||||||
// do not check exit
|
// do not check exit
|
||||||
QString Util::Get2FilePath(const QString& file, const QString& directory)
|
QString Util::Get2FilePath(const QString& file, const QString& directory)
|
||||||
{
|
{
|
||||||
@@ -177,7 +189,7 @@ QVector<QString> Util::GetLocalDrivers()
|
|||||||
{
|
{
|
||||||
QVector<QString> result;
|
QVector<QString> result;
|
||||||
auto drivers = QStorageInfo::mountedVolumes();
|
auto drivers = QStorageInfo::mountedVolumes();
|
||||||
for (const auto& driver : drivers) {
|
for (const auto& driver : std::as_const(drivers)) {
|
||||||
if (driver.isValid() && driver.isReady()) {
|
if (driver.isValid() && driver.isReady()) {
|
||||||
result.push_back(driver.rootPath());
|
result.push_back(driver.rootPath());
|
||||||
}
|
}
|
||||||
@@ -190,6 +202,65 @@ QString DirFileHelper::GetErr() const
|
|||||||
return QString();
|
return QString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DirFileHelper::GetAllFiles(const QString& rootPath, QVector<QString>& files)
|
||||||
|
{
|
||||||
|
QDir rootDir(rootPath);
|
||||||
|
|
||||||
|
if (!rootDir.exists()) {
|
||||||
|
qWarning() << "目录不存在:" << rootPath;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString absoluteRootPath = rootDir.absolutePath();
|
||||||
|
QDirIterator it(absoluteRootPath, QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
QFileInfo fileInfo = it.fileInfo();
|
||||||
|
if (fileInfo.isFile()) {
|
||||||
|
QString absoluteFilePath = fileInfo.absoluteFilePath();
|
||||||
|
QString relativePath = absoluteFilePath.mid(absoluteRootPath.length());
|
||||||
|
if (relativePath.startsWith('/') || relativePath.startsWith('\\')) {
|
||||||
|
relativePath = relativePath.mid(1);
|
||||||
|
}
|
||||||
|
files.append(relativePath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DirFileHelper::GetAllFiles(const QString& rootPath, const QString& mid, QVector<FileStruct>& files)
|
||||||
|
{
|
||||||
|
auto fileRoot = Util::Join(rootPath, mid);
|
||||||
|
QDir rootDir(fileRoot);
|
||||||
|
|
||||||
|
if (!rootDir.exists()) {
|
||||||
|
qWarning() << "目录不存在:" << fileRoot;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString absoluteRootPath = rootDir.absolutePath();
|
||||||
|
QDirIterator it(absoluteRootPath, QDir::Files | QDir::NoSymLinks | QDir::NoDotAndDotDot, QDirIterator::Subdirectories);
|
||||||
|
|
||||||
|
while (it.hasNext()) {
|
||||||
|
it.next();
|
||||||
|
QFileInfo fileInfo = it.fileInfo();
|
||||||
|
if (fileInfo.isFile()) {
|
||||||
|
QString absoluteFilePath = fileInfo.absoluteFilePath();
|
||||||
|
QString relativePath = absoluteFilePath.mid(absoluteRootPath.length());
|
||||||
|
if (relativePath.startsWith('/') || relativePath.startsWith('\\')) {
|
||||||
|
relativePath = relativePath.mid(1);
|
||||||
|
}
|
||||||
|
FileStruct fst;
|
||||||
|
fst.root = rootPath;
|
||||||
|
fst.mid = mid;
|
||||||
|
fst.relative = relativePath;
|
||||||
|
files.append(fst);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
DirFileHelper::DirFileHelper(QObject* parent) : QObject(parent)
|
DirFileHelper::DirFileHelper(QObject* parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
#define UTIL_H
|
#define UTIL_H
|
||||||
|
|
||||||
#include <InfoDirFile.h>
|
#include <InfoDirFile.h>
|
||||||
|
#include <InfoMsg.h>
|
||||||
#include <QMutex>
|
#include <QMutex>
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
@@ -45,7 +46,9 @@ public:
|
|||||||
static QString GetUserHome();
|
static QString GetUserHome();
|
||||||
static void InitLogger(const QString& logPath, const QString& mark);
|
static void InitLogger(const QString& logPath, const QString& mark);
|
||||||
static QString Get2FilePath(const QString& file, const QString& directory);
|
static QString Get2FilePath(const QString& file, const QString& directory);
|
||||||
|
static QString GetFileDir(const QString& path);
|
||||||
static QString Join(const QString& path, const QString& name);
|
static QString Join(const QString& path, const QString& name);
|
||||||
|
static QString Join(const QString& path, const QString& mid, const QString& name);
|
||||||
static QString GetCurConfigPath(const QString& sub);
|
static QString GetCurConfigPath(const QString& sub);
|
||||||
static void ConsoleMsgHander(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
static void ConsoleMsgHander(QtMsgType type, const QMessageLogContext& context, const QString& msg);
|
||||||
static QString GetVersion();
|
static QString GetVersion();
|
||||||
@@ -67,6 +70,8 @@ public:
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
QString GetErr() const;
|
QString GetErr() const;
|
||||||
|
static bool GetAllFiles(const QString& rootPath, QVector<QString>& files);
|
||||||
|
static bool GetAllFiles(const QString& rootPath, const QString& mid, QVector<FileStruct>& files);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void sigHome(const QString& path, const QVector<QString>& drivers);
|
void sigHome(const QString& path, const QVector<QString>& drivers);
|
||||||
|
|||||||
Reference in New Issue
Block a user