gui: add basic gui code.

This commit is contained in:
2025-06-15 14:31:54 +08:00
parent 72df3216a5
commit 7d123b2c06
40 changed files with 1483 additions and 12 deletions

View File

@@ -0,0 +1,13 @@
#include "CompareControl.h"
#include "ui_CompareControl.h"
Compare::Compare(QWidget* parent) : QWidget(parent), ui(new Ui::Compare)
{
ui->setupUi(this);
}
Compare::~Compare()
{
delete ui;
}

View File

@@ -0,0 +1,22 @@
#ifndef COMPARECONTROL_H
#define COMPARECONTROL_H
#include <QWidget>
namespace Ui {
class Compare;
}
class Compare : public QWidget
{
Q_OBJECT
public:
explicit Compare(QWidget *parent = nullptr);
~Compare();
private:
Ui::Compare *ui;
};
#endif // COMPARECONTROL_H

View File

@@ -0,0 +1,19 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Compare</class>
<widget class="QWidget" name="Compare">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,155 @@
#include "ConnectControl.h"
#include <InfoMsg.h>
#include <InfoPack.hpp>
#include <future>
#include "Control/LogControl.h"
#include "GuiUtil/Public.h"
#include "ui_ConnectControl.h"
Connecter::Connecter(QWidget* parent) : QWidget(parent), ui(new Ui::Connecter)
{
ui->setupUi(this);
InitControl();
}
Connecter::~Connecter()
{
if (thConnect_.joinable()) {
thConnect_.join();
}
delete ui;
}
void Connecter::SetClientCore(ClientCore* clientCore)
{
clientCore_ = clientCore;
clientCore_->SetClientsCall([this](const InfoClientVec& clients) { HandleClients(clients); });
}
void Connecter::SetLogPrint(LogPrint* log)
{
log_ = log;
}
void Connecter::SetRemoteCall(const std::function<void(const QString& id)>& call)
{
remoteCall_ = call;
}
void Connecter::HandleClients(const InfoClientVec& clients)
{
model_->removeRows(0, ui->listView->model()->rowCount());
for (const auto& client : clients.vec) {
auto* item = new QStandardItem(client.name);
model_->appendRow(item);
}
}
void Connecter::Connect()
{
auto ip = ui->edIP->text().trimmed();
auto port = ui->edPort->text().trimmed();
if (ip.isEmpty() || port.isEmpty()) {
FTCommon::msg(this, tr("IP or Port is empty."));
return;
}
auto task = [this, ip, port]() {
emit sendConnect(ConnectState::CS_CONNECTING);
connceted_ = clientCore_->Connect(ip, port.toInt());
if (connceted_) {
emit sendConnect(ConnectState::CS_CONNECTED);
} else {
emit sendConnect(ConnectState::CS_DISCONNECT);
}
};
if (thConnect_.joinable()) {
thConnect_.join();
}
thConnect_ = std::thread(task);
}
void Connecter::setState(ConnectState cs)
{
switch (cs) {
case CS_CONNECTING:
ui->btnConnect->setEnabled(false);
ui->btnDisconnect->setEnabled(false);
log_->Info(tr("Connecting..."));
break;
case CS_CONNECTED:
ui->btnConnect->setEnabled(false);
ui->btnDisconnect->setEnabled(true);
break;
case CS_DISCONNECT:
ui->btnConnect->setEnabled(true);
ui->btnDisconnect->setEnabled(false);
break;
default:
break;
}
}
void Connecter::RefreshClient()
{
InfoMsg info;
auto frame = QSharedPointer<FrameBuffer>::create();
frame->data = infoPack(info);
frame->type = FBT_SER_MSG_ASKCLIENTS;
if (!clientCore_->Send(frame)) {
qCritical() << QString(tr("send ask client list failed."));
return;
}
qInfo() << QString(tr("ask client list..."));
}
void Connecter::ShowContextMenu(const QPoint& pos)
{
auto index = ui->listView->indexAt(pos);
if (!index.isValid()) {
return;
}
menu_->exec(QCursor::pos());
}
std::string Connecter::getCurClient()
{
return ui->elbClient->text().toStdString();
}
void Connecter::InitControl()
{
ui->btnDisconnect->setEnabled(false);
ui->edIP->setText("127.0.0.1");
ui->edPort->setText("9009");
connect(ui->btnConnect, &QPushButton::clicked, this, &Connecter::Connect);
connect(ui->btnRefresh, &QPushButton::clicked, this, &Connecter::RefreshClient);
connect(this, &Connecter::sendConnect, this, &Connecter::setState);
model_ = new QStandardItemModel(this);
ui->listView->setModel(model_);
ui->listView->setContextMenuPolicy(Qt::CustomContextMenu);
connect(ui->listView, &QListView::customContextMenuRequested, this, &Connecter::ShowContextMenu);
menu_ = new QMenu(this);
QAction* acUseThis = menu_->addAction(tr("UseThis"));
connect(acUseThis, &QAction::triggered, this, [this]() {
auto index = ui->listView->currentIndex();
if (!index.isValid()) {
return;
}
auto* item = model_->itemFromIndex(index);
if (!item) {
return;
}
auto name = item->text();
ui->elbClient->setText(name);
ui->elbClient->setStyleSheet("color: blue;");
remoteCall_(name);
});
setMaximumSize(300, 300);
}

