From a53657df301e29ac267fb223bfe68202f3ba5e6d Mon Sep 17 00:00:00 2001 From: taynpg Date: Wed, 18 Jun 2025 14:53:56 +0800 Subject: [PATCH] update: add dray trigger task. --- ClientCore/ClientCore.cpp | 5 ++ ClientCore/ClientCore.h | 1 + ClientCore/FileTrans.cpp | 108 +++++++++++++++++++++------------ ClientCore/FileTrans.h | 7 +-- Gui/Control/FileControl.cpp | 17 ++++-- Gui/Control/FileControl.h | 3 + Gui/Control/cusTableWidget.cpp | 62 +++++++++++++++++-- Gui/Control/cusTableWidget.h | 18 +++++- Gui/Form/Transform.cpp | 74 +++++++++++++++++++++- Gui/Form/Transform.h | 38 +++++++++++- Gui/frelayGUI.cpp | 6 +- README.md | 6 +- Util/Util.cpp | 5 ++ Util/Util.h | 1 + 14 files changed, 289 insertions(+), 62 deletions(-) diff --git a/ClientCore/ClientCore.cpp b/ClientCore/ClientCore.cpp index 9a1fd16..9cba6b4 100644 --- a/ClientCore/ClientCore.cpp +++ b/ClientCore/ClientCore.cpp @@ -164,3 +164,8 @@ QString ClientCore::GetRemoteID() { return remoteID_; } + +QString ClientCore::GetOwnID() +{ + return ownID_; +} diff --git a/ClientCore/ClientCore.h b/ClientCore/ClientCore.h index 0689e85..7d4fddf 100644 --- a/ClientCore/ClientCore.h +++ b/ClientCore/ClientCore.h @@ -51,6 +51,7 @@ public: void SetFrameCall(FrameBufferType type, const std::function)>& call); void SetRemoteID(const QString& id); QString GetRemoteID(); + QString GetOwnID(); public: QMutex conMutex_; diff --git a/ClientCore/FileTrans.cpp b/ClientCore/FileTrans.cpp index 67b21d9..459ceaf 100644 --- a/ClientCore/FileTrans.cpp +++ b/ClientCore/FileTrans.cpp @@ -1,9 +1,12 @@ #include "FileTrans.h" + #include FileTrans::FileTrans(ClientCore* clientCore) : clientCore_(clientCore) { RegisterFrameCall(); + downTask_ = QSharedPointer::create(); + sendTask_ = QSharedPointer::create(); } /* @@ -21,24 +24,33 @@ void FileTrans::ReqSendFile(const TransTask& task) info.toPath = task.remotePath; info.fromPath = task.localPath; + sendTask_->file.setFileName(info.fromPath); + if (!sendTask_->file.open(QIODevice::ReadOnly)) { + qCritical() << QString(tr("open file [%1] failed.")).arg(info.fromPath); + sendTask_->state = TaskState::STATE_NONE; + return; + } + QFileInfo fileInfo(info.fromPath); if (fileInfo.exists()) { qint64 size = fileInfo.size(); info.permissions = static_cast(fileInfo.permissions()); info.size = size; } else { - sigError(QString(tr("File [%1] not exit.")).arg(info.fromPath)); + qCritical() << QString(tr("File [%1] not exit.")).arg(info.fromPath); + sendTask_->file.close(); return; } - + if (!clientCore_->Send(info, FBT_CLI_REQ_SEND, task.remoteId)) { - sigError(QString(tr("send req send failed: %1")).arg(info.msg)); - sendTask_.state = TaskState::STATE_NONE; + qCritical() << QString(tr("send req send failed: %1")).arg(info.msg); + sendTask_->state = TaskState::STATE_NONE; + sendTask_->file.close(); return; - } - sendTask_.state = TaskState::STATE_RUNNING; - sendTask_.totalSize = info.size; - sendTask_.tranSize = 0; + } + sendTask_->state = TaskState::STATE_RUNNING; + sendTask_->totalSize = info.size; + sendTask_->tranSize = 0; } void FileTrans::ReqDownFile(const TransTask& task) @@ -50,31 +62,38 @@ void FileTrans::ReqDownFile(const TransTask& task) info.toPath = task.localPath; info.fromPath = task.remotePath; + downTask_->file.setFileName(Util::Get2FilePath(task.remotePath, task.localPath)); + if (!downTask_->file.open(QIODevice::WriteOnly)) { + qCritical() << QString(tr("open file [%1] failed.")).arg(downTask_->file.fileName()); + downTask_->state = TaskState::STATE_NONE; + return; + } if (!clientCore_->Send(info, FBT_CLI_REQ_DOWN, task.remoteId)) { - sigError(QString(tr("send req send failed: %1")).arg(info.msg)); - sendTask_.state = TaskState::STATE_NONE; + qCritical() << QString(tr("send req send failed: %1")).arg(info.msg); + sendTask_->state = TaskState::STATE_NONE; + sendTask_->file.close(); return; } - sendTask_.state = TaskState::STATE_RUNNING; + sendTask_->state = TaskState::STATE_RUNNING; } qint32 FileTrans::GetSendProgress() { - if (sendTask_.state != TaskState::STATE_RUNNING) { + if (sendTask_->state != TaskState::STATE_RUNNING) { return -1; } - double per = (sendTask_.tranSize * 100.0) / sendTask_.totalSize; + double per = (sendTask_->tranSize * 100.0) / sendTask_->totalSize; return per; } qint32 FileTrans::GetDownProgress() { - if (downTask_.state != TaskState::STATE_RUNNING) { + if (downTask_->state != TaskState::STATE_RUNNING) { return -1; } - double per = (downTask_.tranSize * 100.0) / downTask_.totalSize; + double per = (downTask_->tranSize * 100.0) / downTask_->totalSize; return per; } @@ -100,7 +119,7 @@ void FileTrans::fbtReqSend(QSharedPointer frame) // judge is same client's same file. // recv is single thread recv, judge idle - if (downTask_.state == TaskState::STATE_RUNNING) { + if (downTask_->state == TaskState::STATE_RUNNING) { info.msg = QString(tr("busy...")); clientCore_->Send(info, FBT_CLI_CANOT_SEND, frame->fid); return; @@ -108,29 +127,29 @@ void FileTrans::fbtReqSend(QSharedPointer frame) // recv auto newerPath = Util::Get2FilePath(info.fromPath, info.toPath); - downTask_.file.setFileName(newerPath); - if (!downTask_.file.open(QIODevice::WriteOnly)) { + downTask_->file.setFileName(newerPath); + if (!downTask_->file.open(QIODevice::WriteOnly)) { info.msg = QString(tr("open file failed: %1")).arg(newerPath); qCritical() << info.msg; if (!clientCore_->Send(info, FBT_CLI_CANOT_SEND, frame->fid)) { qCritical() << QString(tr("open recv file:%2 failed, and reply %2 failed.")).arg(info.msg).arg(frame->fid); - downTask_.file.close(); + downTask_->file.close(); return; } return; } - downTask_.totalSize = info.size; - downTask_.tranSize = 0; - downTask_.permission = info.permissions; + downTask_->totalSize = info.size; + downTask_->tranSize = 0; + downTask_->permission = info.permissions; info.msg = QString(tr("open recv file success: %1")).arg(newerPath); if (!clientCore_->Send(info, FBT_CLI_CAN_SEND, frame->fid)) { qCritical() << QString(tr("open recv file:%2 success, but reply %2 failed.")).arg(info.msg).arg(frame->fid); - downTask_.file.close(); + downTask_->file.close(); return; } - downTask_.state = TaskState::STATE_RUNNING; + downTask_->state = TaskState::STATE_RUNNING; } // The other party requests to download, prepare to send. @@ -157,10 +176,10 @@ void FileTrans::fbtReqDown(QSharedPointer frame) void FileTrans::fbtTransDone(QSharedPointer frame) { auto info = infoUnpack(frame->data); - if (downTask_.file.isOpen()) { - downTask_.file.close(); - downTask_.state = TaskState::STATE_FINISH; - qInfo() << QString(tr("recv file:%1 success.")).arg(downTask_.file.fileName()); + if (downTask_->file.isOpen()) { + downTask_->file.close(); + downTask_->state = TaskState::STATE_FINISH; + qInfo() << QString(tr("recv file:%1 success.")).arg(downTask_->file.fileName()); clientCore_->Send(info, FBT_CLI_CAN_DOWN, frame->fid); return; } @@ -172,6 +191,9 @@ void FileTrans::fbtCanDown(QSharedPointer frame) { // ready to recv file. auto info = infoUnpack(frame->data); + downTask_->permission = info.permissions; + downTask_->totalSize = info.size; + downTask_->tranSize = 0; qDebug() << QString(tr("start trans file:%1.")).arg(info.fromPath); } @@ -183,36 +205,44 @@ void FileTrans::fbtCanotDown(QSharedPointer frame) void FileTrans::fbtFileBuffer(QSharedPointer frame) { - if (downTask_.state != TaskState::STATE_RUNNING) { + if (downTask_->state != TaskState::STATE_RUNNING) { return; } // For the sake of efficiency, not verify the legality of the file - auto ws = downTask_.file.write(frame->data.constData(), frame->data.size()); + auto ws = downTask_->file.write(frame->data.constData(), frame->data.size()); if (ws != frame->data.size()) { - downTask_.state = TaskState::STATE_FAILED; + downTask_->state = TaskState::STATE_FAILED; InfoMsg info; - info.msg = downTask_.file.errorString(); + info.msg = downTask_->file.errorString(); clientCore_->Send(info, FBT_CLI_TRANS_FAILED, frame->fid); + downTask_->file.close(); } + downTask_->tranSize += ws; } void FileTrans::fbtCanotSend(QSharedPointer frame) { InfoMsg info = infoUnpack(frame->data); qCritical() << QString(tr("request file:%1 failed. reason:%2")).arg(info.fromPath).arg(info.msg); + if (sendTask_->file.isOpen()) { + sendTask_->file.close(); + } } void FileTrans::fbtCanSend(QSharedPointer frame) { + InfoMsg info = infoUnpack(frame->data); + qInfo() << QString(tr("start trans file:%1 to %2")).arg(info.fromPath).arg(frame->fid); + SendFile(sendTask_); } void FileTrans::fbtTransFailed(QSharedPointer frame) { - qCritical() << QString(tr("trans file:%1 failed.")).arg(downTask_.file.fileName()); - if (downTask_.file.isOpen()) { - downTask_.file.close(); + qCritical() << QString(tr("trans file:%1 failed.")).arg(downTask_->file.fileName()); + if (downTask_->file.isOpen()) { + downTask_->file.close(); } - downTask_.state = TaskState::STATE_FAILED; + downTask_->state = TaskState::STATE_FAILED; } void FileTrans::SendFile(const QSharedPointer& task) @@ -251,11 +281,9 @@ void SendThread::run() suc = false; break; } + task_->tranSize += br; } - - if (!suc) { - task_->file.close(); - } + task_->file.close(); } void SendThread::setTask(const QSharedPointer& task) diff --git a/ClientCore/FileTrans.h b/ClientCore/FileTrans.h index f800d73..0c290f3 100644 --- a/ClientCore/FileTrans.h +++ b/ClientCore/FileTrans.h @@ -62,9 +62,6 @@ public: qint32 GetSendProgress(); qint32 GetDownProgress(); -signals: - void sigError(const QString& err); - private: void fbtReqSend(QSharedPointer frame); void fbtReqDown(QSharedPointer frame); @@ -81,8 +78,8 @@ private: void SendFile(const QSharedPointer& task); private: - DoTransTask downTask_; - DoTransTask sendTask_; + QSharedPointer downTask_; + QSharedPointer sendTask_; QMutex lMut_; QMutex rMut_; diff --git a/Gui/Control/FileControl.cpp b/Gui/Control/FileControl.cpp index 9496ad9..11cae2c 100644 --- a/Gui/Control/FileControl.cpp +++ b/Gui/Control/FileControl.cpp @@ -29,12 +29,22 @@ void FileManager::SetModeStr(const QString& modeStr, int type, ClientCore* clien fileHelper_->registerPathCall([this](const QString& path) { ShowPath(path); }); fileHelper_->registerFileCall([this](const DirFileInfoVec& info) { ShowFile(info); }); } else { + cliCore_ = clientCore; auto remotePtr = std::make_shared(); remotePtr->registerPathCall([this](const QString& path) { ShowPath(path); }); remotePtr->registerFileCall([this](const DirFileInfoVec& info) { ShowFile(info); }); remotePtr->setClientCore(clientCore); + ui->tableWidget->setIsRemote(true); + ui->tableWidget->setOwnIDCall([this]() { return cliCore_->GetOwnID(); }); + ui->tableWidget->setRemoteIDCall([this]() { return cliCore_->GetRemoteID(); }); fileHelper_ = remotePtr; } + ui->tableWidget->setBasePathCall([this]() { return curRoot_; }); +} + +void FileManager::SetOtherSidePathCall(const std::function& call) +{ + ui->tableWidget->setOtherSidePathCall(call); } void FileManager::InitControl() @@ -72,10 +82,9 @@ void FileManager::InitControl() void FileManager::InitMenu(bool remote) { if (remote) { - //auto acDown = new QAction(tr("Download")); - } - else { - //auto acUp = new QAction(tr("Upload")); + // auto acDown = new QAction(tr("Download")); + } else { + // auto acUp = new QAction(tr("Upload")); } } diff --git a/Gui/Control/FileControl.h b/Gui/Control/FileControl.h index 2ac889a..4dbb903 100644 --- a/Gui/Control/FileControl.h +++ b/Gui/Control/FileControl.h @@ -21,6 +21,8 @@ public: public: void SetModeStr(const QString& modeStr, int type = 0, ClientCore* clientCore = nullptr); + void SetOtherSidePathCall(const std::function& call); + QString GetCurRoot(); private: void InitControl(); @@ -38,6 +40,7 @@ private: Ui::FileManager* ui; QString curRoot_; QMenu* menu_; + ClientCore* cliCore_; std::shared_ptr fileHelper_; }; diff --git a/Gui/Control/cusTableWidget.cpp b/Gui/Control/cusTableWidget.cpp index 43602bf..23d7176 100644 --- a/Gui/Control/cusTableWidget.cpp +++ b/Gui/Control/cusTableWidget.cpp @@ -1,9 +1,12 @@ #include "cusTableWidget.h" +#include +#include #include #include #include #include +#include "FileControl.h" CustomTableWidget::CustomTableWidget(QWidget* parent) : QTableWidget(parent) { @@ -13,6 +16,36 @@ CustomTableWidget::~CustomTableWidget() { } +void CustomTableWidget::setIsRemote(bool isRemote) +{ + isRemote_ = isRemote; +} + +void CustomTableWidget::setBasePathCall(const std::function& call) +{ + basePathCall_ = call; +} + +void CustomTableWidget::setOtherSidePathCall(const std::function& call) +{ + otherSideCall_ = call; +} + +QString FileManager::GetCurRoot() +{ + return curRoot_; +} + +void CustomTableWidget::setOwnIDCall(const std::function& call) +{ + oidCall_ = call; +} + +void CustomTableWidget::setRemoteIDCall(const std::function& call) +{ + ridCall_ = call; +} + void CustomTableWidget::dropEvent(QDropEvent* event) { if (!event->mimeData()->hasFormat("application/x-custom-data")) { @@ -31,6 +64,25 @@ void CustomTableWidget::dragEnterEvent(QDragEnterEvent* event) } if (event->mimeData()->hasFormat("application/x-custom-data")) { event->acceptProposedAction(); + auto dirinfo = infoUnpack(event->mimeData()->data("application/x-custom-data")); + QVector tasks; + // generate task + for (const auto& df : dirinfo.vec) { + TransTask task; + task.isUpload = isRemote_; + task.localId = oidCall_(); + task.remoteId = ridCall_(); + if (isRemote_) { + task.remotePath = basePathCall_(); + task.localPath = Util::Join(otherSideCall_(), df.name); + } + else { + task.remotePath = Util::Join(otherSideCall_(), df.name); + task.localPath = basePathCall_(); + } + tasks.push_back(task); + } + emit sigTasks(tasks); } else { event->ignore(); } @@ -48,18 +100,20 @@ void CustomTableWidget::mouseMoveEvent(QMouseEvent* event) QDrag* drag = new QDrag(this); QMimeData* mimeData = new QMimeData; - QStringList selectedTexts; + DirFileInfoVec v; + v.root = basePathCall_(); foreach (QTableWidgetItem* item, selectedItems()) { if (item->column() == 1) { - selectedTexts << item->text(); + DirFileInfo df; + df.name = item->text(); } } - mimeData->setData("application/x-custom-data", selectedTexts.join("|").toUtf8()); + mimeData->setData("application/x-custom-data", infoPack(v)); drag->setMimeData(mimeData); QPixmap pixmap(100, 50); pixmap.fill(Qt::lightGray); QPainter painter(&pixmap); - painter.drawText(pixmap.rect(), Qt::AlignCenter, QString("%1 ITEM").arg(selectedTexts.count())); + painter.drawText(pixmap.rect(), Qt::AlignCenter, QString("%1 ITEM").arg(v.vec.size())); drag->setPixmap(pixmap); drag->exec(Qt::CopyAction | Qt::MoveAction); } diff --git a/Gui/Control/cusTableWidget.h b/Gui/Control/cusTableWidget.h index 5d73e08..fb4a038 100644 --- a/Gui/Control/cusTableWidget.h +++ b/Gui/Control/cusTableWidget.h @@ -1,8 +1,9 @@ #ifndef CUSTOM_TABLEWIDET_H #define CUSTOM_TABLEWIDET_H -#include +#include #include +#include class CustomTableWidget : public QTableWidget { @@ -11,6 +12,16 @@ public: explicit CustomTableWidget(QWidget* parent = nullptr); ~CustomTableWidget() override; +signals: + void sigTasks(const QVector& tasks); + +public: + void setIsRemote(bool isRemote); + void setBasePathCall(const std::function& call); + void setOtherSidePathCall(const std::function& call); + void setOwnIDCall(const std::function& call); + void setRemoteIDCall(const std::function& call); + protected: void dropEvent(QDropEvent* event) override; void dragEnterEvent(QDragEnterEvent* event); @@ -18,7 +29,12 @@ protected: void mousePressEvent(QMouseEvent* event) override; protected: + bool isRemote_{false}; QPoint startPos_; + std::function basePathCall_; + std::function otherSideCall_; + std::function oidCall_; + std::function ridCall_; }; #endif diff --git a/Gui/Form/Transform.cpp b/Gui/Form/Transform.cpp index 2024e1f..aa1e0d2 100644 --- a/Gui/Form/Transform.cpp +++ b/Gui/Form/Transform.cpp @@ -7,6 +7,11 @@ TransForm::TransForm(QWidget* parent) : QDialog(parent), ui(new Ui::TransForm) { ui->setupUi(this); + + connect(this, &TransForm::sigProgress, this, &TransForm::setProgress); + connect(this, &TransForm::sigDone, this, &TransForm::handleDone); + connect(this, &TransForm::sigFailed, this, &TransForm::handleFailed); + connect(this, &TransForm::sigSetUi, this, &TransForm::handleUI); } TransForm::~TransForm() @@ -28,12 +33,77 @@ void TransForm::SetTasks(const QVector& tasks) void TransForm::startTask() { for (auto& task : tasks_) { - + sigSetUi(task); + if (task.isUpload) { + fileTrans_->ReqSendFile(task); + while (true) { + auto progress = fileTrans_->GetSendProgress(); + if (progress < 0) { + sigFailed(); + break; + } + if (progress >= 100.0) { + sigDone(); + break; + } + sigProgress(progress); + QThread::msleep(10); + } + } else { + fileTrans_->ReqDownFile(task); + while (true) { + auto progress = fileTrans_->GetDownProgress(); + if (progress < 0) { + sigFailed(); + break; + } + if (progress >= 100.0) { + sigDone(); + break; + } + sigProgress(progress); + QThread::msleep(10); + } + } + } +} + +void TransForm::setProgress(double val) +{ + ui->progressBar->setValue(val); +} + +void TransForm::handleFailed() +{ + ui->progressBar->setValue(0); +} + +void TransForm::handleDone() +{ + ui->progressBar->setValue(0); +} + +void TransForm::handleUI(const TransTask& task) +{ + if (task.isUpload) { + ui->edFrom->setText(task.localId); + ui->edTo->setText(task.remoteId); + ui->pedFrom->setPlainText(task.localPath); + ui->pedTo->setPlainText(task.remotePath); + } + else { + ui->edFrom->setText(task.localId); + ui->edTo->setText(task.remoteId); + ui->pedFrom->setPlainText(task.remotePath); + ui->pedTo->setPlainText(task.localPath); } } void TransForm::showEvent(QShowEvent* event) { QDialog::showEvent(event); - startTask(); + workTh_ = new TranFromTh(this); + fileTrans_->moveToThread(workTh_); + connect(workTh_, &QThread::finished, fileTrans_, &QObject::deleteLater); + workTh_->start(); } diff --git a/Gui/Form/Transform.h b/Gui/Form/Transform.h index 21254f1..6ca130f 100644 --- a/Gui/Form/Transform.h +++ b/Gui/Form/Transform.h @@ -2,14 +2,16 @@ #define TRANSFORM_H #include +#include #include #include -#include +#include namespace Ui { class TransForm; } +class TranFromTh; class TransForm : public QDialog { Q_OBJECT @@ -21,18 +23,50 @@ public: public: void SetClientCore(ClientCore* clientCore); void SetTasks(const QVector& tasks); + void startTask(); + +signals: + void sigProgress(double val); + void sigFailed(); + void sigDone(); + void sigSetUi(const TransTask& task); private: - void startTask(); + void setProgress(double val); + void handleFailed(); + void handleDone(); + void handleUI(const TransTask& task); protected: void showEvent(QShowEvent* event) override; private: + TranFromTh* workTh_{}; QVector tasks_; FileTrans* fileTrans_{}; ClientCore* clientCore_{}; Ui::TransForm* ui; }; +class TranFromTh : public QThread +{ + Q_OBJECT + +public: + explicit TranFromTh(TransForm* tf, QObject* parent = nullptr) : QThread(parent), tf_(tf) + { + } + +protected: + void run() override + { + if (tf_) { + tf_->startTask(); + } + } + +private: + TransForm* tf_; +}; + #endif // TRANSFORM_H diff --git a/Gui/frelayGUI.cpp b/Gui/frelayGUI.cpp index b687b54..4fae481 100644 --- a/Gui/frelayGUI.cpp +++ b/Gui/frelayGUI.cpp @@ -1,10 +1,10 @@ #include "frelayGUI.h" -#include #include +#include +#include #include "./ui_frelayGUI.h" -#include static LogPrint* logPrint = nullptr; @@ -44,7 +44,9 @@ void frelayGUI::InitControl() localFile_ = new FileManager(this); remoteFile_ = new FileManager(this); localFile_->SetModeStr(tr("Local:")); + localFile_->SetOtherSidePathCall([this]() { return remoteFile_->GetCurRoot(); }); remoteFile_->SetModeStr(tr("Remote:"), 1, clientCore_); + remoteFile_->SetOtherSidePathCall([this]() { return localFile_->GetCurRoot(); }); tabWidget_ = new QTabWidget(this); } diff --git a/README.md b/README.md index 55451a1..a6425e2 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# frelay +# frelay A tool that uses a relay server to upload and download files from remote clients. @@ -7,5 +7,7 @@ A tool that uses a relay server to upload and download files from remote clients 1. Minimal configuration—simply start a server, connect to it, and begin transferring files. 2. If you frequently transfer the same files repeatedly, frelay offers a local-remote file mapping feature for one-click transfers. -## Disclaimer +## Disclaimer And Warning This tool is solely designed for simple file transmission between clients via a relay server. It does not include any security validation logic to prevent data attacks or similar threats. It is primarily intended for temporary, non-sensitive file transfers. Please close the software or disconnect from the relay server when not in use. + +The software may contain unexpected bugs that could corrupt or lose your files. Please ensure proper backups or use it only for non-critical file transfers. diff --git a/Util/Util.cpp b/Util/Util.cpp index 7a32871..d4d0afe 100644 --- a/Util/Util.cpp +++ b/Util/Util.cpp @@ -33,6 +33,11 @@ QString Util::GetUserHome() return homePath; } +QString Util::Join(const QString& path, const QString& name) +{ + return QDir::cleanPath(path + QDir::separator() + name); +} + void Util::InitLogger(const QString& logPath, const QString& mark) { auto file_sink = std::make_shared(logPath.toStdString(), 1024 * 1024 * 50, 3); diff --git a/Util/Util.h b/Util/Util.h index 2992898..86a1922 100644 --- a/Util/Util.h +++ b/Util/Util.h @@ -14,6 +14,7 @@ public: static QString GetUserHome(); static void InitLogger(const QString& logPath, const QString& mark); static QString Get2FilePath(const QString& file, const QString& directory); + static QString Join(const QString& path, const QString& name); static void ConsoleMsgHander(QtMsgType type, const QMessageLogContext& context, const QString& msg); };