diff options
-rw-r--r-- | .gitea/workflows/develop-qt5.yml | 13 | ||||
-rw-r--r-- | .gitea/workflows/develop-qt6.yml | 27 | ||||
-rw-r--r-- | .github/workflows/release-qt5.yml | 12 | ||||
-rw-r--r-- | .github/workflows/release.yml | 4 | ||||
-rw-r--r-- | .github/workflows/testing-nightly.yml | 15 | ||||
-rw-r--r-- | CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/CMakeLists.txt | 4 | ||||
-rw-r--r-- | src/core/function/GlobalSettingStation.cpp | 6 | ||||
-rw-r--r-- | src/core/function/gpg/GpgContext.cpp | 12 | ||||
-rw-r--r-- | src/ui/dialog/Wizard.cpp | 167 | ||||
-rw-r--r-- | src/ui/widgets/FilePage.cpp | 29 | ||||
-rw-r--r-- | src/ui/widgets/FilePage.h | 2 | ||||
-rw-r--r-- | src/ui/widgets/FileTreeView.cpp | 82 | ||||
-rw-r--r-- | src/ui/widgets/FileTreeView.h | 6 | ||||
-rw-r--r-- | ui/FilePage.ui | 23 |
15 files changed, 200 insertions, 206 deletions
diff --git a/.gitea/workflows/develop-qt5.yml b/.gitea/workflows/develop-qt5.yml index 3bfc405a..9d31214a 100644 --- a/.gitea/workflows/develop-qt5.yml +++ b/.gitea/workflows/develop-qt5.yml @@ -27,12 +27,7 @@ name: Develop CI Qt5 on: push: - branches: ["dev/**"] - paths-ignore: - - "resource/lfs/locale/**" - - "**.md" - pull_request: - branches: ["dev/**"] + branches: ["develop", "dev/**"] paths-ignore: - "resource/lfs/locale/**" - "**.md" @@ -84,11 +79,11 @@ jobs: run: | mkdir ${{github.workspace}}/build/final-artifact cd ${{github.workspace}}/build/final-artifact - wget -c -nv https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage - chmod u+x linuxdeployqt-continuous-x86_64.AppImage + wget -O linuxdeployqt.AppImage -c -nv https://ftp.bktus.com/linuxdeployqt/linuxdeployqt-01052025-x86_64.AppImage + chmod u+x linuxdeployqt.AppImage mkdir -p ${{github.workspace}}/build/artifacts/AppDir/usr/share/doc/libc6 touch ${{github.workspace}}/build/artifacts/AppDir/usr/share/doc/libc6/copyright - ./linuxdeployqt-continuous-x86_64.AppImage ${{github.workspace}}/build/artifacts/AppDir/usr/share/applications/*.desktop -no-translations -extra-plugins=iconengines,platforms/libqoffscreen.so -appimage -unsupported-allow-new-glibc + ./linuxdeployqt.AppImage ${{github.workspace}}/build/artifacts/AppDir/usr/share/applications/*.desktop -no-translations -extra-plugins=iconengines,platforms/libqoffscreen.so -appimage -unsupported-allow-new-glibc echo "BUILD_TYPE_LOWER=${BUILD_TYPE,,}" >> ${GITHUB_ENV} echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> ${GITHUB_ENV} diff --git a/.gitea/workflows/develop-qt6.yml b/.gitea/workflows/develop-qt6.yml index 794fedc2..65dcf6cb 100644 --- a/.gitea/workflows/develop-qt6.yml +++ b/.gitea/workflows/develop-qt6.yml @@ -27,16 +27,10 @@ name: Develop CI Qt6 on: push: - branches: ["dev/**"] + branches: ["develop", "dev/**"] paths-ignore: - "resource/lfs/locale/**" - "**.md" - pull_request: - branches: ["dev/**"] - paths-ignore: - - "resource/lfs/locale/**" - - "**.md" - env: BUILD_TYPE: Debug @@ -79,18 +73,6 @@ jobs: ninja sudo ninja install - - name: Build & Install Full SDK - run: | - cmake -B ${{github.workspace}}/build-full-sdk -G Ninja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DGPGFRONTEND_BUILD_TYPE_FULL_SDK=ON - cmake --build ${{github.workspace}}/build-full-sdk --config {{$env.BUILD_TYPE}} -- -v - sudo cmake --install ${{github.workspace}}/build-full-sdk --config {{$env.BUILD_TYPE}} - - - name: Build Integrated Modules - run: | - cmake -S ${{github.workspace}}/modules -B ${{github.workspace}}/modules/build -G Ninja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INSTALL_PREFIX=${{github.workspace}}/modules/build/artifacts - cmake --build ${{github.workspace}}/modules/build --config {{$env.BUILD_TYPE}} -- -v - cmake --install ${{github.workspace}}/modules/build --config {{$env.BUILD_TYPE}} - - name: Build GpgFrontend run: | cmake -B ${{github.workspace}}/build -G Ninja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DGPGFRONTEND_BUILD_APP_IMAGE=On @@ -101,17 +83,16 @@ jobs: - name: Copy Modules & Package App Image run: | - cmake -E copy_directory ${{github.workspace}}/modules/build/artifacts/modules ${{github.workspace}}/build/artifacts/AppDir/usr/modules mkdir ${{github.workspace}}/build/final-artifact cd ${{github.workspace}}/build/final-artifact - wget -c -nv https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage - chmod u+x linuxdeployqt-continuous-x86_64.AppImage + wget -O linuxdeployqt.AppImage -c -nv https://ftp.bktus.com/linuxdeployqt/linuxdeployqt-01052025-x86_64.AppImage + chmod u+x linuxdeployqt.AppImage export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib qtchooser -install qt6 $(which qmake6) export QT_SELECT=qt6 mkdir -p ${{github.workspace}}/build/artifacts/AppDir/usr/share/doc/libc6 touch ${{github.workspace}}/build/artifacts/AppDir/usr/share/doc/libc6/copyright - ./linuxdeployqt-continuous-x86_64.AppImage ${{github.workspace}}/build/artifacts/AppDir/usr/share/applications/*.desktop -no-translations -extra-plugins=iconengines,platforms/libqoffscreen.so -appimage -executable-dir=${{github.workspace}}/build/artifacts/AppDir/usr/modules/ -unsupported-allow-new-glibc + ./linuxdeployqt.AppImage ${{github.workspace}}/build/artifacts/AppDir/usr/share/applications/*.desktop -no-translations -extra-plugins=iconengines,platforms/libqoffscreen.so -appimage -executable-dir=${{github.workspace}}/build/artifacts/AppDir/usr/lib/modules -unsupported-allow-new-glibc echo "BUILD_TYPE_LOWER=${BUILD_TYPE,,}" >> ${GITHUB_ENV} echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> ${GITHUB_ENV} diff --git a/.github/workflows/release-qt5.yml b/.github/workflows/release-qt5.yml index fd1f7ba0..8fdf1fc4 100644 --- a/.github/workflows/release-qt5.yml +++ b/.github/workflows/release-qt5.yml @@ -184,7 +184,7 @@ jobs: - name: Build GpgFrontend (Linux) run: | - cmake -B ${{github.workspace}}/build -G Ninja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DGPGFRONTEND_QT5_BUILD=ON + cmake -B ${{github.workspace}}/build -G Ninja -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DGPGFRONTEND_QT5_BUILD=ON -DGPGFRONTEND_BUILD_APP_IMAGE=ON cmake --build ${{github.workspace}}/build --config {{$env.BUILD_TYPE}} -- -v if: runner.os == 'Linux' @@ -242,13 +242,13 @@ jobs: cp TRANSLATORS build/artifacts/ cp COPYING build/artifacts/ cp gpgfrontend.ico build/artifacts/bin/ - rm -rf build/artifacts/bin/modules/*.a + rm -rf build/artifacts/bin/*.a touch build/artifacts/bin/PORTABLE.txt cd build - windeployqt-qt6 --no-translations --force ./artifacts/bin/libgf_core.dll - windeployqt-qt6 --no-translations --force ./artifacts/bin/libgf_ui.dll - windeployqt-qt6 --no-translations --force ./artifacts/bin/libgf_test.dll - windeployqt-qt6 --no-translations --force ./artifacts/bin/GpgFrontend.exe + windeployqt --no-translations --force ./artifacts/bin/libgf_core.dll + windeployqt --no-translations --force ./artifacts/bin/libgf_ui.dll + windeployqt --no-translations --force ./artifacts/bin/libgf_test.dll + windeployqt --no-translations --force ./artifacts/bin/GpgFrontend.exe mkdir upload-artifact cd artifacts zip -r ../upload-artifact/GpgFrontend-${{env.SHORT_SHA}}-x86_64.zip * diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ab0b4f79..d94b6e87 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -262,7 +262,7 @@ jobs: wget -c -nv https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage chmod u+x linuxdeployqt-continuous-x86_64.AppImage export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib - ./linuxdeployqt-continuous-x86_64.AppImage ${{github.workspace}}/build/artifacts/AppDir/usr/share/applications/*.desktop -no-translations -extra-plugins=iconengines,platforms,wayland-graphics-integration-client,wayland-decoration-client,wayland-shell-integration -appimage + ./linuxdeployqt-continuous-x86_64.AppImage ${{github.workspace}}/build/artifacts/AppDir/usr/share/applications/*.desktop -no-translations -extra-plugins=iconengines,platforms,wayland-graphics-integration-client,wayland-decoration-client,wayland-shell-integration -appimage -executable-dir=${{github.workspace}}/build/artifacts/AppDir/usr/lib/modules echo "BUILD_TYPE_LOWER=${BUILD_TYPE,,}" >> ${GITHUB_ENV} echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> ${GITHUB_ENV} if: runner.os == 'Linux' @@ -319,7 +319,9 @@ jobs: cp TRANSLATORS build/artifacts/ cp COPYING build/artifacts/ cp gpgfrontend.ico build/artifacts/bin/ + rm -rf build/artifacts/bin/*.a rm -rf build/artifacts/bin/modules/*.a + mv build/artifacts/bin/modules build/artifacts/modules touch build/artifacts/bin/PORTABLE.txt cd build windeployqt-qt6 --no-translations --force ./artifacts/bin/libgf_core.dll diff --git a/.github/workflows/testing-nightly.yml b/.github/workflows/testing-nightly.yml index 1a41b8e6..6d4eac6a 100644 --- a/.github/workflows/testing-nightly.yml +++ b/.github/workflows/testing-nightly.yml @@ -249,7 +249,7 @@ jobs: wget -c -nv https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage chmod u+x linuxdeployqt-continuous-x86_64.AppImage export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib - ./linuxdeployqt-continuous-x86_64.AppImage ${{github.workspace}}/build/artifacts/AppDir/usr/share/applications/*.desktop -no-translations -extra-plugins=iconengines,platforms,wayland-graphics-integration-client,wayland-decoration-client,wayland-shell-integration -appimage + ./linuxdeployqt-continuous-x86_64.AppImage ${{github.workspace}}/build/artifacts/AppDir/usr/share/applications/*.desktop -no-translations -extra-plugins=iconengines,platforms,wayland-graphics-integration-client,wayland-decoration-client,wayland-shell-integration -appimage -executable-dir=${{github.workspace}}/build/artifacts/AppDir/usr/lib/modules echo "BUILD_TYPE_LOWER=${BUILD_TYPE,,}" >> ${GITHUB_ENV} echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> ${GITHUB_ENV} if: runner.os == 'Linux' @@ -306,7 +306,9 @@ jobs: cp TRANSLATORS build/artifacts/ cp COPYING build/artifacts/ cp gpgfrontend.ico build/artifacts/bin/ + rm -rf build/artifacts/bin/*.a rm -rf build/artifacts/bin/modules/*.a + mv build/artifacts/bin/modules build/artifacts/modules touch build/artifacts/bin/PORTABLE.txt cd build windeployqt-qt6 --no-translations --force ./artifacts/bin/libgf_core.dll @@ -358,13 +360,22 @@ jobs: - name: List files run: ls -rl artifacts/ + - name: Generate Release Title with Date + id: release_title + run: echo "title=Nightly Build $(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT + + - name: Delete Old Nightly Release + run: gh release delete --repo saturneric/GpgFrontend --cleanup-tag --yes nightly + env: + GH_TOKEN: ${{ secrets.USER_GITHUB_TOKEN }} + - name: Update Nightly Release uses: softprops/action-gh-release@v2 env: GITHUB_TOKEN: ${{ secrets.USER_GITHUB_TOKEN }} with: tag_name: nightly - name: "Nightly Build" + name: ${{ steps.release_title.outputs.title }} draft: false prerelease: true body: | diff --git a/CMakeLists.txt b/CMakeLists.txt index 0664e51e..02d8cd59 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -23,9 +23,7 @@ # # SPDX-License-Identifier: GPL-3.0-or-later -cmake_minimum_required(VERSION 3.16) - -message(STATUS "Current Generator: ${CMAKE_GENERATOR}") +cmake_minimum_required(VERSION 3.24) if(CMAKE_GENERATOR STREQUAL "Xcode") set(CMAKE_USER_MAKE_RULES_OVERRIDE "${CMAKE_SOURCE_DIR}/cmake/FlagsOverridesXcode.cmake") diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 828f5f9f..3d58193b 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -487,7 +487,7 @@ if(BUILD_APP_FOR_PACKAGE) set(CPACK_RPM_PACKAGE_LICENSE "GPLv3") set(CPACK_RPM_PACKAGE_GROUP "Applications/System") set(CPACK_RPM_PACKAGE_REQUIRES - "libassuan >= 2.5.0, gpgme >= 1.12.0, qt6-qtbase >= 6.0.0, gtk-update-icon-cache") + "gpgme >= 1.24.2, qt6-qtbase >= 6.4.2, qt6-qtbase-gui >= 6.4.2, libarchive >= 3.6.2, gtk-update-icon-cache") set(CPACK_RPM_PACKAGE_URL "${CPACK_PACKAGE_HOMEPAGE_URL}") set(CPACK_RPM_PACKAGE_LICENSE_FILE "${CMAKE_SOURCE_DIR}/COPYING") set(CPACK_RPM_PACKAGE_DOCUMENTATION "${CMAKE_SOURCE_DIR}/README.md") @@ -508,7 +508,7 @@ if(BUILD_APP_FOR_PACKAGE) set(CPACK_DEBIAN_PACKAGE_MAINTAINER "[email protected]") set(CPACK_DEBIAN_PACKAGE_SECTION "utils") set(CPACK_DEBIAN_PACKAGE_DEPENDS - "libassuan0 (>= 2.5.0), libgpgme11 (>= 1.12.0), qt6-base-dev (>= 6.0.0), gtk-update-icon-cache") + "libgpgme11t64 (>= 1.24.2), libqt6core6t64 (>= 6.4.2), libqt6gui6t64 (>= 6.4.2), libqt6widgets6t64 (>= 6.4.2), libarchive13 (>= 3.6.2), gtk-update-icon-cache") set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "${CPACK_PACKAGE_HOMEPAGE_URL}") set(CPACK_DEBIAN_PACKAGE_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}") set(CPACK_DEBIAN_PACKAGE_LICENSE "GPLv3") diff --git a/src/core/function/GlobalSettingStation.cpp b/src/core/function/GlobalSettingStation.cpp index 21f1c743..28b4ade7 100644 --- a/src/core/function/GlobalSettingStation.cpp +++ b/src/core/function/GlobalSettingStation.cpp @@ -170,13 +170,7 @@ class GlobalSettingStation::Impl { #endif #if defined(_WIN32) || defined(WIN32) - -#ifdef NDEBUG return exec_binary_path + "/../modules"; -#else - return exec_binary_path + "/../modules/bin"; -#endif - #endif #if defined(__APPLE__) && defined(__MACH__) diff --git a/src/core/function/gpg/GpgContext.cpp b/src/core/function/gpg/GpgContext.cpp index 49d39650..0f7d30de 100644 --- a/src/core/function/gpg/GpgContext.cpp +++ b/src/core/function/gpg/GpgContext.cpp @@ -88,7 +88,7 @@ class GpgAgentProcess { args.append("--disable-scdaemon"); } - LOG_E() << "gpg-agent start args: " << args << "channel:" << channel_; + LOG_D() << "gpg-agent start args: " << args << "channel:" << channel_; process_.setProgram(info.absoluteFilePath()); process_.setArguments(args); @@ -162,8 +162,8 @@ class GpgContext::Impl { [[nodiscard]] auto Good() const -> bool { return good_; } - auto SetPassphraseCb(const gpgme_ctx_t &ctx, - gpgme_passphrase_cb_t cb) -> bool { + auto SetPassphraseCb(const gpgme_ctx_t &ctx, gpgme_passphrase_cb_t cb) + -> bool { if (gpgme_get_pinentry_mode(ctx) != GPGME_PINENTRY_MODE_LOOPBACK) { if (CheckGpgError(gpgme_set_pinentry_mode( ctx, GPGME_PINENTRY_MODE_LOOPBACK)) != GPG_ERR_NO_ERROR) { @@ -258,8 +258,8 @@ class GpgContext::Impl { return res == pass_size + 1 ? 0 : GPG_ERR_CANCELED; } - static auto TestStatusCb(void *hook, const char *keyword, - const char *args) -> gpgme_error_t { + static auto TestStatusCb(void *hook, const char *keyword, const char *args) + -> gpgme_error_t { FLOG_D("keyword %s", keyword); return GPG_ERR_NO_ERROR; } @@ -544,7 +544,7 @@ class GpgContext::Impl { args.append({"--kill", "gpg-agent"}); - LOG_E() << "gpgconf kill args: " << args + LOG_D() << "gpgconf kill args: " << args << "channel:" << parent_->GetChannel(); QProcess process; diff --git a/src/ui/dialog/Wizard.cpp b/src/ui/dialog/Wizard.cpp index a126d995..4f2dbbdf 100644 --- a/src/ui/dialog/Wizard.cpp +++ b/src/ui/dialog/Wizard.cpp @@ -59,84 +59,87 @@ void Wizard::slot_wizard_accepted() { } IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) { - setTitle(tr("Getting Started...")); - setSubTitle(tr("... with GpgFrontend")); - - auto* top_label = new QLabel( - tr("Welcome to GpgFrontend for decrypting and signing text or files!") + - " <br><br><a href='https://gpgfrontend.bktus.com'>GpgFrontend</a> " + - tr("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and " - "Installation-Free OpenPGP Crypto Tool. ") + - tr("To get started, be sure to check out the") + + setTitle(tr("Welcome to GpgFrontend")); + setSubTitle(tr("Your OpenPGP encryption companion.")); + + // Intro text + auto* intro_label = new QLabel( + tr("<b>GpgFrontend</b> is a free, user-friendly, and cross-platform tool " + "for " + "OpenPGP encryption, decryption, and signing of text and files.") + + "<br><br>" + tr("To get started, take a quick look at the") + " <a href='https://gpgfrontend.bktus.com/overview/glance'>" + - tr("Overview") + "</a> (" + - tr("by clicking the link, the page will open in your web browser") + - "). <br>"); - top_label->setTextFormat(Qt::RichText); - top_label->setTextInteractionFlags(Qt::TextBrowserInteraction); - top_label->setOpenExternalLinks(true); - top_label->setWordWrap(true); - - // QComboBox for language selection + tr("Overview Page") + "</a>." + " " + + tr("It will open in your default browser.")); + intro_label->setTextFormat(Qt::RichText); + intro_label->setTextInteractionFlags(Qt::TextBrowserInteraction); + intro_label->setOpenExternalLinks(true); + intro_label->setWordWrap(true); + + // Language info auto* lang_label = - new QLabel(tr("If it supports the language currently being used in your " - "system, GpgFrontend will automatically set it.")); + new QLabel(tr("GpgFrontend will automatically use the language of your " + "system if supported. " + "You can change the language later in settings.")); lang_label->setWordWrap(true); - // set layout and add widgets + // Layout auto* layout = new QVBoxLayout; - layout->addWidget(top_label); - layout->addStretch(); + layout->addWidget(intro_label); + layout->addSpacing(20); layout->addWidget(lang_label); - + layout->addStretch(); setLayout(layout); } auto IntroPage::nextId() const -> int { return Wizard::kPAGE_CHOOSE; } ChoosePage::ChoosePage(QWidget* parent) : QWizardPage(parent) { - setTitle(tr("Choose your action...")); - setSubTitle(tr("...by clicking on the appropriate link.")); - - auto* keygen_label = new QLabel( - tr("If you have never used GpgFrontend before and also don't own a gpg " - "key yet you may possibly want to read how to") + - " <a href=\"https://gpgfrontend.bktus.com/guides/generate-key\">" + - tr("Generate Key") + "</a><hr>"); - keygen_label->setTextFormat(Qt::RichText); - keygen_label->setTextInteractionFlags(Qt::TextBrowserInteraction); - keygen_label->setOpenExternalLinks(true); - keygen_label->setWordWrap(true); - - auto* encr_decy_text_label = new QLabel( - tr("If you want to learn how to encrypt, decrypt, sign and verify text, " - "you can read ") + - "<a href=\"https://gpgfrontend.bktus.com/guides/encrypt-decrypt-text\">" + - tr("Encrypt & Decrypt Text") + "</a> " + tr("or") + - " <a href=\"https://gpgfrontend.bktus.com/guides/sign-verify-text\">" + - tr("Sign & Verify Text") + "</a><hr>"); - - encr_decy_text_label->setTextFormat(Qt::RichText); - encr_decy_text_label->setTextInteractionFlags(Qt::TextBrowserInteraction); - encr_decy_text_label->setOpenExternalLinks(true); - encr_decy_text_label->setWordWrap(true); - - auto* sign_verify_text_label = new QLabel( - tr("If you want to operate file, you can read ") + - "<a href=\"https://gpgfrontend.bktus.com/guides/encrypt-decrypt-file\">" + - tr("Encrypt & Sign File") + "</a> " + tr("or") + - " <a href=\"https://gpgfrontend.bktus.com/guides/sign-verify-file\">" + - tr("Sign & Verify File") + "</a><hr>"); - sign_verify_text_label->setTextFormat(Qt::RichText); - sign_verify_text_label->setTextInteractionFlags(Qt::TextBrowserInteraction); - sign_verify_text_label->setOpenExternalLinks(true); - sign_verify_text_label->setWordWrap(true); - - auto* layout = new QVBoxLayout(); - layout->addWidget(keygen_label); - layout->addWidget(encr_decy_text_label); - layout->addWidget(sign_verify_text_label); + setTitle(tr("Welcome to GpgFrontend")); + setSubTitle(tr("These quick guides will help you get started.")); + + auto* layout = new QVBoxLayout; + + // Section 1: Fundamental Concepts + auto* concepts_title = new QLabel(tr("<b>New to encryption?</b>")); + auto* concepts_desc = new QLabel( + tr("Understand the basics of OpenPGP and how GpgFrontend works.")); + auto* concepts_link = new QLabel( + "<a " + "href=\"https://gpgfrontend.bktus.com/guides/fundamental-concepts/\">" + + tr("Fundamental Concepts") + "</a>"); + + // Section 2: Text operations + auto* textops_title = new QLabel(tr("<b>Working with text?</b>")); + auto* textops_desc = new QLabel( + tr("Learn how to encrypt, decrypt, sign, and verify text messages.")); + auto* textops_link = new QLabel( + "<a href=\"https://gpgfrontend.bktus.com/guides/text-opetations/\">" + + tr("Text Operations Guide") + "</a>"); + + // Section 3: File operations + auto* fileops_title = new QLabel(tr("<b>Working with files?</b>")); + auto* fileops_desc = + new QLabel(tr("Learn how to encrypt, sign, and verify files securely.")); + auto* fileops_link = new QLabel( + "<a href=\"https://gpgfrontend.bktus.com/guides/file-operations/\">" + + tr("File Operations Guide") + "</a>"); + + // All labels: uniform setup + const QList<QLabel*> labels = {concepts_title, concepts_desc, concepts_link, + textops_title, textops_desc, textops_link, + fileops_title, fileops_desc, fileops_link}; + for (auto* l : labels) { + l->setTextFormat(Qt::RichText); + l->setTextInteractionFlags(Qt::TextBrowserInteraction); + l->setOpenExternalLinks(true); + l->setWordWrap(true); + layout->addWidget(l); + } + + layout->addStretch(); // push content upward setLayout(layout); + next_page_ = Wizard::kPAGE_CONCLUSION; } @@ -152,42 +155,46 @@ void ChoosePage::slot_jump_page(const QString& page) { } ConclusionPage::ConclusionPage(QWidget* parent) : QWizardPage(parent) { - setTitle(tr("Ready.")); - setSubTitle(tr("Have fun with GpgFrontend!")); + setTitle(tr("You're all set!")); + setSubTitle(tr("GpgFrontend is ready to use.")); auto* bottom_label = new QLabel( - tr("You are ready to use GpgFrontend now.<br><br>") + - "<a href=\"https://gpgfrontend.bktus.com/guides/fundamental-concepts\">" + - tr("The Online Document") + "</a>" + - tr(" will get you started with GpgFrontend. Anytime you encounter " - "problems, please try to find help from the documentation") + - "<br>"); - + tr("GpgFrontend is now fully set up and ready to go.") + "<br><br>" + + tr("If you encounter any issues or have questions, feel free to ") + + "<a href=\"https://github.com/saturneric/GpgFrontend/issues\">" + + tr("submit an issue on GitHub") + "</a> " + tr("or ") + + "<a href=\"https://gpgfrontend.bktus.com/overview/contact/\">" + + tr("contact the developer") + "</a>." + "<br>" + + tr("Any feedback is welcome and valuable!")); bottom_label->setTextFormat(Qt::RichText); bottom_label->setTextInteractionFlags(Qt::TextBrowserInteraction); bottom_label->setOpenExternalLinks(true); bottom_label->setWordWrap(true); - open_help_check_box_ = new QCheckBox(tr("Open offline help.")); + // Option checkboxes + open_help_check_box_ = new QCheckBox(tr("Open offline help now")); open_help_check_box_->setChecked(true); dont_show_wizard_checkbox_ = - new QCheckBox(tr("Don't show the wizard again.")); + new QCheckBox(tr("Don't show this setup wizard again")); dont_show_wizard_checkbox_->setChecked(true); - check_updates_checkbox_ = - new QCheckBox(tr("Check for updates at each startup.")); + check_updates_checkbox_ = new QCheckBox(tr("Check for updates on startup")); check_updates_checkbox_->setChecked(true); + // Register fields registerField("showWizard", dont_show_wizard_checkbox_); registerField("checkUpdate", check_updates_checkbox_); + // Layout auto* layout = new QVBoxLayout; layout->addWidget(bottom_label); - layout->addWidget(dont_show_wizard_checkbox_); + layout->addSpacing(15); + // layout->addWidget(open_help_check_box_); layout->addWidget(check_updates_checkbox_); + layout->addWidget(dont_show_wizard_checkbox_); + layout->addStretch(); setLayout(layout); - setVisible(true); } auto ConclusionPage::nextId() const -> int { return -1; } diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp index 95dbfac9..59a3c9ed 100644 --- a/src/ui/widgets/FilePage.cpp +++ b/src/ui/widgets/FilePage.cpp @@ -37,21 +37,20 @@ namespace GpgFrontend::UI { FilePage::FilePage(QWidget* parent, const QString& target_path) : QWidget(parent), - ui_(GpgFrontend::SecureCreateSharedObject<Ui_FilePage>()), - file_tree_view_(new FileTreeView(this, target_path)) { + ui_(GpgFrontend::SecureCreateSharedObject<Ui_FilePage>()) { ui_->setupUi(this); - ui_->trewViewLayout->addWidget(file_tree_view_); ui_->batchModeButton->setToolTip(tr("Switch Batch Mode")); - connect(ui_->upPathButton, &QPushButton::clicked, file_tree_view_, + connect(ui_->upPathButton, &QPushButton::clicked, ui_->treeView, &FileTreeView::SlotUpLevel); connect(ui_->refreshButton, &QPushButton::clicked, this, &FilePage::SlotGoPath); - connect(this->ui_->newDirButton, &QPushButton::clicked, file_tree_view_, + connect(this->ui_->newDirButton, &QPushButton::clicked, ui_->treeView, &FileTreeView::SlotMkdir); - ui_->pathEdit->setText(file_tree_view_->GetCurrentPath()); + ui_->treeView->SetPath(target_path); + ui_->pathEdit->setText(ui_->treeView->GetCurrentPath()); path_edit_completer_ = new QCompleter(this); path_complete_model_ = new QStringListModel(); @@ -64,13 +63,13 @@ FilePage::FilePage(QWidget* parent, const QString& target_path) option_popup_menu_ = new QMenu(this); auto* show_hidden_act = new QAction(tr("Show Hidden File"), this); show_hidden_act->setCheckable(true); - connect(show_hidden_act, &QAction::triggered, file_tree_view_, + connect(show_hidden_act, &QAction::triggered, ui_->treeView, &FileTreeView::SlotShowHiddenFile); option_popup_menu_->addAction(show_hidden_act); auto* show_system_act = new QAction(tr("Show System File"), this); show_system_act->setCheckable(true); - connect(show_system_act, &QAction::triggered, file_tree_view_, + connect(show_system_act, &QAction::triggered, ui_->treeView, &FileTreeView::SlotShowSystemFile); option_popup_menu_->addAction(show_system_act); @@ -105,30 +104,30 @@ FilePage::FilePage(QWidget* parent, const QString& target_path) connect(this, &FilePage::SignalRefreshInfoBoard, UISignalStation::GetInstance(), &UISignalStation::SignalRefreshInfoBoard); - connect(file_tree_view_, &FileTreeView::SignalPathChanged, this, + connect(ui_->treeView, &FileTreeView::SignalPathChanged, this, [this](const QString& path) { this->ui_->pathEdit->setText(path); }); - connect(file_tree_view_, &FileTreeView::SignalPathChanged, this, + connect(ui_->treeView, &FileTreeView::SignalPathChanged, this, &FilePage::SignalPathChanged); - connect(file_tree_view_, &FileTreeView::SignalOpenFile, + connect(ui_->treeView, &FileTreeView::SignalOpenFile, UISignalStation::GetInstance(), &UISignalStation::SignalMainWindowOpenFile); - connect(file_tree_view_, &FileTreeView::SignalSelectedChanged, this, + connect(ui_->treeView, &FileTreeView::SignalSelectedChanged, this, &FilePage::update_main_basic_opera_menu); connect(this, &FilePage::SignalCurrentTabChanged, this, [this]() { update_main_basic_opera_menu(GetSelected()); }); connect(this, &FilePage::SignalMainWindowUpdateBasicOperaMenu, UISignalStation::GetInstance(), &UISignalStation::SignalMainWindowUpdateBasicOperaMenu); - connect(ui_->batchModeButton, &QToolButton::toggled, file_tree_view_, + connect(ui_->batchModeButton, &QToolButton::toggled, ui_->treeView, &FileTreeView::SlotSwitchBatchMode); } auto FilePage::GetSelected() const -> QStringList { - return file_tree_view_->GetSelectedPaths(); + return ui_->treeView->GetSelectedPaths(); } void FilePage::SlotGoPath() { - file_tree_view_->SlotGoPath(ui_->pathEdit->text()); + ui_->treeView->SlotGoPath(ui_->pathEdit->text()); } void FilePage::keyPressEvent(QKeyEvent* event) { diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h index fbf99ae9..94b90b0d 100644 --- a/src/ui/widgets/FilePage.h +++ b/src/ui/widgets/FilePage.h @@ -29,7 +29,6 @@ #pragma once #include "ui/GpgFrontendUI.h" -#include "ui/widgets/FileTreeView.h" #include "ui/widgets/InfoBoardWidget.h" class Ui_FilePage; @@ -126,7 +125,6 @@ class FilePage : public QWidget { QMenu* popup_menu_{}; ///< QMenu* option_popup_menu_{}; ///< - FileTreeView* file_tree_view_; bool ascii_mode_; private slots: diff --git a/src/ui/widgets/FileTreeView.cpp b/src/ui/widgets/FileTreeView.cpp index 8ebd7274..db628d60 100644 --- a/src/ui/widgets/FileTreeView.cpp +++ b/src/ui/widgets/FileTreeView.cpp @@ -35,7 +35,7 @@ namespace GpgFrontend::UI { -FileTreeView::FileTreeView(QWidget* parent, const QString& target_path) +FileTreeView::FileTreeView(QWidget* parent) : QTreeView(parent), dir_model_(new QFileSystemModel(this)) { dir_model_->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot); dir_model_->setRootPath(QDir::homePath()); @@ -58,43 +58,6 @@ FileTreeView::FileTreeView(QWidget* parent, const QString& target_path) &FileTreeView::slot_adjust_column_widths); connect(dir_model_, &QFileSystemModel::dataChanged, this, &FileTreeView::slot_adjust_column_widths); - - LOG_D() << "try to open target path:" << target_path; - - QFileInfo info(target_path); - QString effective_path; - - if (info.exists()) { - effective_path = - info.isFile() ? info.absolutePath() : info.absoluteFilePath(); - } else { - effective_path = QDir::currentPath(); - } - - LOG_D() << "effective path:" << effective_path; - - dir_model_->setRootPath(effective_path); - current_path_ = dir_model_->rootPath(); - QModelIndex root_index = dir_model_->index(current_path_); - - if (root_index.isValid()) { - QPointer<FileTreeView> self(this); - this->setRootIndex(root_index); - QTimer::singleShot(200, [=]() { - if (self != nullptr && info.isFile()) { - self->setCurrentIndex(dir_model_->index(info.absoluteFilePath())); - self->expand(currentIndex().parent()); - self->scrollTo(currentIndex(), QAbstractItemView::PositionAtCenter); - self->selectionModel()->select( - currentIndex(), - QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); - } - }); - } else { - LOG_W() << "invalid path, fallback to current dir."; - current_path_ = QDir::currentPath(); - this->setRootIndex(dir_model_->index(current_path_)); - } } void FileTreeView::selectionChanged(const QItemSelection& selected, @@ -446,9 +409,8 @@ void FileTreeView::slot_calculate_hash() { return; } auto result = ExtractParams<QString>(data_object, 0); - emit UISignalStation::GetInstance() - -> SignalRefreshInfoBoard(result, - InfoBoardStatus::INFO_ERROR_OK); + emit UISignalStation::GetInstance() -> SignalRefreshInfoBoard( + result, InfoBoardStatus::INFO_ERROR_OK); }, "calculate_file_hash"); }); @@ -481,4 +443,42 @@ void FileTreeView::SlotSwitchBatchMode(bool batch) { selectionModel()->clearSelection(); } +void FileTreeView::SetPath(const QString& target_path) { + LOG_D() << "try to open target path:" << target_path; + + QFileInfo info(target_path); + QString effective_path; + + if (info.exists()) { + effective_path = + info.isFile() ? info.absolutePath() : info.absoluteFilePath(); + } else { + effective_path = QDir::currentPath(); + } + + LOG_D() << "effective path:" << effective_path; + + dir_model_->setRootPath(effective_path); + current_path_ = dir_model_->rootPath(); + QModelIndex root_index = dir_model_->index(current_path_); + + if (root_index.isValid()) { + QPointer<FileTreeView> self(this); + this->setRootIndex(root_index); + QTimer::singleShot(200, [=]() { + if (self != nullptr && info.isFile()) { + self->setCurrentIndex(dir_model_->index(info.absoluteFilePath())); + self->expand(currentIndex().parent()); + self->scrollTo(currentIndex(), QAbstractItemView::PositionAtCenter); + self->selectionModel()->select( + currentIndex(), + QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows); + } + }); + } else { + LOG_W() << "invalid path, fallback to current dir."; + current_path_ = QDir::currentPath(); + this->setRootIndex(dir_model_->index(current_path_)); + } +} } // namespace GpgFrontend::UI diff --git a/src/ui/widgets/FileTreeView.h b/src/ui/widgets/FileTreeView.h index 333e06bc..e7ddb607 100644 --- a/src/ui/widgets/FileTreeView.h +++ b/src/ui/widgets/FileTreeView.h @@ -41,7 +41,11 @@ class FileTreeView : public QTreeView { * @param parent * @param target_path */ - explicit FileTreeView(QWidget* parent, const QString& target_path); + explicit FileTreeView(QWidget* parent); + + /** + */ + void SetPath(const QString& target_path); /** * @brief Get the Current Path object diff --git a/ui/FilePage.ui b/ui/FilePage.ui index b9ae7043..97a3ad94 100644 --- a/ui/FilePage.ui +++ b/ui/FilePage.ui @@ -6,8 +6,8 @@ <rect> <x>0</x> <y>0</y> - <width>858</width> - <height>64</height> + <width>805</width> + <height>666</height> </rect> </property> <property name="sizePolicy"> @@ -16,12 +16,6 @@ <verstretch>0</verstretch> </sizepolicy> </property> - <property name="maximumSize"> - <size> - <width>1041</width> - <height>619</height> - </size> - </property> <property name="windowTitle"> <string>Form</string> </property> @@ -190,7 +184,11 @@ </layout> </item> <item> - <layout class="QVBoxLayout" name="trewViewLayout"/> + <layout class="QVBoxLayout" name="trewViewLayout"> + <item> + <widget class="GpgFrontend::UI::FileTreeView" name="treeView"/> + </item> + </layout> </item> </layout> </item> @@ -198,6 +196,13 @@ </item> </layout> </widget> + <customwidgets> + <customwidget> + <class>GpgFrontend::UI::FileTreeView</class> + <extends>QTreeView</extends> + <header>ui/widgets/FileTreeView.h</header> + </customwidget> + </customwidgets> <resources> <include location="../gpgfrontend.qrc"/> </resources> |