diff options
author | Saturneric <[email protected]> | 2022-03-12 09:54:10 +0000 |
---|---|---|
committer | Saturneric <[email protected]> | 2022-03-12 09:54:10 +0000 |
commit | db24670fedfa8fd9cf207ffd35e41b00f4f3497f (patch) | |
tree | 6c1aae26444a821609fda3ba6d8fb7182615e2f3 /src | |
parent | <fix>(core): Fix the existing problem of the key package (diff) | |
download | GpgFrontend-db24670fedfa8fd9cf207ffd35e41b00f4f3497f.tar.gz GpgFrontend-db24670fedfa8fd9cf207ffd35e41b00f4f3497f.zip |
<feat>(core, ui): Provides the ability to handle folders
1. Convert folders to archive format for processing
Diffstat (limited to 'src')
-rw-r--r-- | src/core/function/ArchiveFileOperator.cpp | 238 | ||||
-rw-r--r-- | src/core/function/ArchiveFileOperator.h | 79 | ||||
-rw-r--r-- | src/ui/main_window/MainWindowFileSlotFunction.cpp | 206 | ||||
-rw-r--r-- | src/ui/widgets/FilePage.cpp | 62 | ||||
-rw-r--r-- | src/ui/widgets/FilePage.h | 6 |
5 files changed, 554 insertions, 37 deletions
diff --git a/src/core/function/ArchiveFileOperator.cpp b/src/core/function/ArchiveFileOperator.cpp new file mode 100644 index 00000000..6315dcd5 --- /dev/null +++ b/src/core/function/ArchiveFileOperator.cpp @@ -0,0 +1,238 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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 "ArchiveFileOperator.h" + +int copy_data(struct archive *ar, struct archive *aw) { + int r; + const void *buff; + size_t size; + int64_t offset; + + for (;;) { + r = archive_read_data_block(ar, &buff, &size, &offset); + if (r == ARCHIVE_EOF) + return (ARCHIVE_OK); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_read_data_block() failed: " << archive_error_string(ar); + return (r); + } + r = archive_write_data_block(aw, buff, size, offset); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_write_data_block() failed: " << archive_error_string(aw); + return (r); + } + } +} + +void GpgFrontend::ArchiveFileOperator::CreateArchive( + const std::filesystem::path &base_path, + const std::filesystem::path &archive_path, int compress, + const std::vector<std::filesystem::path> &files) { + LOG(INFO) << "CreateArchive: " << archive_path.string(); + + auto current_base_path_backup = QDir::currentPath(); + QDir::setCurrent(base_path.string().c_str()); + + auto relative_archive_path = std::filesystem::relative(archive_path, base_path); + + std::vector<std::filesystem::path> relative_files; + relative_files.reserve(files.size()); + for(const auto& file : files) { + relative_files.push_back(std::filesystem::relative(file, base_path)); + } + + struct archive *a; + struct archive_entry *entry; + ssize_t len; + int fd; + + LOG(INFO) << "compress: " << compress; + + a = archive_write_new(); + switch (compress) { +#ifndef NO_BZIP2_CREATE + case 'j': + case 'y': + archive_write_add_filter_bzip2(a); + break; +#endif +#ifndef NO_COMPRESS_CREATE + case 'Z': + archive_write_add_filter_compress(a); + break; +#endif +#ifndef NO_GZIP_CREATE + case 'z': + archive_write_add_filter_gzip(a); + break; +#endif + default: + archive_write_add_filter_none(a); + break; + } + archive_write_set_format_ustar(a); + archive_write_set_format_pax_restricted(a); + + auto filename = relative_archive_path.string(); + if (!filename.empty() && filename == "-") + throw std::runtime_error("cannot write to stdout"); + + archive_write_open_filename(a, filename.c_str()); + + for (const auto &file : relative_files) { + struct archive *disk = archive_read_disk_new(); +#ifndef NO_LOOKUP + archive_read_disk_set_standard_lookup(disk); +#endif + int r; + + LOG(INFO) << "ReadFile: " << file.string(); + + r = archive_read_disk_open(disk, file.string().c_str()); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_read_disk_open() failed: " + << archive_error_string(disk); + throw std::runtime_error("archive_read_disk_open() failed"); + } + + for (;;) { + bool needcr = false; + + entry = archive_entry_new(); + r = archive_read_next_header2(disk, entry); + if (r == ARCHIVE_EOF) break; + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_read_next_header2() failed: " + << archive_error_string(disk); + throw std::runtime_error("archive_read_next_header2() failed"); + } + archive_read_disk_descend(disk); + LOG(INFO) << "Adding: " << archive_entry_pathname(entry) << "size" + << archive_entry_size(entry) << " bytes" + << "file type" << archive_entry_filetype(entry); + r = archive_write_header(a, entry); + if (r < ARCHIVE_OK) { + LOG(ERROR) << "archive_write_header() failed: " + << archive_error_string(a); + throw std::runtime_error("archive_write_header() failed"); + } + if (r == ARCHIVE_FATAL) throw std::runtime_error("archive fatal"); + if (r > ARCHIVE_FAILED) { + ByteArray buff; + FileOperator::ReadFileStd(archive_entry_sourcepath(entry), buff); + archive_write_data(a, buff.c_str(), buff.size()); + } + archive_entry_free(entry); + } + archive_read_close(disk); + archive_read_free(disk); + } + archive_write_close(a); + archive_write_free(a); + + QDir::setCurrent(current_base_path_backup); +} + +void GpgFrontend::ArchiveFileOperator::ExtractArchive( + const std::filesystem::path &archive_path, + const std::filesystem::path &base_path) { + + LOG(INFO) << "ExtractArchive: " << archive_path.string(); + + auto current_base_path_backup = QDir::currentPath(); + QDir::setCurrent(base_path.string().c_str()); + + struct archive *a; + struct archive *ext; + struct archive_entry *entry; + int r; + + a = archive_read_new(); + ext = archive_write_disk_new(); + archive_write_disk_set_options(ext, 0); +#ifndef NO_BZIP2_EXTRACT + archive_read_support_filter_bzip2(a); +#endif +#ifndef NO_GZIP_EXTRACT + archive_read_support_filter_gzip(a); +#endif +#ifndef NO_COMPRESS_EXTRACT + archive_read_support_filter_compress(a); +#endif +#ifndef NO_TAR_EXTRACT + archive_read_support_format_tar(a); +#endif +#ifndef NO_CPIO_EXTRACT + archive_read_support_format_cpio(a); +#endif +#ifndef NO_LOOKUP + archive_write_disk_set_standard_lookup(ext); +#endif + + auto filename = archive_path.string(); + + if (!filename.empty() && filename == "-") { + LOG(ERROR) << "cannot read from stdin"; + } + if ((r = archive_read_open_filename(a, filename.c_str(), 10240))) { + LOG(ERROR) << "archive_read_open_filename() failed: " + << archive_error_string(a); + throw std::runtime_error("archive_read_open_filename() failed"); + } + for (;;) { + r = archive_read_next_header(a, &entry); + if (r == ARCHIVE_EOF) + break; + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_read_next_header() failed: " + << archive_error_string(a); + throw std::runtime_error("archive_read_next_header() failed"); + } + LOG(INFO) << "Extracting: " << archive_entry_pathname(entry) + << "size" << archive_entry_size(entry) << " bytes" + << "file type" << archive_entry_filetype(entry); + r = archive_write_header(ext, entry); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "archive_write_header() failed: " + << archive_error_string(ext); + } else { + r = copy_data(a, ext); + if (r != ARCHIVE_OK) { + LOG(ERROR) << "copy_data() failed: " << archive_error_string(ext); + } + } + } + archive_read_close(a); + archive_read_free(a); + + archive_write_close(ext); + archive_write_free(ext); + + QDir::setCurrent(current_base_path_backup); +} diff --git a/src/core/function/ArchiveFileOperator.h b/src/core/function/ArchiveFileOperator.h new file mode 100644 index 00000000..8e1d9c44 --- /dev/null +++ b/src/core/function/ArchiveFileOperator.h @@ -0,0 +1,79 @@ +/** + * Copyright (C) 2021 Saturneric + * + * 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 + * + */ + +#ifndef GPGFRONTEND_ARCHIVEFILEOPERATOR_H +#define GPGFRONTEND_ARCHIVEFILEOPERATOR_H + +#include "core/GpgFrontendCore.h" +#include "core/function/FileOperator.h" + +namespace GpgFrontend { + +struct ArchiveStruct { + struct archive *archive; + struct archive_entry *entry; + int fd; + bool is_open; + std::string name; +}; + +class ArchiveFileOperator { + public: + static void ListArchive(const std::filesystem::path &archive_path) { + struct archive *a; + struct archive_entry *entry; + int r; + + a = archive_read_new(); + archive_read_support_filter_all(a); + archive_read_support_format_all(a); + r = archive_read_open_filename(a, archive_path.string().c_str(), + 10240); // Note 1 + if (r != ARCHIVE_OK) return; + while (archive_read_next_header(a, &entry) == ARCHIVE_OK) { + LOG(INFO) << "File: " << archive_entry_pathname(entry); + LOG(INFO) << "File Path: " << archive_entry_pathname(entry); + archive_read_data_skip(a); // Note 2 + } + r = archive_read_free(a); // Note 3 + if (r != ARCHIVE_OK) return; + } + + static void CreateArchive( + const std::filesystem::path &base_path, + const std::filesystem::path &archive_path, + int compress, + const std::vector<std::filesystem::path> &files); + + static void ExtractArchive( + const std::filesystem::path &archive_path, + const std::filesystem::path &base_path); +}; +} // namespace GpgFrontend + +#endif // GPGFRONTEND_ARCHIVEFILEOPERATOR_H diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp index 21516c6d..a3a44e68 100644 --- a/src/ui/main_window/MainWindowFileSlotFunction.cpp +++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp @@ -27,20 +27,21 @@ */ #include "MainWindow.h" +#include "core/function/ArchiveFileOperator.h" +#include "core/function/GlobalSettingStation.h" #include "core/function/gpg/GpgFileOpera.h" #include "core/function/gpg/GpgKeyGetter.h" #include "ui/UserInterfaceUtils.h" -#include "core/function/GlobalSettingStation.h" #include "ui/widgets/SignersPicker.h" namespace GpgFrontend::UI { -bool file_pre_check(QWidget* parent, const QString& path) { +bool path_pre_check(QWidget* parent, const QString& path) { QFileInfo file_info(path); QFileInfo path_info(file_info.absolutePath()); - if (!file_info.isFile()) { + if (!path_info.exists()) { QMessageBox::critical(parent, _("Error"), - _("Select a file before doing it.")); + QString(_("The path %1 does not exist.")).arg(path)); return false; } if (!file_info.isReadable()) { @@ -56,11 +57,94 @@ bool file_pre_check(QWidget* parent, const QString& path) { return true; } +/** + * @brief convert directory into tarball + * + * @param parent parent widget + * @param path the directory to be converted + * @return + */ +bool process_tarball_into_directory(QWidget* parent, + std::filesystem::path& path) { + auto selected_dir_path = std::filesystem::path(path); + + if (selected_dir_path.extension() != ".tar") { + QMessageBox::critical(parent, _("Error"), _("The file is not a tarball.")); + return false; + } + + try { + auto base_path = selected_dir_path.parent_path(); + + auto target_path = selected_dir_path; + target_path.replace_extension(".tar"); + + LOG(INFO) << "base path" << base_path << "target archive path" + << target_path; + + bool if_error = false; + process_operation(parent, _("Extracting Tarball"), [&]() { + try { + GpgFrontend::ArchiveFileOperator::ExtractArchive(target_path, + base_path); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (if_error || !exists(target_path)) { + throw std::runtime_error("Decompress Failed"); + } + path = target_path.string().c_str(); + } catch (...) { + LOG(ERROR) << "decompress error"; + return false; + } + return true; +} + +/** + * @brief convert tarball into directory + * + * @param parent parent widget + * @param path the tarball to be converted + */ +bool process_directory_into_tarball(QWidget* parent, QString& path) { + auto selected_dir_path = std::filesystem::path(path.toStdString()); + try { + auto base_path = selected_dir_path.parent_path(); + auto target_path = selected_dir_path; + selected_dir_path.replace_extension(""); + + LOG(INFO) << "base path" << base_path << "target archive path" + << target_path << "selected_dir_path" << selected_dir_path; + + bool if_error = false; + process_operation(parent, _("Making Tarball"), [&]() { + try { + GpgFrontend::ArchiveFileOperator::CreateArchive(base_path, target_path, + 0, {selected_dir_path}); + } catch (const std::runtime_error& e) { + if_error = true; + } + }); + + if (if_error || !exists(target_path)) { + throw std::runtime_error("Compress Failed"); + } + path = target_path.string().c_str(); + } catch (...) { + LOG(ERROR) << "compress error"; + return false; + } + return true; +} + void MainWindow::SlotFileEncrypt() { auto fileTreeView = edit_->SlotCurPageFileTreeView(); auto path = fileTreeView->GetSelected(); - if (!file_pre_check(this, path)) return; + if (!path_pre_check(this, path)) return; // check selected keys auto key_ids = m_key_list_->GetChecked(); @@ -77,9 +161,16 @@ void MainWindow::SlotFileEncrypt() { LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); } + // get file info + QFileInfo file_info(path); + + if (file_info.isDir()) { + path = path + (file_info.isDir() ? ".tar" : ""); + } + auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; auto _extension = ".asc"; - if (non_ascii_when_export) { + if (non_ascii_when_export || file_info.isDir()) { _channel = GPGFRONTEND_NON_ASCII_CHANNEL; _extension = ".gpg"; } @@ -98,6 +189,15 @@ void MainWindow::SlotFileEncrypt() { if (ret == QMessageBox::Cancel) return; } + if (file_info.isDir()) { + // stop if the process making tarball failed + if (!process_directory_into_tarball(this, path)) { + QMessageBox::critical(this, _("Error"), + _("Unable to convert the folder into tarball.")); + return; + } + } + if (key_ids->empty()) { // Symmetric Encrypt auto ret = QMessageBox::information( @@ -144,6 +244,15 @@ void MainWindow::SlotFileEncrypt() { }); } + // remove xxx.tar and only left xxx.tar.gpg + if (file_info.isDir()) { + auto selected_dir_path = std::filesystem::path(path.toStdString()); + auto target_path = selected_dir_path.replace_extension(".tar"); + if (exists(target_path)) { + std::filesystem::remove(target_path); + } + } + if (!if_error) { auto resultAnalyse = GpgEncryptResultAnalyse(error, std::move(result)); resultAnalyse.Analyse(); @@ -160,7 +269,7 @@ void MainWindow::SlotFileDecrypt() { auto fileTreeView = edit_->SlotCurPageFileTreeView(); auto path = fileTreeView->GetSelected(); - if (!file_pre_check(this, path)) return; + if (!path_pre_check(this, path)) return; std::filesystem::path out_path = path.toStdString(); @@ -202,13 +311,33 @@ void MainWindow::SlotFileDecrypt() { _("An error occurred during operation.")); return; } + + // extract the tarball + if (out_path.extension() == ".tar") { + bool ret = QMessageBox::information( + this, _("Decrypting"), + _("Do you want to extract and delete the decrypted tarball?"), + QMessageBox::Ok | QMessageBox::Cancel); + if (ret) { + if (process_tarball_into_directory(this, out_path)) { + QMessageBox::information(this, _("Decrypting"), + _("Extracting tarball succeeded.")); + // remove tarball + std::filesystem::remove(out_path); + } else { + QMessageBox::critical(this, _("Decrypting"), + _("Extracting tarball failed.")); + } + } + } + } void MainWindow::SlotFileSign() { auto fileTreeView = edit_->SlotCurPageFileTreeView(); auto path = fileTreeView->GetSelected(); - if (!file_pre_check(this, path)) return; + if (!path_pre_check(this, path)) return; auto key_ids = m_key_list_->GetChecked(); auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids); @@ -379,7 +508,7 @@ void MainWindow::SlotFileEncryptSign() { auto fileTreeView = edit_->SlotCurPageFileTreeView(); auto path = fileTreeView->GetSelected(); - if (!file_pre_check(this, path)) return; + if (!path_pre_check(this, path)) return; // check selected keys auto key_ids = m_key_list_->GetChecked(); @@ -406,7 +535,7 @@ void MainWindow::SlotFileEncryptSign() { } } - // Detect ascii mode + // detect ascii mode auto& settings = GlobalSettingStation::GetInstance().GetUISettings(); bool non_ascii_when_export = true; try { @@ -415,16 +544,23 @@ void MainWindow::SlotFileEncryptSign() { LOG(ERROR) << _("Setting Operation Error") << _("non_ascii_when_export"); } + // get file info + QFileInfo file_info(path); + + if (file_info.isDir()) { + path = path + (file_info.isDir() ? ".tar" : ""); + } + auto _channel = GPGFRONTEND_DEFAULT_CHANNEL; auto _extension = ".asc"; - if (non_ascii_when_export) { + if (non_ascii_when_export || file_info.isDir()) { _channel = GPGFRONTEND_NON_ASCII_CHANNEL; _extension = ".gpg"; } - std::filesystem::path out_path = path.toStdString() + _extension; + auto out_path = path + _extension; - if (exists(out_path)) { + if (QFile::exists(out_path)) { auto ret = QMessageBox::warning( this, _("Warning"), _("The target file already exists, do you need to overwrite it?"), @@ -441,6 +577,16 @@ void MainWindow::SlotFileEncryptSign() { auto signer_key_ids = signersPicker->GetCheckedSigners(); auto p_signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids); + // convert directory into tarball + if (file_info.isDir()) { + // stop if the process making tarball failed + if (!process_directory_into_tarball(this, path)) { + QMessageBox::critical(this, _("Error"), + _("Unable to convert the folder into tarball.")); + return; + } + } + GpgEncrResult encr_result = nullptr; GpgSignResult sign_result = nullptr; @@ -451,7 +597,7 @@ void MainWindow::SlotFileEncryptSign() { try { error = GpgFileOpera::EncryptSignFile( std::move(p_keys), std::move(p_signer_keys), path.toStdString(), - out_path.string(), encr_result, sign_result, _channel); + out_path.toStdString(), encr_result, sign_result, _channel); } catch (const std::runtime_error& e) { if_error = true; } @@ -472,13 +618,23 @@ void MainWindow::SlotFileEncryptSign() { _("An error occurred during operation.")); return; } + + // remove xxx.tar and only left xxx.tar.gpg + if (file_info.isDir()) { + auto selected_dir_path = std::filesystem::path(path.toStdString()); + auto target_path = selected_dir_path.replace_extension(".tar"); + if (exists(target_path)) { + std::filesystem::remove(target_path); + } + } + } void MainWindow::SlotFileDecryptVerify() { auto fileTreeView = edit_->SlotCurPageFileTreeView(); auto path = fileTreeView->GetSelected(); - if (!file_pre_check(this, path)) return; + if (!path_pre_check(this, path)) return; std::filesystem::path in_path(path.toStdString()); std::filesystem::path out_path = in_path; @@ -532,6 +688,26 @@ void MainWindow::SlotFileDecryptVerify() { _("An error occurred during operation.")); return; } + + // extract the tarball + if (out_path.extension() == ".tar") { + bool ret = QMessageBox::information( + this, _("Decrypting"), + _("Do you want to extract and delete the decrypted tarball?"), + QMessageBox::Ok | QMessageBox::Cancel); + if (ret) { + if (process_tarball_into_directory(this, out_path)) { + QMessageBox::information(this, _("Decrypting"), + _("Extracting tarball succeeded.")); + // remove tarball + std::filesystem::remove(out_path); + } else { + QMessageBox::critical(this, _("Decrypting"), + _("Extracting tarball failed.")); + } + } + } + } } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp index bbe5e548..7682448d 100644 --- a/src/ui/widgets/FilePage.cpp +++ b/src/ui/widgets/FilePage.cpp @@ -30,8 +30,10 @@ #include <string> -#include "main_window/MainWindow.h" +#include "core/function/ArchiveFileOperator.h" +#include "core/function/gpg/GpgFileOpera.h" #include "ui/SignalStation.h" +#include "ui/main_window/MainWindow.h" #include "ui_FilePage.h" namespace GpgFrontend::UI { @@ -103,36 +105,35 @@ void FilePage::slot_file_tree_view_item_clicked(const QModelIndex& index) { LOG(INFO) << "selected path" << selected_path_; selected_path_ = std::filesystem::path(selected_path_); - MainWindow::CryptoMenu::OperationType operation_type = MainWindow::CryptoMenu::None; - + MainWindow::CryptoMenu::OperationType operation_type = + MainWindow::CryptoMenu::None; + if (index.isValid()) { QFileInfo info(QString::fromStdString(selected_path_.string())); - - if(info.isFile() && (info.suffix() != "gpg" && - info.suffix() != "sig" && - info.suffix() != "asc")) { + if ((info.isDir() || info.isFile()) && + (info.suffix() != "gpg" && info.suffix() != "sig" && + info.suffix() != "asc")) { operation_type |= MainWindow::CryptoMenu::Encrypt; } - if(info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig" && - info.suffix() != "asc")){ + if ((info.isDir() || info.isFile()) && + (info.suffix() != "gpg" && info.suffix() != "sig" && + info.suffix() != "asc")) { operation_type |= MainWindow::CryptoMenu::EncryptAndSign; } - if(info.isFile() && (info.suffix() == "gpg" || info.suffix() == "asc")) { + if (info.isFile() && (info.suffix() == "gpg" || info.suffix() == "asc")) { operation_type |= MainWindow::CryptoMenu::Decrypt; operation_type |= MainWindow::CryptoMenu::DecryptAndVerify; } - if(info.isFile() && (info.suffix() != "gpg" && - info.suffix() != "sig" && - info.suffix() != "asc")){ + if (info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig" && + info.suffix() != "asc")) { operation_type |= MainWindow::CryptoMenu::Sign; } - if(info.isFile() && (info.suffix() == "sig" || - info.suffix() == "gpg" || + if (info.isFile() && (info.suffix() == "sig" || info.suffix() == "gpg" || info.suffix() == "asc")) { operation_type |= MainWindow::CryptoMenu::Verify; } @@ -214,20 +215,30 @@ void FilePage::create_popup_menu() { connect(ui_->actionCalculateHash, &QAction::triggered, this, &FilePage::slot_calculate_hash); - ui_->actionMakeDirectory->setText(_("Make New Directory")); + ui_->actionMakeDirectory->setText(_("Directory")); connect(ui_->actionMakeDirectory, &QAction::triggered, this, &FilePage::slot_mkdir); - ui_->actionCreateEmptyFile->setText(_("Create Empty File")); + ui_->actionCreateEmptyFile->setText(_("File")); connect(ui_->actionCreateEmptyFile, &QAction::triggered, this, &FilePage::slot_create_empty_file); + ui_->actionCompressFiles->setText(_("Compress...")); + ui_->actionCompressFiles->setVisible(false); + connect(ui_->actionCompressFiles, &QAction::triggered, this, + &FilePage::slot_compress_files); + + auto new_item_action_menu = new QMenu(this); + new_item_action_menu->setTitle(_("New")); + new_item_action_menu->addAction(ui_->actionCreateEmptyFile); + new_item_action_menu->addAction(ui_->actionMakeDirectory); + popup_menu_->addAction(ui_->actionOpenFile); popup_menu_->addAction(ui_->actionRenameFile); popup_menu_->addAction(ui_->actionDeleteFile); popup_menu_->addSeparator(); - popup_menu_->addAction(ui_->actionMakeDirectory); - popup_menu_->addAction(ui_->actionCreateEmptyFile); + popup_menu_->addMenu(new_item_action_menu); + popup_menu_->addAction(ui_->actionCompressFiles); popup_menu_->addAction(ui_->actionCalculateHash); option_popup_menu_ = new QMenu(); @@ -259,9 +270,14 @@ void FilePage::create_popup_menu() { void FilePage::onCustomContextMenu(const QPoint& point) { QModelIndex index = ui_->fileTreeView->indexAt(point); + LOG(INFO) << "right click" << selected_path_; + selected_path_ = std::filesystem::path( dir_model_->fileInfo(index).absoluteFilePath().toStdString()); - LOG(INFO) << "right click" << selected_path_; + + // update crypt menu + slot_file_tree_view_item_clicked(index); + if (index.isValid()) { ui_->actionOpenFile->setEnabled(true); ui_->actionRenameFile->setEnabled(true); @@ -293,6 +309,7 @@ void FilePage::slot_open_item() { } } else { if (info.isReadable()) { + // handle normal text or binary file auto main_window = qobject_cast<MainWindow*>(first_parent_); LOG(INFO) << "open item" << selected_path_; auto qt_path = QString::fromStdString(selected_path_.string()); @@ -348,8 +365,7 @@ void FilePage::slot_delete_item() { void FilePage::slot_calculate_hash() { auto info_str = FileOperator::CalculateHash(selected_path_); - emit SignalRefreshInfoBoard(info_str.c_str(), - InfoBoardStatus::INFO_ERROR_OK); + emit SignalRefreshInfoBoard(info_str.c_str(), InfoBoardStatus::INFO_ERROR_OK); } void FilePage::slot_mkdir() { @@ -398,4 +414,6 @@ void FilePage::keyPressEvent(QKeyEvent* event) { } } +void FilePage::slot_compress_files() {} + } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h index e8ee3f25..cff395a8 100644 --- a/src/ui/widgets/FilePage.h +++ b/src/ui/widgets/FilePage.h @@ -142,6 +142,12 @@ class FilePage : public QWidget { */ void slot_create_empty_file(); + /** + * @brief compress directory into gpg-zip + * + */ + void slot_compress_files(); + protected: /** * @brief |