DSCAnalysisTool/src/ui/leftwidget.cpp
2025-12-11 16:15:36 +08:00

571 lines
18 KiB
C++

#include <QDir>
#include <QDebug>
#include <QHBoxLayout>
#include <QStyle>
#include <QFileInfo>
#include <QTreeWidgetItemIterator>
#include <QTreeWidget>
#include <QTreeWidgetItem>
#include <QDirIterator>
#include <QMenu>
#include <QAction>
#include <QMessageBox>
#include <QInputDialog>
#include "leftwidget.h"
#include "filemanager.h"
#include "global.h"
#include "logger.h"
LeftWidget::LeftWidget(QWidget *parent) : QDockWidget(parent)
{
setWindowTitle("文件浏览");
_treeWidget = new QTreeWidget();
_treeWidget->setHeaderHidden(true);
_treeWidget->setSortingEnabled(false);
setWidget(_treeWidget);
// 初始化文件树
reloadFileTree();
// connections
connect(_treeWidget, &QTreeWidget::itemDoubleClicked,
this, &LeftWidget::slotTreeWidgetItemClicked);
// 右键菜单
_contextMenu = new QMenu(_treeWidget);
_deleteFileAction = new QAction("删除文件", this);
_createFolderAction = new QAction("新建文件夹", this);
_contextMenu->addAction(_deleteFileAction);
_contextMenu->addAction(_createFolderAction);
_treeWidget->setContextMenuPolicy(Qt::CustomContextMenu);
connect(_treeWidget, &QTreeWidget::customContextMenuRequested,
this, &LeftWidget::slotShowContextMenu);
connect(_deleteFileAction, &QAction::triggered,
this, &LeftWidget::slotDeleteActionTriggered);
connect(_createFolderAction, &QAction::triggered,
this, &LeftWidget::slotCreateFolderActionTriggered);
}
void LeftWidget::reloadFileName()
{
clearAllChildItems(_sampleDataItem);
// clearAllChildItems(_baseLineItem);
clearAllChildItems(_analysisStateItem);
initFileName(_sampleDataItem, Global::SampleDataFloder);
#if 0
initFileName(_baseLineItem,Global::BaseLineFolder);
#endif
initFileName(_analysisStateItem, Global::AnalysisStateFolder);
// 更新文件列表
Global::updateFileList();
}
QString LeftWidget::filePathCheck(const QString fileName, const QString folderPath)
{
QString resultFileName = fileName;
QDir dir(folderPath);
QStringList files = dir.entryList(QDir::Files);
for (const QString &existedFileName : files)
{
QFileInfo fileInfo(existedFileName);
if (fileName == fileInfo.baseName())
{
QDateTime currentDateTime = QDateTime::currentDateTime();
QString formattedTime = currentDateTime.toString("yyyy_MM_dd_HH_mm_ss");
resultFileName = fileName + QString("_") + formattedTime;
break;
}
}
return resultFileName;
}
void LeftWidget::initData()
{
// const QString folderPath = QDir::currentPath()+"/../experiment_data";
const QString folderPath = Global::SampleDataFloder;
#if 1
QDir dir(folderPath);
if (!dir.exists())
{
qWarning() << "文件夹不存在: " << folderPath;
return;
}
// 遍历文件
QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
for (const QFileInfo &fileInfo : fileList)
{
QFile file(fileInfo.absoluteFilePath());
if (file.open(QIODevice::ReadOnly | QIODevice::Text))
{
QString content = file.readAll();
qDebug() << "读取文件 " << fileInfo.absoluteFilePath() << " 内容: " << content;
file.close();
// 写入文件操作示例:这里简单在文件末尾追加一行内容
if (file.open(QIODevice::Append | QIODevice::Text))
{
file.write("\n这是通过递归写入添加的内容");
qDebug() << "已向文件 " << fileInfo.absoluteFilePath() << " 写入内容";
file.close();
}
else
{
qWarning() << "无法打开文件进行写入: " << fileInfo.absoluteFilePath();
}
}
else
{
qWarning() << "无法打开文件进行读取: " << fileInfo.absoluteFilePath();
}
}
#endif
}
void LeftWidget::slotTreeWidgetItemClicked(QTreeWidgetItem *item, int column)
{
qDebug() << "item clicked:" << item->text(0) << column;
if (Global::Mode::Analysis != Global::_mode)
{
return;
}
// 检查是否是文件项(有用户数据)
QVariant userData = item->data(0, Qt::UserRole);
if (userData.isNull() || !userData.isValid())
{
qDebug() << "点击的是目录项或无效项";
return;
}
QString filePath = userData.toString();
if (filePath.isEmpty())
{
qDebug() << "文件路径为空";
return;
}
// 检查文件是否存在
QFileInfo fileInfo(filePath);
if (!fileInfo.exists())
{
qWarning() << "文件不存在: " << filePath;
return;
}
// 发送文件路径信号
emit sigSendAnalysisFileName(filePath);
}
void LeftWidget::initFileName(QTreeWidgetItem *parentItem, const QString &folderPath)
{
QDir dir(folderPath);
QStringList files = dir.entryList(QDir::Files);
for (const QString &fileName : files)
{
QTreeWidgetItem *subItem = new QTreeWidgetItem();
subItem->setText(0, fileName);
subItem->setData(0, Qt::UserRole, QVariant::fromValue(folderPath + "/" + fileName));
parentItem->addChild(subItem);
}
}
void LeftWidget::expandAll(QTreeWidgetItem *item)
{
item->setExpanded(true);
for (int i = 0; i < item->childCount(); ++i)
{
expandAll(item->child(i));
}
}
void LeftWidget::clearAllChildItems(QTreeWidgetItem *parentItem)
{
int childCount = parentItem->childCount();
for (int i = 0; i < childCount; ++i)
{
QTreeWidgetItem *childItem = parentItem->takeChild(0);
delete childItem;
}
}
#if 0
void LeftWidget::recursiveFolderOperation(const QString& folderPath) {
QDir dir(folderPath);
if (!dir.exists()) {
qWarning() << "文件夹不存在: " << folderPath;
return;
}
// 遍历文件
QFileInfoList fileList = dir.entryInfoList(QDir::Files | QDir::NoDotAndDotDot);
for (const QFileInfo& fileInfo : fileList) {
QFile file(fileInfo.absoluteFilePath());
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
QString content = file.readAll();
qDebug() << "读取文件 " << fileInfo.absoluteFilePath() << " 内容: " << content;
file.close();
// 写入文件操作示例:这里简单在文件末尾追加一行内容
if (file.open(QIODevice::Append | QIODevice::Text)) {
file.write("\n这是通过递归写入添加的内容");
qDebug() << "已向文件 " << fileInfo.absoluteFilePath() << " 写入内容";
file.close();
} else {
qWarning() << "无法打开文件进行写入: " << fileInfo.absoluteFilePath();
}
} else {
qWarning() << "无法打开文件进行读取: " << fileInfo.absoluteFilePath();
}
}
// 递归遍历子文件夹
QFileInfoList subDirList = dir.entryInfoList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QFileInfo& subDirInfo : subDirList) {
recursiveFolderOperation(subDirInfo.absoluteFilePath());
}
}
#endif
void LeftWidget::slotShowContextMenu(const QPoint &pos)
{
QTreeWidgetItem *item = _treeWidget->itemAt(pos);
if (item) {
// 获取文件路径
QString filePath = item->data(0, Qt::UserRole).toString();
QString dirPath = item->data(0, Qt::UserRole + 1).toString();
// 如果是文件
if (!filePath.isEmpty()) {
_deleteFileActionFilePath = filePath;
_deleteFileAction->setVisible(true);
_deleteFileAction->setText(tr("删除文件"));
}
// 如果是目录
else if (!dirPath.isEmpty()) {
// 暂时不要删除文件件功能
_deleteFileAction->setVisible(false);
#if 0
_deleteFileAction->setVisible(true);
_deleteFileActionFilePath = dirPath;
_deleteFileAction->setText(tr("删除文件夹"));
#endif
} else {
_deleteFileAction->setVisible(false);
}
// 只有当点击的是目录时才显示"新建文件夹"选项
bool isDir = !dirPath.isEmpty();
_createFolderAction->setVisible(isDir);
_contextMenu->exec(_treeWidget->mapToGlobal(pos));
}
}
void LeftWidget::slotDeleteActionTriggered()
{
if (_deleteFileActionFilePath.isEmpty()) {
return;
}
QFileInfo fileInfo(_deleteFileActionFilePath);
bool isDir = fileInfo.isDir();
// 检查文件/目录是否存在
if (!fileInfo.exists()) {
QMessageBox::warning(this, tr("警告"), tr("文件/目录不存在!"));
return;
}
// 确认删除对话框
int ret = QMessageBox::question(this, tr("确认删除"),
tr("确定要删除%1\n%2?").arg(isDir ? tr("文件夹及其所有内容") : tr("文件")).arg(_deleteFileActionFilePath),
QMessageBox::Yes | QMessageBox::No,
QMessageBox::No);
if (ret == QMessageBox::Yes) {
bool success;
if (isDir) {
// 删除目录及其内容
success = removeDir(_deleteFileActionFilePath);
} else {
// 删除文件
success = QFile::remove(_deleteFileActionFilePath);
}
if (success) {
// 重新加载文件树
reloadFileTree();
} else {
QMessageBox::critical(this, tr("错误"), tr("删除失败!"));
}
}
_deleteFileActionFilePath.clear();
}
bool LeftWidget::removeDir(const QString &dirPath)
{
bool result = true;
QDir dir(dirPath);
if (dir.exists(dirPath)) {
Q_FOREACH(QFileInfo info, dir.entryInfoList(QDir::NoDotAndDotDot | QDir::System | QDir::Hidden | QDir::AllDirs | QDir::Files, QDir::DirsFirst)) {
if (info.isDir()) {
result = removeDir(info.absoluteFilePath());
} else {
result = QFile::remove(info.absoluteFilePath());
}
if (!result) {
return result;
}
}
result = dir.rmdir(dirPath);
}
return result;
}
void LeftWidget::slotCreateFolderActionTriggered()
{
// 获取当前选中的项目
QTreeWidgetItem *currentItem = _treeWidget->currentItem();
if (!currentItem) {
return;
}
// 获取当前目录路径
QString dirPath;
if (currentItem->data(0, Qt::UserRole + 1).toString().isEmpty()) {
// 如果是文件,获取其父目录
dirPath = QFileInfo(currentItem->data(0, Qt::UserRole).toString()).absolutePath();
} else {
// 如果是目录,直接使用其路径
dirPath = currentItem->data(0, Qt::UserRole + 1).toString();
}
// 弹出对话框,输入新文件夹名称
bool ok;
QString folderName = QInputDialog::getText(this, tr("新建文件夹"),
tr("请输入文件夹名称:"),
QLineEdit::Normal,
tr("新建文件夹"), &ok);
if (!ok || folderName.isEmpty()) {
return;
}
// 检查文件夹名称是否有效
if (folderName.contains(QRegExp("[\\/:*?\"<>|]"))) {
QMessageBox::warning(this, tr("错误"), tr("文件夹名称包含非法字符!"));
return;
}
// 创建新文件夹路径
QString newFolderPath = dirPath + "/" + folderName;
// 检查文件夹是否已存在
if (QDir(newFolderPath).exists()) {
QMessageBox::warning(this, tr("错误"), tr("文件夹已存在!"));
return;
}
// 创建文件夹
if (QDir().mkdir(newFolderPath)) {
// 保存当前展开状态
saveExpandedState();
// 重新加载文件树
reloadFileTree();
// 恢复展开状态
restoreExpandedState();
// 展开当前目录并选中新创建的文件夹
expandAndSelectItem(newFolderPath);
} else {
QMessageBox::critical(this, tr("错误"), tr("创建文件夹失败!"));
}
}
void LeftWidget::expandAndSelectItem(const QString &path)
{
// 递归展开到指定路径并选中该项
QTreeWidgetItemIterator it(_treeWidget);
while (*it) {
QTreeWidgetItem *item = *it;
QString itemPath = item->data(0, Qt::UserRole + 1).toString();
if (itemPath == path) {
// 展开所有父节点
QTreeWidgetItem *parent = item->parent();
while (parent) {
parent->setExpanded(true);
parent = parent->parent();
}
// 选中新创建的文件夹
_treeWidget->setCurrentItem(item);
break;
}
++it;
}
}
void LeftWidget::confirmDelete(bool enabled)
{
if (enabled)
{
if (QFile::remove(_deleteFileActionFilePath))
{
// qDebug() << "文件删除成功:" << filePath;
logde << "delete succ:" << _deleteFileActionFilePath.toStdString();
}
else
{
// qWarning() << "文件删除失败:" << filePath;
logde << "delete fail:" << _deleteFileActionFilePath.toStdString();
}
// 重新加载文件树
reloadFileTree();
}
}
void LeftWidget::reloadFileTree()
{
// 保存当前展开状态
saveExpandedState();
// 清空现有的树形结构
_treeWidget->clear();
// 创建根节点
QTreeWidgetItem *rootItem = new QTreeWidgetItem(_treeWidget);
rootItem->setText(0, "实验数据");
rootItem->setData(0, Qt::UserRole, Global::ExperimentDirPath);
// 保存根目录路径,用于恢复展开状态
rootItem->setData(0, Qt::UserRole + 1, Global::ExperimentDirPath);
// 递归扫描目录并构建树形结构
buildFileTree(rootItem, Global::ExperimentDirPath);
// 展开根节点
rootItem->setExpanded(true);
// 恢复展开状态
restoreExpandedState();
// 更新全局文件列表
Global::updateFileList();
}
QFileInfoList LeftWidget::scanDirRecursively(const QString &rootPath)
{
QFileInfoList result; // 1. 结果容器
QDirIterator it(rootPath, // 2. 迭代器:从 rootPath 开始
QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot, // 3. 要哪些条目
QDirIterator::Subdirectories); // 4. 递归标志
while (it.hasNext())
{ // 5. 还有下一条吗?
it.next(); // 6. 推进到下一个条目
result.append(it.fileInfo()); // 7. 把当前条目塞进列表
}
return result; // 8. 返回
}
void LeftWidget::buildFileTree(QTreeWidgetItem *parentItem, const QString &dirPath)
{
QDir dir(dirPath);
if (!dir.exists()) {
qWarning() << "目录不存在: " << dirPath;
return;
}
// 获取所有子目录和文件,按名称排序
dir.setSorting(QDir::Name | QDir::DirsFirst);
QFileInfoList list = dir.entryInfoList(QDir::Dirs | QDir::Files | QDir::NoDotAndDotDot);
for (const QFileInfo &fileInfo : list) {
QTreeWidgetItem *item = new QTreeWidgetItem(parentItem);
if (fileInfo.isDir()) {
// 设置目录项
item->setText(0, fileInfo.fileName());
// 使用系统默认的目录图标
item->setIcon(0, _treeWidget->style()->standardIcon(QStyle::SP_DirIcon));
// 保存目录路径,用于恢复展开状态
item->setData(0, Qt::UserRole + 1, fileInfo.absoluteFilePath());
// 递归处理子目录
buildFileTree(item, fileInfo.absoluteFilePath());
} else {
// 设置文件项
item->setText(0, fileInfo.fileName());
item->setData(0, Qt::UserRole, fileInfo.absoluteFilePath());
// 根据文件类型设置不同的图标
QString suffix = fileInfo.suffix().toLower();
if (suffix == "xlsx" || suffix == "xls") {
// 使用系统默认的文档图标
item->setIcon(0, _treeWidget->style()->standardIcon(QStyle::SP_FileIcon));
} else {
// 使用默认文件图标
item->setIcon(0, _treeWidget->style()->standardIcon(QStyle::SP_FileIcon));
}
}
}
}
void LeftWidget::saveExpandedState()
{
_expandedPaths.clear();
// 递归遍历所有项,保存展开的目录路径
QTreeWidgetItemIterator it(_treeWidget);
while (*it) {
QTreeWidgetItem *item = *it;
if (item->isExpanded()) {
QVariant pathData = item->data(0, Qt::UserRole + 1);
if (!pathData.isNull()) {
_expandedPaths.append(pathData.toString());
}
}
++it;
}
qDebug() << "保存了" << _expandedPaths.size() << "个展开状态:" << _expandedPaths;
}
void LeftWidget::restoreExpandedState()
{
int restoredCount = 0;
// 递归遍历所有项,恢复展开状态
QTreeWidgetItemIterator it(_treeWidget);
while (*it) {
QTreeWidgetItem *item = *it;
QVariant pathData = item->data(0, Qt::UserRole + 1);
if (!pathData.isNull()) {
QString path = pathData.toString();
if (_expandedPaths.contains(path)) {
item->setExpanded(true);
restoredCount++;
}
}
++it;
}
qDebug() << "恢复了" << restoredCount << "个展开状态";
}