View File

@@ -0,0 +1,61 @@
#ifndef CONNECTCONTROL_H
#define CONNECTCONTROL_H
#include <ClientCore.h>
#include <InfoClient.h>
#include <QMenu>
#include <QStandardItemModel>
#include <QWidget>
namespace Ui {
class Connecter;
}
enum ConnectState {
CS_DISCONNECT,
CS_CONNECTING,
CS_CONNECTED,
};
class LogPrint;
class Connecter : public QWidget
{
Q_OBJECT
public:
explicit Connecter(QWidget* parent = nullptr);
~Connecter();
public:
void SetClientCore(ClientCore* clientCore);
void SetLogPrint(LogPrint* log);
void SetRemoteCall(const std::function<void(const QString& id)>& call);
void HandleClients(const InfoClientVec& clients);
signals:
void sendConnect(ConnectState cs);
private:
void InitControl();
void Connect();
void setState(ConnectState cs);
void RefreshClient();
void ShowContextMenu(const QPoint& pos);
std::string getCurClient();
private:
std::thread thConnect_;
Ui::Connecter* ui;
LogPrint* log_;
bool thRun_{false};
bool connceted_{false};
std::thread thContext_;
std::function<void(const QString& id)> remoteCall_;
ClientCore* clientCore_;
private:
QMenu* menu_;
QStandardItemModel* model_;
};
#endif // CONNECTCONTROL_H

View File

@@ -0,0 +1,137 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Connecter</class>
<widget class="QWidget" name="Connecter">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>350</width>
<height>276</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lbIP">
<property name="text">
<string>Server IP:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="edIP"/>
</item>
<item>
<widget class="QLabel" name="label">
<property name="text">
<string>Port:</string>
</property>
</widget>
</item>
<item>
<widget class="QLineEdit" name="edPort">
<property name="maximumSize">
<size>
<width>60</width>
<height>16777215</height>
</size>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QLabel" name="lbClient">
<property name="text">
<string>Client:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="elbClient">
<property name="text">
<string>None</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_3">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QListView" name="listView"/>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QPushButton" name="btnDisconnect">
<property name="text">
<string>Disconnect</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_4">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnRefresh">
<property name="text">
<string>Refresh</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="btnConnect">
<property name="text">
<string>Connect</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

222
Gui/Control/FileControl.cpp Normal file
View File

