#include #include #include #include #include #include #include #include #include #include #include #include #include #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 << "个展开状态"; }