aboutsummaryrefslogtreecommitdiffstats
path: root/src/ui/widgets/FileTreeView.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui/widgets/FileTreeView.cpp')
-rw-r--r--src/ui/widgets/FileTreeView.cpp403
1 files changed, 403 insertions, 0 deletions
diff --git a/src/ui/widgets/FileTreeView.cpp b/src/ui/widgets/FileTreeView.cpp
new file mode 100644
index 00000000..f3556dc9
--- /dev/null
+++ b/src/ui/widgets/FileTreeView.cpp
@@ -0,0 +1,403 @@
+/**
+ * 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/IOUtils.h"
+#include "ui/UISignalStation.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_ = std::filesystem::path(dir_model_->rootPath().toStdString());
+
+ 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);
+
+ if (!selected.indexes().empty()) {
+ selected_path_ = dir_model_->fileInfo(selected.indexes().first())
+ .filesystemAbsoluteFilePath();
+ GF_UI_LOG_DEBUG("file tree view selected target path: {}",
+ selected_path_.u8string());
+ emit SignalSelectedChanged(QString::fromStdString(selected_path_));
+ } else {
+ selected_path_ = std::filesystem::path{};
+ }
+}
+
+void FileTreeView::SlotGoPath(const std::filesystem::path& target_path) {
+ auto file_info = QFileInfo(target_path);
+ if (file_info.isDir() && file_info.isReadable() && file_info.isExecutable()) {
+ current_path_ = file_info.filesystemAbsoluteFilePath();
+ GF_UI_LOG_DEBUG("file tree view set target path: {}",
+ current_path_.u8string());
+ 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(QString::fromStdString(current_path_.u8string()));
+}
+
+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.filesystemAbsoluteFilePath());
+ }
+}
+
+void FileTreeView::SlotUpLevel() {
+ QModelIndex const current_root = this->rootIndex();
+
+ auto target_path =
+ dir_model_->fileInfo(current_root).filesystemAbsoluteFilePath();
+ if (target_path.has_parent_path() && !target_path.parent_path().empty()) {
+ target_path = target_path.parent_path();
+ GF_UI_LOG_DEBUG("file tree view go parent path: {}",
+ target_path.u8string());
+ this->SlotGoPath(target_path);
+ }
+ current_path_ = target_path;
+}
+
+auto FileTreeView::GetCurrentPath() -> std::filesystem::path {
+ 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(QString::fromStdString(current_path_.u8string()));
+}
+
+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(QString::fromStdString(current_path_.u8string()));
+}
+
+auto FileTreeView::GetPathByClickPoint(const QPoint& point)
+ -> std::filesystem::path {
+ auto const index = this->indexAt(point);
+
+ if (!index.isValid()) {
+ return {};
+ }
+
+ auto index_path = dir_model_->fileInfo(index).filesystemAbsoluteFilePath();
+ GF_UI_LOG_DEBUG("file tree view right click on: {}", index_path.string());
+ return index_path;
+}
+
+auto FileTreeView::GetSelectedPath() -> std::filesystem::path {
+ 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() {
+ std::filesystem::path 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()) {
+#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::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(QString::fromStdString(selected_path_.u8string()));
+ auto q_selected_path = QString::fromStdString(selected_path_.u8string());
+ if (info.isDir()) {
+ const auto file_path = info.filePath().toUtf8().toStdString();
+ QDesktopServices::openUrl(QUrl::fromLocalFile(q_selected_path));
+
+ } else {
+ QDesktopServices::openUrl(QUrl::fromLocalFile(q_selected_path));
+ }
+}
+
+void FileTreeView::SlotRenameSelectedItem() {
+ bool ok;
+ auto text = QInputDialog::getText(
+ this, tr("Rename"), tr("New Filename"), QLineEdit::Normal,
+ QString::fromStdString(selected_path_.filename().u8string()), &ok);
+ if (ok && !text.isEmpty()) {
+ try {
+#ifdef WINDOWS
+ auto new_name_path = selected_path_.parent_path() / text.toStdU16String();
+#else
+ auto new_name_path = selected_path_.parent_path() / text.toStdString();
+#endif
+ GF_UI_LOG_DEBUG("new name path: {}", new_name_path.u8string());
+ std::filesystem::rename(selected_path_, new_name_path);
+
+ // refresh
+ SlotGoPath(current_path_);
+ } catch (...) {
+ GF_UI_LOG_ERROR("file tree view rename error: {}",
+ selected_path_.u8string());
+ QMessageBox::critical(this, tr("Error"),
+ tr("Unable to rename the file or folder."));
+ }
+ }
+}
+
+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(QString::fromStdString(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.empty()) {
+ action_open_file_->setEnabled(true);
+ action_rename_file_->setEnabled(true);
+ action_delete_file_->setEnabled(true);
+
+ QFileInfo const info(QString::fromStdString(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() {
+ emit UISignalStation::GetInstance()->SignalRefreshInfoBoard(
+ CalculateHash(this->GetSelectedPath().c_str()),
+ InfoBoardStatus::INFO_ERROR_OK);
+}
+
+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