@@ -0,0 +1,222 @@
#include "FileControl.h"
#include <LocalFile.h>
#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QHeaderView>
#include <QTableWidgetItem>
#include <RemoteFile.h>
#include "LogControl.h"
#include "ui_FileControl.h"
FileManager::FileManager(QWidget* parent) : QWidget(parent), ui(new Ui::FileManager)
{
ui->setupUi(this);
InitControl();
}
FileManager::~FileManager()
{
delete ui;
}
void FileManager::SetModeStr(const QString& modeStr, int type, ClientCore* clientCore)
{
ui->lbMode->setText(modeStr);
if (type == 0) {
fileHelper_ = std::make_shared<LocalFile>();
fileHelper_->registerPathCall([this](const QString& path) { ShowPath(path); });
fileHelper_->registerFileCall([this](const DirFileInfoVec& info) { ShowFile(info); });
} else {
auto remotePtr = std::make_shared<RemoteFile>();
remotePtr->registerPathCall([this](const QString& path) { ShowPath(path); });
remotePtr->registerFileCall([this](const DirFileInfoVec& info) { ShowFile(info); });
remotePtr->setClientCore(clientCore);
fileHelper_ = remotePtr;
}
}
void FileManager::SetLogPrint(LogPrint* log)
{
log_ = log;
}
void FileManager::InitControl()
{
QStringList headers;
headers << tr("") << tr("FileName") << tr("ModifyTime") << tr("Type") << tr("Size");
ui->tableWidget->setColumnCount(headers.size());
ui->tableWidget->setHorizontalHeaderLabels(headers);
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->comboBox->setEditable(true);
// ui->tableWidget->setColumnWidth(0, 50);
ui->tableWidget->setColumnWidth(1, 300);
ui->tableWidget->setColumnWidth(2, 150);
ui->tableWidget->setColumnWidth(3, 70);
ui->tableWidget->setColumnWidth(4, 90);
ui->tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
ui->tableWidget->verticalHeader()->setSectionResizeMode(QHeaderView::Fixed);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(0, QHeaderView::Fixed);
ui->tableWidget->horizontalHeader()->setSectionResizeMode(1, QHeaderView::Stretch);
// ui->tableWidget->setStyleSheet("QTableWidget::item:hover { background-color: transparent; }");
connect(ui->btnHome, &QPushButton::clicked, this, &FileManager::evtHome);
connect(ui->btnVisit, &QPushButton::clicked, this, &FileManager::evtFile);
connect(ui->tableWidget, &QTableWidget::cellDoubleClicked, this, &FileManager::doubleClick);
connect(ui->btnUp, &QPushButton::clicked, this, &FileManager::evtUp);
}
void FileManager::ShowPath(const QString& path)
{
int existingIndex = ui->comboBox->findText(path);
if (existingIndex != -1) {
ui->comboBox->removeItem(existingIndex);
} else if (ui->comboBox->count() >= 20) {
ui->comboBox->removeItem(ui->comboBox->count() - 1);
}
ui->comboBox->insertItem(0, path);
ui->comboBox->setCurrentIndex(0);
}
void FileManager::ShowFile(const DirFileInfoVec& info)
{
QAbstractItemModel* const mdl = ui->tableWidget->model();
mdl->removeRows(0, mdl->rowCount());
ui->tableWidget->setRowCount(info.vec.size());
for (int i = 0; i < info.vec.size(); ++i) {
const DirFileInfo& fileInfo = info.vec[i];
// ***********************************************************************************
auto* iconItem = new QTableWidgetItem("");
iconItem->setTextAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
iconItem->setFlags(iconItem->flags() & ~Qt::ItemIsEditable);
ui->tableWidget->setItem(i, 0, iconItem);
// ***********************************************************************************
auto* fileItem = new QTableWidgetItem(fileInfo.name);
fileItem->setFlags(fileItem->flags() & ~Qt::ItemIsEditable);
ui->tableWidget->setItem(i, 1, fileItem);
QDateTime modifyTime = QDateTime::fromMSecsSinceEpoch(fileInfo.lastModified);
// ***********************************************************************************
QString timeStr = modifyTime.toString("yyyy-MM-dd hh:mm:ss");
auto* timeItem = new QTableWidgetItem(timeStr);
timeItem->setFlags(timeItem->flags() & ~Qt::ItemIsEditable);
ui->tableWidget->setItem(i, 2, timeItem);
// ***********************************************************************************
QString typeStr;
switch (fileInfo.type) {
case File:
typeStr = "File";
iconItem->setIcon(QApplication::style()->standardIcon(QStyle::SP_FileIcon));
break;
case Dir:
typeStr = "Dir";
iconItem->setIcon(QApplication::style()->standardIcon(QStyle::SP_DirIcon));
break;
case Link:
typeStr = "Link";
break;
case Other:
typeStr = "Other";
break;
default:
typeStr = "Unknown";
break;
}
// ***********************************************************************************
auto* typeItem = new QTableWidgetItem(typeStr);
typeItem->setFlags(typeItem->flags() & ~Qt::ItemIsEditable);
ui->tableWidget->setItem(i, 3, typeItem);
// ***********************************************************************************
QString sizeStr;
if (fileInfo.size < 1024) {
sizeStr = QString::number(fileInfo.size) + " B";
} else if (fileInfo.size < 1024 * 1024) {
sizeStr = QString::number(fileInfo.size / 1024.0, 'f', 2) + " KB";
} else {
sizeStr = QString::number(fileInfo.size / (1024.0 * 1024.0), 'f', 2) + " MB";
}
QTableWidgetItem* item = nullptr;
if (fileInfo.type == File) {
item = new QTableWidgetItem(sizeStr);
} else {
item = new QTableWidgetItem("");
}
item->setFlags(item->flags() & ~Qt::ItemIsEditable);
ui->tableWidget->setItem(i, 4, item);
}
ui->tableWidget->resizeColumnToContents(0);
if (info.vec.empty()) {
return;
}
QString fp = info.vec[0].fullPath;
QDir dir(fp);
dir.cdUp();
fp = dir.path();
curRoot_ = fp;
ShowPath(curRoot_);
}
void FileManager::evtHome()
{
auto r = fileHelper_->GetHome();
auto curPath = ui->comboBox->currentText();
curRoot_ = curPath;
qDebug() << QString(tr("%1 get home ret:%2").arg(__FUNCTION__).arg(r));
}
void FileManager::evtFile()
{
auto curPath = ui->comboBox->currentText();
auto r = fileHelper_->GetDirFile(curPath);
curRoot_ = curPath;
qDebug() << QString(tr("%1 get files ret:%2").arg(__FUNCTION__).arg(r));
}
void FileManager::evtUp()
{
QString path(curRoot_);
QDir dir(path);
dir.cdUp();
path = dir.path();
if (path.isEmpty()) {
return;
}
auto r = fileHelper_->GetDirFile(path);
if (r) {
curRoot_ = path;
ShowPath(curRoot_);
}
}
void FileManager::doubleClick(int row, int column)
{
Q_UNUSED(column)
auto* item = ui->tableWidget->item(row, 1);
if (item == nullptr) {
return;
}
auto type = ui->tableWidget->item(row, 3)->text();
if (type != "Dir") {
return;
}
QDir dir(curRoot_);
QString np = dir.filePath(item->text());
fileHelper_->GetDirFile(np);
}

