diff options
author | Saturn&Eric <[email protected]> | 2024-01-23 07:21:28 +0000 |
---|---|---|
committer | GitHub <[email protected]> | 2024-01-23 07:21:28 +0000 |
commit | 56acf161d439ce73eceaa145c40fe703bb2c3f02 (patch) | |
tree | a5d4790a6b2efc8786a3c0f74a07f5a8032d4e94 /src/ui/widgets/FileTreeView.cpp | |
parent | fix: use more secure cdn links (diff) | |
parent | fix: solve issues on detected gnupg path function and fix linking errors on w... (diff) | |
download | GpgFrontend-56acf161d439ce73eceaa145c40fe703bb2c3f02.tar.gz GpgFrontend-56acf161d439ce73eceaa145c40fe703bb2c3f02.zip |
Merge pull request #126 from saturneric/dev/2.1.1/main
Develop 2.1.2.1
Diffstat (limited to 'src/ui/widgets/FileTreeView.cpp')
-rw-r--r-- | src/ui/widgets/FileTreeView.cpp | 405 |
1 files changed, 405 insertions, 0 deletions
diff --git a/src/ui/widgets/FileTreeView.cpp b/src/ui/widgets/FileTreeView.cpp new file mode 100644 index 00000000..0c299a97 --- /dev/null +++ b/src/ui/widgets/FileTreeView.cpp @@ -0,0 +1,405 @@ +/** + * Copyright (C) 2021 Saturneric <[email protected]> + * + * This file is part of GpgFrontend. + * + * GpgFrontend is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GpgFrontend is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GpgFrontend. If not, see <https://www.gnu.org/licenses/>. + * + * The initial version of the source code is inherited from + * the gpg4usb project, which is under GPL-3.0-or-later. + * + * All the source code of GpgFrontend was modified and released by + * Saturneric <[email protected]> starting on May 12, 2021. + * + * SPDX-License-Identifier: GPL-3.0-or-later + * + */ + +#include "FileTreeView.h" + +#include "core/utils/AsyncUtils.h" +#include "core/utils/IOUtils.h" +#include "ui/UISignalStation.h" +#include "ui/UserInterfaceUtils.h" + +namespace GpgFrontend::UI { + +FileTreeView::FileTreeView(QWidget* parent, const QString& target_path) + : QTreeView(parent) { + dir_model_ = new QFileSystemModel(); + dir_model_->setRootPath(target_path.isEmpty() ? QDir::currentPath() + : target_path); + dir_model_->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); + + this->setModel(dir_model_); + this->setColumnWidth(0, 320); + this->sortByColumn(0, Qt::AscendingOrder); + current_path_ = dir_model_->rootPath(); + + slot_create_popup_menu(); + this->setContextMenuPolicy(Qt::CustomContextMenu); + connect(this, &QWidget::customContextMenuRequested, this, + &FileTreeView::slot_show_custom_context_menu); + connect(this, &QTreeView::doubleClicked, this, + &FileTreeView::slot_file_tree_view_item_double_clicked); +} + +void FileTreeView::selectionChanged(const QItemSelection& selected, + const QItemSelection& deselected) { + QTreeView::selectionChanged(selected, deselected); + GF_UI_LOG_DEBUG( + "file tree view selected changed, selected: {}, deselected: {}", + selected.size(), deselected.size()); + if (!selected.indexes().empty()) { + selected_path_ = dir_model_->filePath(selected.indexes().first()); + GF_UI_LOG_DEBUG("file tree view selected target path: {}", selected_path_); + emit SignalSelectedChanged(selected_path_); + } else { + selected_path_ = {}; + if (!this->selectedIndexes().isEmpty()) { + selected_path_ = dir_model_->filePath(this->selectedIndexes().front()); + emit SignalSelectedChanged(selected_path_); + } + } +} + +void FileTreeView::SlotGoPath(const QString& target_path) { + auto file_info = QFileInfo(target_path); + if (file_info.isDir() && file_info.isReadable() && file_info.isExecutable()) { + current_path_ = file_info.absoluteFilePath(); + GF_UI_LOG_DEBUG("file tree view set target path: {}", current_path_); + this->setRootIndex(dir_model_->index(file_info.filePath())); + dir_model_->setRootPath(file_info.filePath()); + for (int i = 1; i < dir_model_->columnCount(); ++i) { + this->resizeColumnToContents(i); + } + } else { + QMessageBox::critical( + this, tr("Error"), + tr("The path is not exists, unprivileged or unreachable.")); + } + emit SignalPathChanged(current_path_); +} + +void FileTreeView::slot_file_tree_view_item_double_clicked( + const QModelIndex& index) { + QFileInfo const file_info(dir_model_->fileInfo(index).absoluteFilePath()); + if (file_info.isFile()) { + if (file_info.isReadable()) { + emit SignalOpenFile(file_info.absoluteFilePath()); + } else { + QMessageBox::critical(this, tr("Error"), + tr("The file is unprivileged or unreachable.")); + } + } else { + SlotGoPath(file_info.absoluteFilePath()); + } +} + +void FileTreeView::SlotUpLevel() { + QModelIndex const current_root = this->rootIndex(); + + auto target_path = dir_model_->fileInfo(current_root).absoluteFilePath(); + if (auto parent_path = QDir(target_path); parent_path.cdUp()) { + target_path = parent_path.absolutePath(); + GF_UI_LOG_DEBUG("file tree view go parent path: {}", target_path); + this->SlotGoPath(target_path); + } + current_path_ = target_path; +} + +auto FileTreeView::GetCurrentPath() -> QString { return current_path_; } + +void FileTreeView::SlotShowSystemFile(bool on) { + auto filters = on ? dir_model_->filter() | QDir::System + : dir_model_->filter() & ~QDir::System; + dir_model_->setFilter(filters); + dir_model_->setRootPath(current_path_); +} + +void FileTreeView::SlotShowHiddenFile(bool on) { + auto filters = on ? dir_model_->filter() | QDir::Hidden + : dir_model_->filter() & ~QDir::Hidden; + dir_model_->setFilter(filters); + dir_model_->setRootPath(current_path_); +} + +auto FileTreeView::GetPathByClickPoint(const QPoint& point) -> QString { + auto const index = this->indexAt(point); + + if (!index.isValid()) { + return {}; + } + + auto index_path = dir_model_->fileInfo(index).absoluteFilePath(); + GF_UI_LOG_DEBUG("file tree view right click on: {}", index_path); + return index_path; +} + +auto FileTreeView::GetSelectedPath() -> QString { return selected_path_; } + +auto FileTreeView::SlotDeleteSelectedItem() -> void { + QModelIndex const index = this->currentIndex(); + QVariant const data = this->model()->data(index); + + auto ret = QMessageBox::warning(this, tr("Warning"), + tr("Are you sure you want to delete it?"), + QMessageBox::Ok | QMessageBox::Cancel); + + if (ret == QMessageBox::Cancel) return; + + GF_UI_LOG_DEBUG("delete item: {}", data.toString().toStdString()); + + if (!dir_model_->remove(index)) { + QMessageBox::critical(this, tr("Error"), + tr("Unable to delete the file or folder.")); + } +} + +void FileTreeView::SlotMkdir() { + auto index = this->rootIndex(); + + QString new_dir_name; + bool ok; + new_dir_name = QInputDialog::getText(this, tr("Make New Directory"), + tr("Directory Name"), QLineEdit::Normal, + new_dir_name, &ok); + if (ok && !new_dir_name.isEmpty()) { + dir_model_->mkdir(index, new_dir_name); + } +} + +void FileTreeView::SlotMkdirBelowAtSelectedItem() { + auto index = this->currentIndex(); + + QString new_dir_name; + bool ok; + new_dir_name = QInputDialog::getText(this, tr("Make New Directory"), + tr("Directory Name"), QLineEdit::Normal, + new_dir_name, &ok); + if (ok && !new_dir_name.isEmpty()) { + dir_model_->mkdir(index, new_dir_name); + } +} + +void FileTreeView::SlotTouch() { +#ifdef WINDOWS + auto root_path_str = dir_model_->rootPath().toStdU16String(); +#else + auto root_path_str = dir_model_->rootPath().toStdString(); +#endif + std::filesystem::path root_path(root_path_str); + + QString new_file_name; + bool ok; + new_file_name = QInputDialog::getText( + this, tr("Create Empty File"), tr("Filename (you can given extension)"), + QLineEdit::Normal, new_file_name, &ok); + if (ok && !new_file_name.isEmpty()) { +#ifdef WINDOWS + auto file_path = root_path / new_file_name.toStdU16String(); +#else + auto file_path = root_path / new_file_name.toStdString(); +#endif + QFile new_file(file_path.u8string().c_str()); + if (!new_file.open(QIODevice::WriteOnly | QIODevice::NewOnly)) { + QMessageBox::critical(this, tr("Error"), + tr("Unable to create the file.")); + } + new_file.close(); + } +} + +void FileTreeView::SlotTouchBelowAtSelectedItem() { + auto root_path(selected_path_); + + QString new_file_name; + bool ok; + new_file_name = QInputDialog::getText( + this, tr("Create Empty File"), tr("Filename (you can given extension)"), + QLineEdit::Normal, new_file_name, &ok); + if (ok && !new_file_name.isEmpty()) { + auto file_path = root_path + "/" + new_file_name; + + QFile new_file(file_path); + if (!new_file.open(QIODevice::WriteOnly | QIODevice::NewOnly)) { + QMessageBox::critical(this, tr("Error"), + tr("Unable to create the file.")); + } + new_file.close(); + } +} + +void FileTreeView::keyPressEvent(QKeyEvent* event) { + QTreeView::keyPressEvent(event); + + if (this->currentIndex().isValid()) { + if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) { + slot_file_tree_view_item_double_clicked(this->currentIndex()); + } else if (event->key() == Qt::Key_Delete || + event->key() == Qt::Key_Backspace) { + SlotDeleteSelectedItem(); + } + } +} + +void FileTreeView::SlotOpenSelectedItemBySystemApplication() { + QFileInfo const info(selected_path_); + if (info.isDir()) { + const auto file_path = info.filePath().toUtf8().toStdString(); + QDesktopServices::openUrl(QUrl::fromLocalFile(selected_path_)); + + } else { + QDesktopServices::openUrl(QUrl::fromLocalFile(selected_path_)); + } +} + +void FileTreeView::SlotRenameSelectedItem() { + bool ok; + auto text = QInputDialog::getText(this, tr("Rename"), tr("New Filename"), + QLineEdit::Normal, + QFileInfo(selected_path_).fileName(), &ok); + if (ok && !text.isEmpty()) { + auto file_info = QFileInfo(selected_path_); + auto new_name_path = file_info.absolutePath() + "/" + text; + GF_UI_LOG_DEBUG("new filename path: {}", new_name_path); + if (QDir().rename(file_info.absoluteFilePath(), new_name_path)) { + QMessageBox::critical(this, tr("Error"), + tr("Unable to rename the file or folder.")); + return; + } + + // refresh + SlotGoPath(current_path_); + } +} + +auto FileTreeView::GetMousePointGlobal(const QPoint& point) -> QPoint { + return this->viewport()->mapToGlobal(point); +} + +void FileTreeView::slot_create_popup_menu() { + popup_menu_ = new QMenu(); + + action_open_file_ = new QAction(this); + action_open_file_->setText(tr("Open")); + connect(action_open_file_, &QAction::triggered, this, + [this](bool) { emit SignalOpenFile(GetSelectedPath()); }); + + action_rename_file_ = new QAction(this); + action_rename_file_->setText(tr("Rename")); + connect(action_rename_file_, &QAction::triggered, this, + &FileTreeView::SlotRenameSelectedItem); + + action_delete_file_ = new QAction(this); + action_delete_file_->setText(tr("Delete")); + connect(action_delete_file_, &QAction::triggered, this, + &FileTreeView::SlotDeleteSelectedItem); + + action_calculate_hash_ = new QAction(this); + action_calculate_hash_->setText(tr("Calculate Hash")); + connect(action_calculate_hash_, &QAction::triggered, this, + &FileTreeView::slot_calculate_hash); + + action_make_directory_ = new QAction(this); + action_make_directory_->setText(tr("Directory")); + connect(action_make_directory_, &QAction::triggered, this, + &FileTreeView::SlotMkdirBelowAtSelectedItem); + + action_create_empty_file_ = new QAction(this); + action_create_empty_file_->setText(tr("File")); + connect(action_create_empty_file_, &QAction::triggered, this, + &FileTreeView::SlotTouchBelowAtSelectedItem); + + action_compress_files_ = new QAction(this); + action_compress_files_->setText(tr("Compress...")); + action_compress_files_->setVisible(false); + connect(action_compress_files_, &QAction::triggered, this, + &FileTreeView::slot_compress_files); + + auto* action_open_with_system_default_application = new QAction(this); + action_open_with_system_default_application->setText( + tr("Open with Default System Application")); + connect(action_open_with_system_default_application, &QAction::triggered, + this, &FileTreeView::SlotOpenSelectedItemBySystemApplication); + + auto* new_item_action_menu = new QMenu(this); + new_item_action_menu->setTitle(tr("New")); + new_item_action_menu->addAction(action_create_empty_file_); + new_item_action_menu->addAction(action_make_directory_); + + popup_menu_->addAction(action_open_file_); + popup_menu_->addAction(action_open_with_system_default_application); + + popup_menu_->addSeparator(); + popup_menu_->addMenu(new_item_action_menu); + popup_menu_->addSeparator(); + + popup_menu_->addAction(action_rename_file_); + popup_menu_->addAction(action_delete_file_); + popup_menu_->addAction(action_compress_files_); + popup_menu_->addAction(action_calculate_hash_); +} + +void FileTreeView::slot_show_custom_context_menu(const QPoint& point) { + auto target_path = this->GetPathByClickPoint(point); + + if (!target_path.isEmpty()) { + action_open_file_->setEnabled(true); + action_rename_file_->setEnabled(true); + action_delete_file_->setEnabled(true); + + QFileInfo const info(this->GetSelectedPath()); + action_calculate_hash_->setEnabled(info.isFile() && info.isReadable()); + + } else { + action_open_file_->setEnabled(false); + action_rename_file_->setEnabled(false); + action_delete_file_->setEnabled(false); + + action_calculate_hash_->setEnabled(false); + } + popup_menu_->exec(this->GetMousePointGlobal(point)); +} + +void FileTreeView::slot_calculate_hash() { + CommonUtils::WaitForOpera( + this->parentWidget(), tr("Calculating"), [=](const OperaWaitingHd& hd) { + RunOperaAsync( + [=](DataObjectPtr data_object) { + data_object->Swap({CalculateHash(this->GetSelectedPath())}); + return 0; + }, + [hd](int rtn, DataObjectPtr data_object) { + hd(); + if (rtn < 0 || !data_object->Check<QString>()) { + return; + } + auto result = ExtractParams<QString>(data_object, 0); + emit UISignalStation::GetInstance()->SignalRefreshInfoBoard( + result, InfoBoardStatus::INFO_ERROR_OK); + }, + "calculate_file_hash"); + }); +} + +void FileTreeView::slot_compress_files() {} + +void FileTreeView::paintEvent(QPaintEvent* event) { + QTreeView::paintEvent(event); + for (int i = 1; i < dir_model_->columnCount(); ++i) { + this->resizeColumnToContents(i); + } +} +} // namespace GpgFrontend::UI |