44
Gui/Control/FileControl.h Normal file
View File

@@ -0,0 +1,44 @@
#ifndef FILECONTROL_H
#define FILECONTROL_H
#include <ClientCore.h>
#include <InfoDirFile.h>
#include <QWidget>
#include <Util.h>
namespace Ui {
class FileManager;
}
class LogPrint;
class FileManager : public QWidget
{
Q_OBJECT
public:
explicit FileManager(QWidget* parent = nullptr);
~FileManager();
public:
void SetModeStr(const QString& modeStr, int type = 0, ClientCore* clientCore = nullptr);
void SetLogPrint(LogPrint* log);
private:
void InitControl();
void ShowPath(const QString& path);
void ShowFile(const DirFileInfoVec& info);
void doubleClick(int row, int column);
private:
void evtHome();
void evtFile();
void evtUp();
private:
Ui::FileManager* ui;
LogPrint* log_;
QString curRoot_;
std::shared_ptr<DirFileHelper> fileHelper_;
};
#endif // FILECONTROL_H

View File

@@ -0,0 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>FileManager</class>
<widget class="QWidget" name="FileManager">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>719</width>
<height>339</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QLabel" name="lbMode">
<property name="text">
<string>Mode:</string>
</property>
</widget>
</item>
<item>
<widget class="QComboBox" name="comboBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnVisit">
<property name="text">
<string>Go</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnHome">
<property name="text">
<string>Home</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="btnUp">
<property name="text">
<string>Up</string>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QTableWidget" name="tableWidget"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>

View File

@@ -0,0 +1,63 @@
#include "LogControl.h"
#include <QDateTime>
#include <QStandardItem>
#include <iomanip>
#include <sstream>
#include "ui_LogControl.h"
LogPrint::LogPrint(QWidget* parent) : QWidget(parent), ui(new Ui::LogPrint)
{
ui->setupUi(this);
InitControl();
}
void LogPrint::InitControl()
{
model_ = new QStandardItemModel(this);
ui->listView->setModel(model_);
}
std::string LogPrint::now_str()
{
auto now = std::chrono::system_clock::now();
auto time_t_now = std::chrono::system_clock::to_time_t(now);
auto milliseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()) % 1000;
std::ostringstream timestamp;
timestamp << std::put_time(std::localtime(&time_t_now), "%H:%M:%S") << "." << std::setfill('0') << std::setw(3)
<< milliseconds.count() << " ";
return timestamp.str();
}
LogPrint::~LogPrint()
{
delete ui;
}
void LogPrint::Info(const QString& message)
{
Print(message, Qt::black);
}
void LogPrint::Warn(const QString& message)
{
Print(message, Qt::yellow);
}
void LogPrint::Error(const QString& message)
{
Print(message, Qt::red);
}
void LogPrint::Debug(const QString& message)
{
Print(message, Qt::blue);
}
void LogPrint::Print(const QString& message, const QBrush& color)
{
auto timeStr = QString("%1%2").arg(QString::fromStdString(now_str())).arg(message);
auto* item = new QStandardItem(timeStr);
item->setForeground(color);
model_->appendRow(item);
ui->listView->scrollToBottom();
}

38
Gui/Control/LogControl.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef LOGCONTROL_H
#define LOGCONTROL_H
#include <QBrush>
#include <QStandardItemModel>
#include <QWidget>
namespace Ui {
class LogPrint;
}
class LogPrint : public QWidget
{
Q_OBJECT
public:
explicit LogPrint(QWidget* parent = nullptr);
~LogPrint();
public:
void Info(const QString& message);
void Warn(const QString& message);
void Error(const QString& message);
void Debug(const QString& message);
public:
std::string now_str();
private:
void InitControl();
void Print(const QString& message, const QBrush& color);
private:
Ui::LogPrint* ui;
QStandardItemModel* model_;
};
#endif // LOGCONTROL_H

24
Gui/Control/LogControl.ui Normal file
View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>LogPrint</class>
<widget class="QWidget" name="LogPrint">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>767</width>
<height>291</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QListView" name="listView"/>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>