aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--.github/workflows/release-ci.yml39
-rw-r--r--CMakeLists.txt8
-rw-r--r--include/GpgFrontend.h79
-rw-r--r--include/GpgFrontendBuildInfo.h54
-rw-r--r--resource/conf/gpgfrontend.ini53
-rw-r--r--resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop2
-rw-r--r--resource/gpgfrontend/usr/share/icons/hicolor/128x128/apps/GpgFrontend.pngbin0 -> 3819 bytes
-rwxr-xr-xresource/gpgfrontend/usr/share/icons/hicolor/200x200/apps/gpgfrontend-appimage-icon.pngbin5651 -> 0 bytes
-rw-r--r--resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.pngbin0 -> 9155 bytes
-rw-r--r--src/CMakeLists.txt16
-rw-r--r--src/GpgFrontend.h.in11
-rw-r--r--src/gpg/CMakeLists.txt7
-rw-r--r--src/gpg/GpgConstants.cpp16
-rw-r--r--src/gpg/GpgConstants.h7
-rw-r--r--src/gpg/GpgContext.h4
-rw-r--r--src/gpg/GpgModel.h2
-rw-r--r--src/gpg/function/GpgCommandExecutor.cpp7
-rw-r--r--src/gpg/function/GpgCommandExecutor.h5
-rw-r--r--src/gpg/function/GpgKeyOpera.cpp67
-rw-r--r--src/gpg/result_analyse/VerifyResultAnalyse.cpp9
-rw-r--r--src/gpg/result_analyse/VerifyResultAnalyse.h2
-rw-r--r--src/main.cpp26
-rw-r--r--src/smtp/smtpexports.h20
-rw-r--r--src/ui/CMakeLists.txt4
-rw-r--r--src/ui/GpgFrontendUI.h6
-rw-r--r--src/ui/KeyServerImportDialog.cpp52
-rw-r--r--src/ui/KeyServerImportDialog.h2
-rw-r--r--src/ui/MainWindow.cpp2
-rw-r--r--src/ui/Wizard.cpp96
-rw-r--r--src/ui/Wizard.h2
-rw-r--r--src/ui/function/FileReadThread.cpp13
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.cpp2
-rw-r--r--src/ui/keypair_details/KeyPairUIDTab.cpp2
-rw-r--r--src/ui/main_window/MainWindowFileSlotFunction.cpp32
-rw-r--r--src/ui/settings/GlobalSettingStation.cpp6
-rw-r--r--src/ui/settings/GlobalSettingStation.h1
-rw-r--r--src/ui/settings/SettingsDialog.cpp2
-rw-r--r--src/ui/settings/SettingsGeneral.cpp30
-rw-r--r--src/ui/widgets/EditorPage.cpp18
-rw-r--r--src/ui/widgets/EditorPage.h8
-rw-r--r--src/ui/widgets/FilePage.cpp36
-rw-r--r--src/ui/widgets/TextEdit.cpp30
-rw-r--r--test/data/pv3.key212
-rw-r--r--test/data/pv4.key164
44 files changed, 698 insertions, 456 deletions
diff --git a/.github/workflows/release-ci.yml b/.github/workflows/release-ci.yml
index 2823e056..3eabc44e 100644
--- a/.github/workflows/release-ci.yml
+++ b/.github/workflows/release-ci.yml
@@ -25,7 +25,7 @@ jobs:
build:
strategy:
matrix:
- os: [ 'ubuntu-16.04', 'macos-latest', 'windows-latest' ]
+ os: [ 'ubuntu-18.04', 'macos-latest', 'windows-latest' ]
runs-on: ${{ matrix.os }}
steps:
@@ -35,12 +35,12 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -y install build-essential binutils git autoconf automake gettext texinfo
- sudo apt-get -y install gcc g++
+ sudo apt-get -y install gcc g++ libconfig++-dev libboost-all-dev
sudo apt-get -y install gpgsm libxcb-xinerama0 libxcb-icccm4-dev libcups2-dev libdrm-dev libegl1-mesa-dev
sudo apt-get -y install libgcrypt11-dev libnss3-dev libpci-dev libpulse-dev libudev-dev libxtst-dev gyp ninja-build
sudo apt-get -y install libglu1-mesa-dev libfontconfig1-dev libx11-xcb-dev libicu-dev libxcb-image0
sudo apt-get -y install libglu1-mesa-dev libfontconfig1-dev libx11-xcb-dev libicu-dev libxcb-*
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Codesign Configuration (macOS)
run: |
@@ -50,11 +50,14 @@ jobs:
security unlock-keychain -p gpgfrontend build.keychain
security import certificate.p12 -k build.keychain -P ${{secrets.MAOS_CERTIFICATE_PWD}} -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k gpgfrontend build.keychain
+ security set-keychain-settings -lut 3600
if: matrix.os == 'macos-latest'
-
+
- name: Install Dependence (macOS)
run: |
- brew install cmake git autoconf automake qt@5 gcc texinfo gettext libgpg-error libassuan gpgme openssl
+ brew install cmake git autoconf automake qt@5 gcc texinfo gettext libgpg-error libassuan gpgme openssl
+ brew install boost libconfig gettext
+ brew unlink gettext && brew link --force gettext
brew link qt@5
brew link gcc
brew link openssl --force
@@ -66,13 +69,13 @@ jobs:
with:
path: ../Qt
key: ${{ runner.os }}-QtCache
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
cached: ${{ steps.cache-qt.outputs.cache-hit }}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Set up MinGW (Windows)
uses: msys2/setup-msys2@v2
@@ -85,7 +88,7 @@ jobs:
shell: msys2 {0}
run: |
pacman --noconfirm -S --needed mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake autoconf automake mingw-w64-x86_64-qt-creator mingw-w64-x86_64-gpgme
- pacman --noconfirm -S --needed make texinfo
+ pacman --noconfirm -S --needed make texinfo mingw-w64-x86_64-libconfig mingw-w64-x86_64-boost mingw-w64-x86_64-gnupg gettext-devel libintl msys2-runtime-devel
if: matrix.os == 'windows-latest'
- name: Build gpg-error (Linux)
@@ -97,7 +100,7 @@ jobs:
./configure --enable-maintainer-mode --enable-static=yes && make -j2
sudo make install
cd ${{github.workspace}}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Build assuan (Linux)
run: |
@@ -108,7 +111,7 @@ jobs:
./configure --enable-maintainer-mode --enable-static=yes && make -j2
sudo make install
cd ${{github.workspace}}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Build GpgME (Linux)
run: |
@@ -119,7 +122,7 @@ jobs:
./configure --enable-maintainer-mode --enable-static=yes --enable-languages=cpp && make -j2
sudo make install
cd ${{github.workspace}}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Build GpgME (Windows)
shell: msys2 {0}
@@ -127,7 +130,7 @@ jobs:
git clone https://github.com/saturneric/gpgme
cd gpgme
./autogen.sh
- ./configure --enable-maintainer-mode --enable-static=yes --enable-languages=cpp LDFLAGS="-static" && make -j2
+ ./configure --enable-maintainer-mode --enable-static=yes --disable-gpg-test --enable-languages=cpp LDFLAGS="-static" && make -j2
make install
if: matrix.os == 'windows-latest'
@@ -135,15 +138,16 @@ jobs:
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DEXECUTABLE_OUTPUT_PATH=${{env.EXECUTABLE_OUTPUT_PATH}}
- if: matrix.os == 'ubuntu-16.04' || matrix.os == 'macos-latest'
+ if: matrix.os == 'ubuntu-18.04' || matrix.os == 'macos-latest'
- name: Build GpgFrontend
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config $env.BUILD_TYPE}} -- -j 2
- if: matrix.os == 'ubuntu-16.04' || matrix.os == 'macos-latest'
+ if: matrix.os == 'ubuntu-18.04' || matrix.os == 'macos-latest'
- name: Build & Sign App Bundle (macOS)
run: |
+ security -v unlock-keychain -p gpgfrontend
macdeployqt ${{github.workspace}}/build/release/GpgFrontend.app
codesign --deep --force --options=runtime -s "Developer ID Application: Yu Hu (4279AWUL3X)" ${{github.workspace}}/build/release/GpgFrontend.app -v
mkdir ${{github.workspace}}/build/tmp/
@@ -151,11 +155,12 @@ jobs:
- name: Package & Sign App Bundle (macOS)
run: |
+ security -v unlock-keychain -p gpgfrontend
hdiutil create ${{github.workspace}}/build/tmp/tmp.dmg -ov -volname "GpgFrontend" -fs HFS+ -srcfolder ${{github.workspace}}/build/release/
mkdir ${{github.workspace}}/build/artifactOut
hdiutil convert ${{github.workspace}}/build/tmp/tmp.dmg -format UDZO -o ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg
codesign -s "Developer ID Application: Yu Hu (4279AWUL3X)" ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg
- mv ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg ${{github.workspace}}/build/artifactOut/GpgFrontend-${{steps.vars.outputs.sha_short}}-x86_64.dmg
+ mv ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg ${{github.workspace}}/build/artifactOut/GpgFrontend-${{steps.vars.outputs.sha_short}}-x86_64.dmg
if: matrix.os == 'macos-latest'
- name: Notarize Release Build (macOS)
@@ -170,7 +175,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
./linuxdeployqt-continuous-x86_64.AppImage ${{github.workspace}}/build/release/gpgfrontend/usr/share/applications/*.desktop -appimage
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Configure CMake & Build Binary(Windows)
shell: msys2 {0}
@@ -191,7 +196,7 @@ jobs:
with:
name: gpgfrontend-${{matrix.os}}-${{env.BUILD_TYPE}}-${{steps.vars.outputs.sha_short}}
path: ${{github.workspace}}/build/artifactOut/GpgFrontend*.AppImage*
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Upload Artifact(macOS)
uses: actions/upload-artifact@master
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 914b447a..e67cdaf7 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -25,6 +25,7 @@ endif ()
# Using Standard C++-17 (Consider compatibility)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
# CMake
@@ -87,6 +88,9 @@ if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
ADD_DEFINITIONS(-DRELEASE)
message(STATUS "Build Type RELEASE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
+ # Release Version Build MINIMUM_APPLICATION_BUILD
+ set(FULL_APPLICATION_BUILD 0)
+ set(MINIMUM_APPLICATION_BUILD 1)
else ()
set(BUILD_FLAG 1)
ADD_DEFINITIONS(-DDEBUG)
@@ -137,13 +141,13 @@ message(STATUS "Build Version ${BUILD_VERSION}")
message(STATUS "Git Version ${GIT_VERSION}")
IF (MINGW)
-
message(STATUS "Configuration For OS Platform Microsoft Windows")
message(STATUS "Build Environment MINGW")
set(OS_PLATFORM 0)
- ADD_DEFINITIONS(-DWINDOWS)
+ add_definitions(-DWINDOWS)
+ set(Boost_USE_STATIC_LIBS ON)
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
include_directories(
diff --git a/include/GpgFrontend.h b/include/GpgFrontend.h
new file mode 100644
index 00000000..e7250d27
--- /dev/null
+++ b/include/GpgFrontend.h
@@ -0,0 +1,79 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_H_IN
+#define GPGFRONTEND_H_IN
+
+/**
+ * STD Headers
+ */
+#include <iostream>
+#include <string>
+#include <cmath>
+#include <clocale>
+#include <cerrno>
+#include <utility>
+#include <list>
+
+/**
+ * QT Headers
+ */
+#include <QtCore>
+#include <QtWidgets>
+#include <QtNetwork/QtNetwork>
+#include <QtPrintSupport/QtPrintSupport>
+
+/**
+ * GpgME Headers
+ */
+#include <gpgme.h>
+
+/**
+ * Platform Vars
+ */
+#define WINDOWS 0
+#define MACOS 1
+#define LINUX 2
+
+#define OS_PLATFORM 1
+
+/**
+ * Build Options Vars
+ */
+#define RELEASE 0
+#define DEBUG 1
+
+/**
+ * Resources File(s) Path Vars
+ */
+#if OS_PLATFORM == MACOS && BUILD_FLAG == RELEASE
+# define RESOURCE_DIR(appDir) (appDir + "/../Resources/")
+#elif OS_PLATFORM == LINUX && BUILD_FLAG == RELEASE
+# define RESOURCE_DIR(appDir) (appDir + "/../share/")
+#else
+# define RESOURCE_DIR(appDir) (appDir)
+#endif
+
+
+#endif //GPGFRONTEND_H_IN
diff --git a/include/GpgFrontendBuildInfo.h b/include/GpgFrontendBuildInfo.h
new file mode 100644
index 00000000..3f75ebd6
--- /dev/null
+++ b/include/GpgFrontendBuildInfo.h
@@ -0,0 +1,54 @@
+/**
+ * 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.
+ *
+ * Foobar 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 Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_BUILD_INFO_H_IN
+#define GPGFRONTEND_BUILD_INFO_H_IN
+
+/**
+ * Logic Version (*.*.*)
+ */
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 3
+#define VERSION_PATCH 1
+
+/**
+ * Code Version (According to Git)
+ */
+#define GIT_BRANCH_NAME "main"
+#define GIT_COMMIT_HASH "d0146c8c640b2a7ec9a62c3c87a8f5e7c84f1fe7"
+
+/**
+ * Generated Information (According to CMake)
+ */
+#define PROJECT_NAME "GpgFrontend"
+#define BUILD_VERSION "1.3.1_Darwin-20.5.0_x86_64_Debug"
+#define GIT_VERSION "main_d0146c8c640b2a7ec9a62c3c87a8f5e7c84f1fe7"
+
+/**
+ * Build Information
+ */
+#define BUILD_FLAG 1
+#define BUILD_TIMESTAMP "2021-08-28 12:37:33"
+
+#endif // GPGFRONTEND_BUILD_INFO_H_IN
diff --git a/resource/conf/gpgfrontend.ini b/resource/conf/gpgfrontend.ini
deleted file mode 100644
index f606531f..00000000
--- a/resource/conf/gpgfrontend.ini
+++ /dev/null
@@ -1,53 +0,0 @@
-[keyserver]
-keyServerList=http://keys.gnupg.net, https://keyserver.ubuntu.com, http://pool.sks-keyservers.net
-defaultKeyServer=https://keyserver.ubuntu.com
-
-[int]
-lang=en_us
-
-[keys]
-saveKeyChecked=true
-
-[wizard]
-showWizard=true
-
-[window]
-windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x2\0\0\0\x1\0\0\x1\xcc\0\0\x2V\xfc\x2\0\0\0\x1\xfb\0\0\0\x16\0\x45\0n\0\x63\0r\0y\0p\0t\0\x44\0o\0\x63\0k\x1\0\0\0I\0\0\x2V\0\0\0]\0\xff\xff\xff\0\0\0\x3\0\0\x2\xe0\0\0\0\xf5\xfc\x1\0\0\0\x1\xfb\0\0\0\"\0I\0n\0\x66\0o\0r\0m\0\x61\0t\0i\0o\0n\0 \0\x42\0o\0\x61\0r\0\x64\x1\0\0\0\0\0\0\x2\xe0\0\0\x1\xe0\0\xff\xff\xff\0\0\x2\xe0\0\0\x1]\0\0\0\x4\0\0\0\x4\0\0\0\x1\0\0\0\x2\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x5\0\0\0\x16\0\x66\0i\0l\0\x65\0T\0o\0o\0l\0\x42\0\x61\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\x18\0\x63\0r\0y\0p\0t\0T\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\x14\0k\0\x65\0y\0T\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\x1z\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\x16\0\x65\0\x64\0i\0t\0T\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\x2\f\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0$\0s\0p\0\x65\0\x63\0i\0\x61\0l\0\x45\0\x64\0i\0t\0T\0o\0o\0l\0\x42\0\x61\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)
-pos=@Point(100 100)
-size=@Size(1200 700)
-windowSave=false
-
-[advanced]
-steganography=false
-autoPubkeyExchange=true
-
-[gpgpaths]
-keydbpath=.
-
-[sendMail]
-smtpAddress=
-username=
-password=
-port=25
-connectionType=None
-defaultSender=
-enable=false
-
-[toolbar]
-iconsize=@Size(24 24)
-iconstyle=3
-
-[%General]
-currentGpgfrontendServer=service.gpgfrontend.pub
-gpgfrontendServerList=service.gpgfrontend.pub, localhost
-ownKeyId=
-serviceToken=
-confirmImportKeys=true
-
-[keymgmt]
-pos=@Point(100 100)
-size=@Size(900 600)
-setWindowSize=true
-
-[informationBoard]
-fontSize=10 \ No newline at end of file
diff --git a/resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop b/resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop
index bce3dc62..8530e1d6 100644
--- a/resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop
+++ b/resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop
@@ -3,5 +3,5 @@ Type=Application
Name=GpgFrontend
Comment=A Cross-Platform OpenPGP Frontend Software
Exec=GpgFrontend
-Icon=gpgfrontend-appimage-icon
+Icon=GpgFrontend
Categories=Utility;
diff --git a/resource/gpgfrontend/usr/share/icons/hicolor/128x128/apps/GpgFrontend.png b/resource/gpgfrontend/usr/share/icons/hicolor/128x128/apps/GpgFrontend.png
new file mode 100644
index 00000000..5c24791f
--- /dev/null
+++ b/resource/gpgfrontend/usr/share/icons/hicolor/128x128/apps/GpgFrontend.png
Binary files differ
diff --git a/resource/gpgfrontend/usr/share/icons/hicolor/200x200/apps/gpgfrontend-appimage-icon.png b/resource/gpgfrontend/usr/share/icons/hicolor/200x200/apps/gpgfrontend-appimage-icon.png
deleted file mode 100755
index 7366dc97..00000000
--- a/resource/gpgfrontend/usr/share/icons/hicolor/200x200/apps/gpgfrontend-appimage-icon.png
+++ /dev/null
Binary files differ
diff --git a/resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.png b/resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.png
new file mode 100644
index 00000000..b3268b01
--- /dev/null
+++ b/resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.png
Binary files differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 47cd8a50..d5a713b1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -107,7 +107,6 @@ if (APPLICATION_BUILD)
# Copy Resource Files
file(COPY ${CMAKE_SOURCE_DIR}/resource/css DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
file(COPY ${CMAKE_SOURCE_DIR}/resource/icons DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- file(COPY ${CMAKE_SOURCE_DIR}/resource/conf DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
if (MULTI_LANG_SUPPORT)
make_directory(${RESOURCE_OUTPUT_DIRECTORY}/locales)
file(COPY ${CMAKE_SOURCE_DIR}/resource/locale/out/ DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/locales FOLLOW_SYMLINK_CHAIN)
@@ -174,11 +173,11 @@ if (APPLICATION_BUILD)
elseif (LINUX)
add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
add_custom_command(TARGET ${AppName} POST_BUILD
- COMMAND /bin/mkdir ./gpgfrontend/usr/bin && /bin/mv -f ./${AppName} ./gpgfrontend/usr/bin/
+ COMMAND /bin/mkdir -p ./gpgfrontend/usr/bin && /bin/mv -f ./${AppName} ./gpgfrontend/usr/bin/
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
COMMENT "Copying Binary into App Image")
add_custom_command(TARGET ${AppName} POST_BUILD
- COMMAND /bin/mkdir ./gpgfrontend/usr/lib
+ COMMAND /bin/mkdir -p ./gpgfrontend/usr/lib
WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
COMMENT "Complement to build the required architecture")
else ()
@@ -205,22 +204,25 @@ if (APPLICATION_BUILD)
set(GPGFRONTEND_AFTER_UI_LIBS ${GPGFRONTEND_AFTER_UI_LIBS} server)
endif ()
-
set(GPGFRONTEND_LIBS ${GPGFRONTEND_AFTER_UI_LIBS} gpgfrontend-ui ${GPGFRONTEND_BEFORE_UI_LIBS} gpg_core easy_logging_pp)
-
set(QT_DEPENDENCY_LIBS Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core)
+
IF (MINGW)
message(STATUS "Link Application Static Library For MINGW")
+ find_library(libconfig NAMES libconfig++.a)
+ find_library(libintl NAMES libintl.a)
+ find_library(libiconv NAMES libiconv.a)
+
target_link_libraries(${AppName}
${GPGFRONTEND_LIBS}
${QT_DEPENDENCY_LIBS}
- crypto ssl)
+ ${libintl} ${libiconv} ${libconfig} crypto ssl)
elseif (APPLE)
message(STATUS "Link Application Static Library For macOS")
target_link_libraries(${AppName}
${GPGFRONTEND_LIBS}
${QT_DEPENDENCY_LIBS}
- crypto ssl)
+ crypto ssl intl)
else ()
message(STATUS "Link Application Static Library For UNIX ")
target_link_libraries(${AppName}
diff --git a/src/GpgFrontend.h.in b/src/GpgFrontend.h.in
index 1814ddbc..622c2b07 100644
--- a/src/GpgFrontend.h.in
+++ b/src/GpgFrontend.h.in
@@ -26,12 +26,23 @@
#define GPGFRONTEND_H_IN
// i18n
+#ifdef WINDOWS
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
#include <libintl.h>
#define _(String) gettext (String)
#define gettext_noop(String) String
#define N_(String) gettext_noop (String)
+#ifdef WINDOWS
+#include <clocale>
+#undef vsnprintf
+#endif
+
// logging
+#define ELPP_DEFAULT_LOGGING_FLAGS 8192
#include <easyloggingpp/easylogging++.h>
#define PROJECT_NAME "@CMAKE_PROJECT_NAME@"
diff --git a/src/gpg/CMakeLists.txt b/src/gpg/CMakeLists.txt
index 36a81591..886f8fdc 100644
--- a/src/gpg/CMakeLists.txt
+++ b/src/gpg/CMakeLists.txt
@@ -23,11 +23,16 @@ if (MINGW)
target_link_libraries(gpg_core ${THIRD_PARTY_LIBS}
${BOOST_LIBS}
gpgme gpg-error assuan wsock32)
+ target_compile_features(gpg_core PUBLIC cxx_std_17)
elseif (APPLE)
+ find_library(libgpgme NAMES libgpgme.a)
+ find_library(libgpg-error NAMES libgpg-error.a)
+ find_library(libassuan NAMES libassuan.a)
message(STATUS "Link GPG Static Library For macOS")
target_link_libraries(gpg_core ${THIRD_PARTY_LIBS}
${BOOST_LIBS}
- libgpgme.a libgpg-error.a libassuan.a dl)
+ ${libgpgme} ${libgpg-error} ${libassuan}
+ dl)
else ()
message(STATUS "Link GPG Static Library For Unix")
target_link_libraries(gpg_core ${THIRD_PARTY_LIBS}
diff --git a/src/gpg/GpgConstants.cpp b/src/gpg/GpgConstants.cpp
index aa56fe10..5688287e 100644
--- a/src/gpg/GpgConstants.cpp
+++ b/src/gpg/GpgConstants.cpp
@@ -27,7 +27,7 @@
#include <gpg-error.h>
#include <boost/algorithm/string/predicate.hpp>
-#include <filesystem>
+#include <boost/filesystem.hpp>
const char* GpgFrontend::GpgConstants::PGP_CRYPT_BEGIN =
"-----BEGIN PGP MESSAGE-----";
@@ -78,9 +78,9 @@ gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err,
std::string GpgFrontend::beautify_fingerprint(
GpgFrontend::BypeArrayConstRef fingerprint) {
auto _fingerprint = fingerprint;
- uint len = fingerprint.size();
+ unsigned len = fingerprint.size();
if ((len > 0) && (len % 4 == 0))
- for (uint n = 0; 4 * (n + 1) < len; ++n)
+ for (unsigned n = 0; 4 * (n + 1) < len; ++n)
_fingerprint.insert(static_cast<int>(5u * n + 4u), " ");
return fingerprint;
}
@@ -108,7 +108,7 @@ static inline std::string trim(std::string& s) {
}
std::string GpgFrontend::read_all_data_in_file(const std::string& path) {
- using namespace std::filesystem;
+ using namespace boost::filesystem;
class path file_info(path.c_str());
if (!exists(file_info) || !is_regular_file(path))
@@ -126,7 +126,7 @@ std::string GpgFrontend::read_all_data_in_file(const std::string& path) {
bool GpgFrontend::write_buffer_to_file(const std::string& path,
const std::string& out_buffer) {
- std::ofstream out_file(std::filesystem::path(path), std::ios::out);
+ std::ofstream out_file(boost::filesystem::path(path).string(), std::ios::out);
if (!out_file.good()) return false;
out_file.write(out_buffer.c_str(), out_buffer.size());
out_file.close();
@@ -135,7 +135,7 @@ bool GpgFrontend::write_buffer_to_file(const std::string& path,
std::string GpgFrontend::get_file_extension(const std::string& path) {
// Create a Path object from given string
- std::filesystem::path path_obj(path);
+ boost::filesystem::path path_obj(path);
// Check if file name in the path object has extension
if (path_obj.has_extension()) {
// Fetch the extension from path object and return
@@ -147,11 +147,11 @@ std::string GpgFrontend::get_file_extension(const std::string& path) {
std::string GpgFrontend::get_only_file_name_with_path(const std::string& path) {
// Create a Path object from given string
- std::filesystem::path path_obj(path);
+ boost::filesystem::path path_obj(path);
// Check if file name in the path object has extension
if (path_obj.has_filename()) {
// Fetch the extension from path object and return
- return path_obj.parent_path() / path_obj.stem();
+ return (path_obj.parent_path() / path_obj.stem()).string();
}
// In case of no extension return empty string
throw std::runtime_error("invalid file path");
diff --git a/src/gpg/GpgConstants.h b/src/gpg/GpgConstants.h
index 4804924a..1cd0f64d 100644
--- a/src/gpg/GpgConstants.h
+++ b/src/gpg/GpgConstants.h
@@ -25,19 +25,16 @@
#ifndef GPG_CONSTANTS_H
#define GPG_CONSTANTS_H
-#define ELPP_DEFAULT_LOGGING_FLAGS 8192
-#include <easyloggingpp/easylogging++.h>
+#include "GpgFrontend.h"
+
#include <gpg-error.h>
#include <gpgme.h>
#include <cassert>
#include <functional>
-#include <libconfig.h++>
#include <memory>
#include <string>
-#include "GpgFrontend.h"
-
const int RESTART_CODE = 1000;
namespace GpgFrontend {
diff --git a/src/gpg/GpgContext.h b/src/gpg/GpgContext.h
index 7df90060..4a9b6fc0 100644
--- a/src/gpg/GpgContext.h
+++ b/src/gpg/GpgContext.h
@@ -25,6 +25,8 @@
#ifndef __SGPGMEPP_CONTEXT_H__
#define __SGPGMEPP_CONTEXT_H__
+#include "GpgConstants.h"
+
#include "GpgFunctionObject.h"
#include "GpgInfo.h"
#include "GpgModel.h"
@@ -36,7 +38,7 @@ namespace GpgFrontend {
*/
class GpgContext : public SingletonFunctionObject<GpgContext> {
public:
- GpgContext(bool independent_database = false,
+ explicit GpgContext(bool independent_database = false,
std::string path = std::string(), int channel = 0);
~GpgContext() override = default;
diff --git a/src/gpg/GpgModel.h b/src/gpg/GpgModel.h
index a9351e50..3e07427c 100644
--- a/src/gpg/GpgModel.h
+++ b/src/gpg/GpgModel.h
@@ -25,6 +25,8 @@
#ifndef GPGFRONTEND_ZH_CN_TS_GPGMODEL_H
#define GPGFRONTEND_ZH_CN_TS_GPGMODEL_H
+#include "GpgConstants.h"
+
#include <list>
#include <utility>
diff --git a/src/gpg/function/GpgCommandExecutor.cpp b/src/gpg/function/GpgCommandExecutor.cpp
index a494d4a8..9b99b400 100644
--- a/src/gpg/function/GpgCommandExecutor.cpp
+++ b/src/gpg/function/GpgCommandExecutor.cpp
@@ -22,8 +22,11 @@
*
*/
#include "gpg/function/GpgCommandExecutor.h"
-
+#ifndef WINDOWS
#include <boost/asio.hpp>
+#endif
+
+#ifndef WINDOWS
using boost::process::async_pipe;
@@ -52,3 +55,5 @@ void GpgFrontend::GpgCommandExecutor::Execute(
child_process.wait();
child_process.exit_code();
}
+
+#endif
diff --git a/src/gpg/function/GpgCommandExecutor.h b/src/gpg/function/GpgCommandExecutor.h
index a6eaaf4a..f28caca8 100644
--- a/src/gpg/function/GpgCommandExecutor.h
+++ b/src/gpg/function/GpgCommandExecutor.h
@@ -25,7 +25,9 @@
#ifndef GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H
#define GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H
+#ifndef WINDOWS
#include <boost/process.hpp>
+#endif
#include "gpg/GpgContext.h"
#include "gpg/GpgFunctionObject.h"
@@ -33,10 +35,13 @@
namespace GpgFrontend {
class GpgCommandExecutor : public SingletonFunctionObject<GpgCommandExecutor> {
public:
+
+#ifndef WINDOWS
void Execute(StringArgsRef arguments,
const std::function<void(boost::process::async_pipe &in,
boost::process::async_pipe &out)>
&interact_func);
+#endif
private:
GpgContext &ctx = GpgContext::GetInstance();
diff --git a/src/gpg/function/GpgKeyOpera.cpp b/src/gpg/function/GpgKeyOpera.cpp
index a7371904..c60f9157 100644
--- a/src/gpg/function/GpgKeyOpera.cpp
+++ b/src/gpg/function/GpgKeyOpera.cpp
@@ -24,7 +24,7 @@
#include "gpg/function/GpgKeyOpera.h"
-#include <boost/asio/read_until.hpp>
+#include <boost/asio.hpp>
#include <boost/date_time/posix_time/conversion.hpp>
#include <boost/process/async_pipe.hpp>
#include <memory>
@@ -99,38 +99,45 @@ void GpgFrontend::GpgKeyOpera::GenerateRevokeCert(
using boost::asio::async_write;
using boost::process::async_pipe;
+#ifndef WINDOWS
GpgCommandExecutor::GetInstance().Execute(
args, [](async_pipe& in, async_pipe& out) -> void {
- boost::asio::streambuf buff;
- boost::asio::read_until(in, buff, '\n');
-
- std::istream is(&buff);
-
- while (!is.eof()) {
- std::string line;
- is >> line;
- LOG(INFO) << "line" << line;
- boost::algorithm::trim(line);
- if (line == std::string("[GNUPG:] GET_BOOL gen_revoke.okay")) {
-
- } else if (line ==
- std::string(
- "[GNUPG:] GET_LINE ask_revocation_reason.code")) {
-
- } else if (line ==
- std::string(
- "[GNUPG:] GET_LINE ask_revocation_reason.text")) {
-
- } else if (line ==
- std::string("[GNUPG:] GET_BOOL openfile.overwrite.okay")) {
-
- } else if (line ==
- std::string(
- "[GNUPG:] GET_BOOL ask_revocation_reason.okay")) {
-
- }
- }
+ // boost::asio::streambuf buff;
+ // boost::asio::read_until(in, buff, '\n');
+ //
+ // std::istream is(&buff);
+ //
+ // while (!is.eof()) {
+ // std::string line;
+ // is >> line;
+ // LOG(INFO) << "line" << line;
+ // boost::algorithm::trim(line);
+ // if (line == std::string("[GNUPG:] GET_BOOL
+ // gen_revoke.okay")) {
+ //
+ // } else if (line ==
+ // std::string(
+ // "[GNUPG:] GET_LINE
+ // ask_revocation_reason.code")) {
+ //
+ // } else if (line ==
+ // std::string(
+ // "[GNUPG:] GET_LINE
+ // ask_revocation_reason.text")) {
+ //
+ // } else if (line ==
+ // std::string("[GNUPG:] GET_BOOL
+ // openfile.overwrite.okay")) {
+ //
+ // } else if (line ==
+ // std::string(
+ // "[GNUPG:] GET_BOOL
+ // ask_revocation_reason.okay")) {
+ //
+ // }
+ // }
});
+#endif
}
/**
diff --git a/src/gpg/result_analyse/VerifyResultAnalyse.cpp b/src/gpg/result_analyse/VerifyResultAnalyse.cpp
index 849c2051..55e50f38 100644
--- a/src/gpg/result_analyse/VerifyResultAnalyse.cpp
+++ b/src/gpg/result_analyse/VerifyResultAnalyse.cpp
@@ -113,7 +113,7 @@ void GpgFrontend::VerifyResultAnalyse::do_analyse() {
case GPG_ERR_NO_PUBKEY:
stream << _("A signature could NOT be verified due to a Missing Key")
<< std::endl;
- setStatus(-1);
+ setStatus(-2);
break;
case GPG_ERR_CERT_REVOKED:
stream << _("A signature is valid but the key used to verify the "
@@ -184,3 +184,10 @@ bool GpgFrontend::VerifyResultAnalyse::print_signer(std::stringstream &stream,
stream << std::endl;
return keyFound;
}
+
+gpgme_signature_t GpgFrontend::VerifyResultAnalyse::GetSignatures() {
+ if (result)
+ return result->signatures;
+ else
+ return nullptr;
+}
diff --git a/src/gpg/result_analyse/VerifyResultAnalyse.h b/src/gpg/result_analyse/VerifyResultAnalyse.h
index c3364025..51ce17ac 100644
--- a/src/gpg/result_analyse/VerifyResultAnalyse.h
+++ b/src/gpg/result_analyse/VerifyResultAnalyse.h
@@ -34,6 +34,8 @@ class VerifyResultAnalyse : public ResultAnalyse {
public:
explicit VerifyResultAnalyse(GpgError error, GpgVerifyResult result);
+ gpgme_signature_t GetSignatures();
+
private:
void do_analyse();
diff --git a/src/main.cpp b/src/main.cpp
index e3506064..82cfe9c1 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -74,8 +74,6 @@ int main(int argc, char* argv[]) {
*/
int return_from_event_loop_code;
- LOG(INFO) << _("Resource Directory") << RESOURCE_DIR(app_path);
-
do {
QApplication::setQuitOnLastWindowClosed(true);
@@ -135,25 +133,41 @@ void init_locale() {
settings.lookup("general").getType() != libconfig::Setting::TypeGroup)
settings.add("general", libconfig::Setting::TypeGroup);
+ // set system default at first
auto& general = settings["general"];
if (!general.exists("lang"))
- general.add("lang", libconfig::Setting::TypeString) =
- QLocale::system().name().toStdString();
+ general.add("lang", libconfig::Setting::TypeString) = "";
GpgFrontend::UI::GlobalSettingStation::GetInstance().Sync();
+ auto* locale_name = setlocale(LC_ALL, nullptr);
+ LOG(INFO) << "current system locale" << locale_name;
+
+ // read from settings file
std::string lang;
if (!general.lookupValue("lang", lang)) {
LOG(ERROR) << _("Could not read properly from configure file");
};
LOG(INFO) << "lang" << lang;
+ LOG(INFO) << "PROJECT_NAME" << PROJECT_NAME;
+ LOG(INFO) << "locales path"
+ << GpgFrontend::UI::GlobalSettingStation::GetInstance()
+ .GetLocaleDir()
+ .c_str();
+ if (!lang.empty()) lang += ".UTF8";
// GNU gettext settings
- setlocale(LC_ALL, lang.c_str());
+ locale_name = setlocale(LC_ALL, lang.c_str());
+ if (locale_name == nullptr) {
+ LOG(WARNING) << "set locale name failed";
+ } else {
+ LOG(INFO) << "locale name now" << locale_name;
+ }
+
bindtextdomain(PROJECT_NAME,
GpgFrontend::UI::GlobalSettingStation::GetInstance()
.GetLocaleDir()
- .c_str());
+ .string().c_str());
textdomain(PROJECT_NAME);
}
diff --git a/src/smtp/smtpexports.h b/src/smtp/smtpexports.h
index 9ca12bae..4bad0da0 100644
--- a/src/smtp/smtpexports.h
+++ b/src/smtp/smtpexports.h
@@ -1,10 +1,10 @@
-#ifndef SMTPEXPORTS_H
-#define SMTPEXPORTS_H
-
-#ifdef SMTP_BUILD
-#define SMTP_EXPORT
-#else
-#define SMTP_EXPORT
-#endif
-
-#endif // SMTPEXPORTS_H
+#ifndef SMTPEXPORTS_H
+#define SMTPEXPORTS_H
+
+#ifdef SMTP_BUILD
+#define SMTP_EXPORT
+#else
+#define SMTP_EXPORT
+#endif
+
+#endif // SMTPEXPORTS_H
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index acd0e42f..b80da2ec 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -16,4 +16,6 @@ endif ()
add_library(gpgfrontend-ui STATIC ${UI_SOURCE})
target_link_libraries(gpgfrontend-ui
- Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) \ No newline at end of file
+ Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core)
+
+target_compile_features(gpgfrontend-ui PUBLIC cxx_std_17) \ No newline at end of file
diff --git a/src/ui/GpgFrontendUI.h b/src/ui/GpgFrontendUI.h
index c5d80d01..01f82822 100644
--- a/src/ui/GpgFrontendUI.h
+++ b/src/ui/GpgFrontendUI.h
@@ -25,13 +25,17 @@
#ifndef GPGFRONTEND_GPGFRONTENDUI_H
#define GPGFRONTEND_GPGFRONTENDUI_H
-#include <GpgFrontend.h>
+#include "GpgFrontend.h"
#include <QtCore>
#include <QtNetwork>
#include <QtPrintSupport>
#include <QtWidgets>
+#undef LIBCONFIGXX_STATIC
+#define LIBCONFIGXX_STATIC
+#include <libconfig.h++>
+
/**
* Resources File(s) Path Vars
*/
diff --git a/src/ui/KeyServerImportDialog.cpp b/src/ui/KeyServerImportDialog.cpp
index c7d9cd37..17db7d65 100644
--- a/src/ui/KeyServerImportDialog.cpp
+++ b/src/ui/KeyServerImportDialog.cpp
@@ -195,6 +195,8 @@ void KeyServerImportDialog::createKeysTable() {
}
void KeyServerImportDialog::setMessage(const QString& text, bool error) {
+ if (mAutomatic) return;
+
message->setText(text);
if (error) {
icon->setPixmap(
@@ -429,7 +431,8 @@ void KeyServerImportDialog::slotImport(const QStringList& keyIds,
auto manager = new QNetworkAccessManager(this);
QNetworkReply* reply = manager->get(QNetworkRequest(req_url));
- connect(reply, SIGNAL(finished()), this, SLOT(slotImportFinished()));
+ connect(reply, &QNetworkReply::finished, this,
+ [&, keyId]() { this->slotImportFinished(keyId); });
LOG(INFO) << "loading start";
setLoading(true);
while (reply->isRunning()) QApplication::processEvents();
@@ -438,7 +441,7 @@ void KeyServerImportDialog::slotImport(const QStringList& keyIds,
}
}
-void KeyServerImportDialog::slotImportFinished() {
+void KeyServerImportDialog::slotImportFinished(QString keyid) {
LOG(INFO) << _("Called");
auto* reply = qobject_cast<QNetworkReply*>(sender());
@@ -448,18 +451,39 @@ void KeyServerImportDialog::slotImportFinished() {
auto error = reply->error();
if (error != QNetworkReply::NoError) {
LOG(ERROR) << "Error From Reply" << reply->errorString().toStdString();
- switch (error) {
- case QNetworkReply::ContentNotFoundError:
- setMessage(_("Key Not Found"), true);
- break;
- case QNetworkReply::TimeoutError:
- setMessage(_("Timeout"), true);
- break;
- case QNetworkReply::HostNotFoundError:
- setMessage(_("Key Server Not Found"), true);
- break;
- default:
- setMessage(_("Connection Error"), true);
+ if (!mAutomatic) {
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ setMessage(_("Key Not Found"), true);
+ break;
+ case QNetworkReply::TimeoutError:
+ setMessage(_("Timeout"), true);
+ break;
+ case QNetworkReply::HostNotFoundError:
+ setMessage(_("Key Server Not Found"), true);
+ break;
+ default:
+ setMessage(_("Connection Error"), true);
+ }
+ } else {
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ QMessageBox::critical(
+ nullptr, _("Public key Not Found"),
+ QString(_("Public key fingerprint %1 not found in the Keyserver"))
+ .arg(keyid));
+ break;
+ case QNetworkReply::TimeoutError:
+ QMessageBox::critical(nullptr, _("Timeout"), "Connection timeout");
+ break;
+ case QNetworkReply::HostNotFoundError:
+ QMessageBox::critical(nullptr, _("Host Not Found"),
+ "cannot resolve the default Keyserver");
+ break;
+ default:
+ QMessageBox::critical(nullptr, _("Connection Error"),
+ _("General Connection Error"));
+ }
}
if (mAutomatic) {
setWindowFlags(Qt::Window | Qt::WindowTitleHint |
diff --git a/src/ui/KeyServerImportDialog.h b/src/ui/KeyServerImportDialog.h
index d7f3364d..67571f2f 100644
--- a/src/ui/KeyServerImportDialog.h
+++ b/src/ui/KeyServerImportDialog.h
@@ -53,7 +53,7 @@ class KeyServerImportDialog : public QDialog {
void slotSearchFinished();
- void slotImportFinished();
+ void slotImportFinished(QString keyid);
void slotSearch();
diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp
index 31271ef1..6b0977fd 100644
--- a/src/ui/MainWindow.cpp
+++ b/src/ui/MainWindow.cpp
@@ -26,7 +26,7 @@
#include "ui/UserInterfaceUtils.h"
#ifdef RELEASE
-#include "ui/help/VersionCheckThread.h"
+#include "ui/function/VersionCheckThread.h"
#endif
#include "ui/settings/GlobalSettingStation.h"
diff --git a/src/ui/Wizard.cpp b/src/ui/Wizard.cpp
index 67af385b..de0107c4 100644
--- a/src/ui/Wizard.cpp
+++ b/src/ui/Wizard.cpp
@@ -99,7 +99,9 @@ IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) {
topLabel->setWordWrap(true);
// QComboBox for language selection
- auto* langLabel = new QLabel(_("Choose a Language"));
+ auto* langLabel =
+ new QLabel(_("If it supports the language currently being used in your "
+ "system, GpgFrontend will automatically set it."));
langLabel->setWordWrap(true);
languages = SettingsDialog::listLanguages();
@@ -110,56 +112,64 @@ IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) {
}
// selected entry from config
- auto lang = "en_US";
- auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
- try {
- lang = settings.lookup("general.lang");
- } catch (...) {
- LOG(INFO) << "Read for general.lang failed";
- }
-
- QString langKey = lang;
- QString langValue = languages.value(langKey);
- if (!langKey.isEmpty()) {
- langSelectBox->setCurrentIndex(langSelectBox->findText(langValue));
- }
-
- connect(langSelectBox, SIGNAL(currentIndexChanged(QString)), this,
- SLOT(slotLangChange(QString)));
+ // auto lang = "";
+ // auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ // try {
+ // lang = settings.lookup("general.lang");
+ // } catch (...) {
+ // LOG(INFO) << "Read for general.lang failed";
+ // }
+ //
+ // QString langKey = lang;
+ // QString langValue = languages.value(langKey);
+ // LOG(INFO) << "lang key" << langKey.toStdString() << "lang value"
+ // << langValue.toStdString();
+ // langSelectBox->setCurrentIndex(langSelectBox->findText(langValue));
+
+ // connect(langSelectBox, SIGNAL(currentIndexChanged(QString)), this,
+ // SLOT(slotLangChange(QString)));
// set layout and add widgets
auto* layout = new QVBoxLayout;
layout->addWidget(topLabel);
+ layout->addStretch();
layout->addWidget(langLabel);
- layout->addWidget(langSelectBox);
+ // layout->addWidget(langSelectBox);
+
setLayout(layout);
}
-void IntroPage::slotLangChange(const QString& lang) {
- auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
-
- if (!settings.exists("general") ||
- settings.lookup("general").getType() != libconfig::Setting::TypeGroup)
- settings.add("general", libconfig::Setting::TypeGroup);
-
- auto& general = settings["general"];
- if (!general.exists("lang"))
- general.add("lang", libconfig::Setting::TypeString) =
- languages.key(lang).toStdString();
-
- if (!settings.exists("wizard") ||
- settings.lookup("wizard").getType() != libconfig::Setting::TypeGroup)
- settings.add("wizard", libconfig::Setting::TypeGroup);
-
- auto& wizard = settings["wizard"];
- if (!wizard.exists("next_page"))
- wizard.add("next_page", libconfig::Setting::TypeInt) =
- this->wizard()->currentId();
-
- GlobalSettingStation::GetInstance().Sync();
-
- qApp->exit(RESTART_CODE);
-}
+// void IntroPage::slotLangChange(const QString& lang) {
+// auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+//
+// if (!settings.exists("general") ||
+// settings.lookup("general").getType() != libconfig::Setting::TypeGroup)
+// settings.add("general", libconfig::Setting::TypeGroup);
+//
+// auto& general = settings["general"];
+// if (!general.exists("lang"))
+// general.add("lang", libconfig::Setting::TypeString) =
+// languages.key(lang).toStdString();
+// else {
+// general["lang"] = languages.key(lang).toStdString();
+// }
+//
+// if (!settings.exists("wizard") ||
+// settings.lookup("wizard").getType() != libconfig::Setting::TypeGroup)
+// settings.add("wizard", libconfig::Setting::TypeGroup);
+//
+// auto& wizard = settings["wizard"];
+// if (!wizard.exists("next_page"))
+// wizard.add("next_page", libconfig::Setting::TypeInt) =
+// this->wizard()->currentId();
+// else {
+// wizard["next_page"] = this->wizard()->currentId();
+// }
+//
+// GlobalSettingStation::GetInstance().Sync();
+//
+// qApp->exit(RESTART_CODE);
+// }
int IntroPage::nextId() const { return Wizard::Page_Choose; }
diff --git a/src/ui/Wizard.h b/src/ui/Wizard.h
index 5a66fb6e..8d7395db 100644
--- a/src/ui/Wizard.h
+++ b/src/ui/Wizard.h
@@ -64,7 +64,7 @@ class IntroPage : public QWizardPage {
private:
private slots:
- void slotLangChange(const QString& lang);
+ // void slotLangChange(const QString& lang);
};
class ChoosePage : public QWizardPage {
diff --git a/src/ui/function/FileReadThread.cpp b/src/ui/function/FileReadThread.cpp
index 34ade8e2..a5a861ea 100644
--- a/src/ui/function/FileReadThread.cpp
+++ b/src/ui/function/FileReadThread.cpp
@@ -32,15 +32,15 @@ namespace GpgFrontend::UI {
FileReadThread::FileReadThread(std::string path) : path(std::move(path)) {}
void FileReadThread::run() {
- LOG(INFO) << "read_thread Started";
+ LOG(INFO) << "Started";
boost::filesystem::path read_file_path(this->path);
if (is_regular_file(read_file_path)) {
- LOG(INFO) << "read_thread Read Open";
+ LOG(INFO) << "Read Open";
- auto fp = fopen(read_file_path.c_str(), "r");
+ auto fp = fopen(read_file_path.string().c_str(), "r");
size_t read_size;
LOG(INFO) << "Thread Start Reading";
-
+
char buffer[8192];
while ((read_size = fread(buffer, sizeof(char), sizeof buffer, fp)) > 0) {
// Check isInterruptionRequested
@@ -53,6 +53,11 @@ void FileReadThread::run() {
std::string buffer_str(buffer, read_size);
emit sendReadBlock(QString::fromStdString(buffer_str));
+#ifdef RELEASE
+ QThread::msleep(16);
+#else
+ QThread::msleep(24);
+#endif
}
fclose(fp);
emit readDone();
diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
index 7b239bf1..4458be50 100644
--- a/src/ui/keypair_details/KeyPairSubkeyTab.cpp
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
@@ -185,7 +185,7 @@ void KeyPairSubkeyTab::slotRefreshSubkeyList() {
if (!row) {
for (auto i = 0; i < subkeyList->columnCount(); i++) {
- subkeyList->item(row, i)->setTextColor(QColor(65, 105, 255));
+ subkeyList->item(row, i)->setForeground(QColor(65, 105, 255));
}
}
diff --git a/src/ui/keypair_details/KeyPairUIDTab.cpp b/src/ui/keypair_details/KeyPairUIDTab.cpp
index 7358c20a..0ca7eb2c 100644
--- a/src/ui/keypair_details/KeyPairUIDTab.cpp
+++ b/src/ui/keypair_details/KeyPairUIDTab.cpp
@@ -177,7 +177,7 @@ void KeyPairUIDTab::slotRefreshUIDList() {
if (!row) {
for (auto i = 0; i < uidList->columnCount(); i++) {
- uidList->item(row, i)->setTextColor(QColor(65, 105, 255));
+ uidList->item(row, i)->setForeground(QColor(65, 105, 255));
}
}
diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp
index b0f7c535..0b4f7837 100644
--- a/src/ui/main_window/MainWindowFileSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp
@@ -278,11 +278,37 @@ void MainWindow::slotFileVerify() {
resultAnalyse.analyse();
process_result_analyse(edit, infoBoard, resultAnalyse);
- // if (resultAnalyse->getStatus() >= 0) {
+ if (resultAnalyse.getStatus() == -2) {
+ QMessageBox::StandardButton reply;
+ reply = QMessageBox::question(
+ this, _("Public key not found locally"),
+ _("There is no target public key content in local for GpgFrontend to "
+ "gather enough information about this Signature. Do you want to "
+ "import the public key from Keyserver now?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (reply == QMessageBox::Yes) {
+ qDebug() << "Yes was clicked";
+ auto dialog = KeyServerImportDialog(true, this);
+ auto key_ids = std::make_unique<KeyIdArgsList>();
+ auto* signature = resultAnalyse.GetSignatures();
+ while (signature != nullptr) {
+ LOG(INFO) << "signature fpr" << signature->fpr;
+ key_ids->push_back(signature->fpr);
+ signature = signature->next;
+ }
+ dialog.slotImport(key_ids);
+ dialog.show();
+
+ } else {
+ qDebug() << "Yes was *not* clicked";
+ }
+ }
+
+ // if (resultAnalyse.getStatus() >= 0) {
// infoBoard->resetOptionActionsMenu();
// infoBoard->addOptionalAction(
- // "Show Verify Details", [this, error, result]() {
- // VerifyDetailsDialog(this, mCtx, mKeyList, error, result);
+ // "Show Verify Details", [this, error, &result]() {
+ // VerifyDetailsDialog(this, mKeyList, error, result);
// });
// }
diff --git a/src/ui/settings/GlobalSettingStation.cpp b/src/ui/settings/GlobalSettingStation.cpp
index 8946d267..e88de93b 100644
--- a/src/ui/settings/GlobalSettingStation.cpp
+++ b/src/ui/settings/GlobalSettingStation.cpp
@@ -38,7 +38,7 @@ GpgFrontend::UI::GlobalSettingStation::GetInstance() {
void GpgFrontend::UI::GlobalSettingStation::Sync() noexcept {
using namespace libconfig;
try {
- ui_cfg.writeFile(ui_config_path.c_str());
+ ui_cfg.writeFile(ui_config_path.string().c_str());
LOG(INFO) << _("Updated ui configuration successfully written to")
<< ui_config_path;
@@ -70,7 +70,7 @@ GpgFrontend::UI::GlobalSettingStation::GlobalSettingStation() noexcept {
if (!exists(ui_config_path)) {
try {
- this->ui_cfg.writeFile(ui_config_path.c_str());
+ this->ui_cfg.writeFile(ui_config_path.string().c_str());
LOG(INFO) << _("UserInterface configuration successfully written to")
<< ui_config_path;
@@ -81,7 +81,7 @@ GpgFrontend::UI::GlobalSettingStation::GlobalSettingStation() noexcept {
}
} else {
try {
- this->ui_cfg.readFile(ui_config_path.c_str());
+ this->ui_cfg.readFile(ui_config_path.string().c_str());
LOG(INFO) << _("UserInterface configuration successfully read from")
<< ui_config_path;
} catch (const FileIOException& fioex) {
diff --git a/src/ui/settings/GlobalSettingStation.h b/src/ui/settings/GlobalSettingStation.h
index 22713626..ef2c6a9a 100644
--- a/src/ui/settings/GlobalSettingStation.h
+++ b/src/ui/settings/GlobalSettingStation.h
@@ -27,7 +27,6 @@
#include <boost/filesystem/operations.hpp>
#include <boost/filesystem/path.hpp>
-#include <libconfig.h++>
#include "ui/GpgFrontendUI.h"
diff --git a/src/ui/settings/SettingsDialog.cpp b/src/ui/settings/SettingsDialog.cpp
index 7fac5348..fcef70c7 100644
--- a/src/ui/settings/SettingsDialog.cpp
+++ b/src/ui/settings/SettingsDialog.cpp
@@ -131,7 +131,7 @@ QHash<QString, QString> SettingsDialog::listLanguages() {
auto locale_path = GlobalSettingStation::GetInstance().GetLocaleDir();
- auto locale_dir = QDir(locale_path.c_str());
+ auto locale_dir = QDir(QString::fromStdString(locale_path.string()) );
QStringList file_names = locale_dir.entryList(QStringList("*"));
for (int i = 0; i < file_names.size(); ++i) {
diff --git a/src/ui/settings/SettingsGeneral.cpp b/src/ui/settings/SettingsGeneral.cpp
index c0db08a5..e6ee5499 100644
--- a/src/ui/settings/SettingsGeneral.cpp
+++ b/src/ui/settings/SettingsGeneral.cpp
@@ -206,7 +206,9 @@ void GeneralTab::setSettings() {
QString lang_value = lang.value(lang_key.c_str());
LOG(INFO) << "lang settings current" << lang_value.toStdString();
if (!lang.empty()) {
- langSelectBox->setCurrentIndex(langSelectBox->findText(lang_key.c_str()));
+ langSelectBox->setCurrentIndex(langSelectBox->findText(lang_value));
+ } else {
+ langSelectBox->setCurrentIndex(0);
}
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("lang");
@@ -275,26 +277,26 @@ void GeneralTab::applySettings() {
#ifdef MULTI_LANG_SUPPORT
if (!general.exists("lang"))
general.add("lang", libconfig::Setting::TypeBoolean) =
- langSelectBox->currentText().toStdString();
+ lang.key(langSelectBox->currentText()).toStdString();
else {
- general["lang"] = langSelectBox->currentText().toStdString();
+ general["lang"] = lang.key(langSelectBox->currentText()).toStdString();
#endif
+ }
#ifdef SERVER_SUPPORT
- settings.setValue(
- "general/ownKeyId",
- QString::fromStdString(keyIdsList[ownKeySelectBox->currentIndex()]));
+ settings.setValue(
+ "general/ownKeyId",
+ QString::fromStdString(keyIdsList[ownKeySelectBox->currentIndex()]));
- settings.setValue("general/serviceToken",
- QString::fromStdString(serviceToken));
+ settings.setValue("general/serviceToken",
+ QString::fromStdString(serviceToken));
#endif
- if (!general.exists("confirm_import_keys"))
- general.add("confirm_import_keys", libconfig::Setting::TypeBoolean) =
- importConfirmationCheckBox->isChecked();
- else {
- general["confirm_import_keys"] = importConfirmationCheckBox->isChecked();
- }
+ if (!general.exists("confirm_import_keys"))
+ general.add("confirm_import_keys", libconfig::Setting::TypeBoolean) =
+ importConfirmationCheckBox->isChecked();
+ else {
+ general["confirm_import_keys"] = importConfirmationCheckBox->isChecked();
}
}
diff --git a/src/ui/widgets/EditorPage.cpp b/src/ui/widgets/EditorPage.cpp
index eeedfaf5..94c98036 100644
--- a/src/ui/widgets/EditorPage.cpp
+++ b/src/ui/widgets/EditorPage.cpp
@@ -107,9 +107,11 @@ void EditorPage::slotFormatGpgHeader() {
cursor.setCharFormat(signFormat);
}
-void EditorPage::readFile() {
+void EditorPage::ReadFile() {
LOG(INFO) << "Called";
+ readDone = false;
+
auto text_page = this->getTextPage();
text_page->setReadOnly(true);
auto thread = new FileReadThread(this->fullFilePath.toStdString());
@@ -126,19 +128,27 @@ void EditorPage::readFile() {
connect(thread, &FileReadThread::finished, this, [=]() {
LOG(INFO) << "Thread finished";
thread->deleteLater();
+ readDone = true;
+ readThread = nullptr;
});
- connect(this, &FileReadThread::destroyed, [=]() {
+ connect(this, &EditorPage::destroyed, [=]() {
LOG(INFO) << "RequestInterruption for readThread";
thread->requestInterruption();
- thread->deleteLater();
+ readThread = nullptr;
});
-
+ this->readThread = thread;
thread->start();
}
void EditorPage::slotInsertText(const QString& text) {
this->getTextPage()->insertPlainText(text);
}
+void EditorPage::PrepareToDestroy() {
+ if (readThread) {
+ readThread->requestInterruption();
+ readThread = nullptr;
+ }
+}
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/EditorPage.h b/src/ui/widgets/EditorPage.h
index 1a19134c..a0a05dab 100644
--- a/src/ui/widgets/EditorPage.h
+++ b/src/ui/widgets/EditorPage.h
@@ -84,13 +84,19 @@ class EditorPage : public QWidget {
*/
void closeNoteByClass(const char* className);
- void readFile();
+ void ReadFile();
+
+ [[nodiscard]] bool ReadDone() const { return this->readDone; }
+
+ void PrepareToDestroy();
private:
QTextEdit* textPage; /** The textedit of the tab */
QVBoxLayout* mainLayout; /** The layout for the tab */
QString fullFilePath; /** The path to the file handled in the tab */
bool signMarked{}; /** true, if the signed header is marked, false if not */
+ bool readDone = false;
+ QThread* readThread = nullptr;
private slots:
diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp
index bb026804..2c8df5e4 100644
--- a/src/ui/widgets/FilePage.cpp
+++ b/src/ui/widgets/FilePage.cpp
@@ -31,10 +31,8 @@
namespace GpgFrontend::UI {
FilePage::FilePage(QWidget* parent) : QWidget(parent) {
- qDebug() << "First Parent" << parent;
firstParent = parent;
-
- qDebug() << "New File Page";
+ LOG(INFO) << "New File Page";
dirModel = new QFileSystemModel();
dirModel->setRootPath(QDir::currentPath());
@@ -43,8 +41,9 @@ FilePage::FilePage(QWidget* parent) : QWidget(parent) {
dirTreeView->setModel(dirModel);
dirTreeView->setAnimated(true);
dirTreeView->setIndentation(20);
- dirTreeView->setRootIndex(dirModel->index(QDir::currentPath()));
dirTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
+ dirTreeView->setColumnWidth(0, 320);
+ dirTreeView->setRootIndex(dirModel->index(QDir::currentPath()));
mPath = boost::filesystem::path(dirModel->rootPath().toStdString());
createPopupMenu();
@@ -63,7 +62,7 @@ FilePage::FilePage(QWidget* parent) : QWidget(parent) {
upLevelButton->setIconSize(upPixmap.rect().size());
upLevelButton->setStyleSheet(buttonStyle);
- refreshButton = new QPushButton("Refresh");
+ refreshButton = new QPushButton(_("Refresh"));
connect(refreshButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath()));
goPathButton = new QPushButton();
@@ -107,7 +106,8 @@ FilePage::FilePage(QWidget* parent) : QWidget(parent) {
connect(dirTreeView, SIGNAL(customContextMenuRequested(const QPoint&)), this,
SLOT(onCustomContextMenu(const QPoint&)));
- emit pathChanged(mPath.c_str());
+ // refresh
+ slotGoPath();
}
void FilePage::fileTreeViewItemClicked(const QModelIndex& index) {
@@ -124,31 +124,33 @@ void FilePage::slotUpLevel() {
if (mPath.has_parent_path()) {
mPath = mPath.parent_path();
- auto fileInfo = QFileInfo(mPath.c_str());
+ auto fileInfo = QFileInfo(QString::fromStdString(mPath.string()));
if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
- pathEdit->setText(mPath.c_str());
+ pathEdit->setText(QString::fromStdString(mPath.string()));
slotGoPath();
}
LOG(INFO) << "Current Root mPath" << mPath;
- emit pathChanged(mPath.c_str());
+ emit pathChanged(QString::fromStdString(mPath.string()));
}
}
void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex& index) {
mPath = boost::filesystem::path(
dirModel->fileInfo(index).absoluteFilePath().toStdString());
- auto fileInfo = QFileInfo(mPath.c_str());
+ auto fileInfo = QFileInfo(QString::fromStdString(mPath.string()));
auto targetModelIndex =
dirTreeView->model()->index(index.row(), 0, index.parent());
if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
dirTreeView->setRootIndex(targetModelIndex);
- pathEdit->setText(mPath.c_str());
+ pathEdit->setText(QString::fromStdString(mPath.string()));
}
+ for (int i = 1; i < dirModel->columnCount(); ++i)
+ dirTreeView->resizeColumnToContents(i);
LOG(INFO) << "Index mPath" << mPath;
- emit pathChanged(mPath.c_str());
+ emit pathChanged(QString::fromStdString(mPath.string()));
}
-QString FilePage::getSelected() const { return selectedPath.c_str(); }
+QString FilePage::getSelected() const { return QString::fromStdString(selectedPath.string()); }
void FilePage::slotGoPath() {
qDebug() << "getSelected" << pathEdit->text();
@@ -157,11 +159,13 @@ void FilePage::slotGoPath() {
mPath = boost::filesystem::path(fileInfo.filePath().toStdString());
LOG(INFO) << "Set Path" << mPath;
dirTreeView->setRootIndex(dirModel->index(fileInfo.filePath()));
+ for (int i = 1; i < dirModel->columnCount(); ++i)
+ dirTreeView->resizeColumnToContents(i);
} else {
QMessageBox::critical(this, "Error",
"The path is unprivileged or unreachable.");
}
- emit pathChanged(mPath.c_str());
+ emit pathChanged(QString::fromStdString(mPath.string()));
}
void FilePage::createPopupMenu() {
@@ -195,7 +199,7 @@ void FilePage::onCustomContextMenu(const QPoint& point) {
dirModel->fileInfo(index).absoluteFilePath().toStdString());
LOG(INFO) << "FilePage::onCustomContextMenu Right Click" << selectedPath;
if (index.isValid()) {
- QFileInfo info(selectedPath.c_str());
+ QFileInfo info(QString::fromStdString(selectedPath.string()));
encryptItemAct->setEnabled(
info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig"));
decryptItemAct->setEnabled(info.isFile() && info.suffix() == "gpg");
@@ -209,7 +213,7 @@ void FilePage::onCustomContextMenu(const QPoint& point) {
}
void FilePage::slotOpenItem() {
- QFileInfo info(selectedPath.c_str());
+ QFileInfo info(QString::fromStdString(selectedPath.string()));
if (info.isDir()) {
LOG(INFO) << "FilePage::slotOpenItem getSelected"
<< pathEdit->text().toStdString();
diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp
index 528a4c88..8d4ea4a0 100644
--- a/src/ui/widgets/TextEdit.cpp
+++ b/src/ui/widgets/TextEdit.cpp
@@ -83,7 +83,7 @@ void TextEdit::slotOpenFile(QString& path) {
tabWidget->setCurrentIndex(tabWidget->count() - 1);
QApplication::restoreOverrideCursor();
page->getTextPage()->setFocus();
- page->readFile();
+ page->ReadFile();
} else {
QMessageBox::warning(this, _("Warning"),
(boost::format(_("Cannot read file %1%:\n%2%.")) %
@@ -250,7 +250,7 @@ bool TextEdit::maybeSaveCurrentTab(bool askToSave) {
}
QTextDocument* document = page->getTextPage()->document();
- if (document->isModified()) {
+ if (page->ReadDone() && document->isModified()) {
QMessageBox::StandardButton result = QMessageBox::Cancel;
// write title of tab to docname and remove the leading *
@@ -284,6 +284,9 @@ bool TextEdit::maybeSaveCurrentTab(bool askToSave) {
return false;
}
}
+
+ // destroy
+ page->PrepareToDestroy();
return true;
}
@@ -326,20 +329,16 @@ bool TextEdit::maybeSaveAnyTab() {
return false;
}
} else {
- bool allsaved = true;
+ bool all_saved = true;
QList<int> tabIdsToSave = dialog->getTabIdsToSave();
- foreach (int tabId, tabIdsToSave) {
+ for (const auto& tabId : tabIdsToSave) {
tabWidget->setCurrentIndex(tabId);
if (!maybeSaveCurrentTab(false)) {
- allsaved = false;
+ all_saved = false;
}
}
- if (allsaved) {
- return true;
- } else {
- return false;
- }
+ return all_saved;
}
}
// code should never reach this statement
@@ -489,11 +488,14 @@ QHash<int, QString> TextEdit::unsavedDocuments() const {
for (int i = 0; i < tabWidget->count(); i++) {
auto* ep = qobject_cast<EditorPage*>(tabWidget->widget(i));
- if (ep != nullptr && ep->getTextPage()->document()->isModified()) {
- QString docname = tabWidget->tabText(i);
+ if (ep != nullptr && ep->ReadDone() &&
+ ep->getTextPage()->document()->isModified()) {
+ QString doc_name = tabWidget->tabText(i);
+ LOG(INFO) << "unsaved" << doc_name.toStdString();
+
// remove * before name of modified doc
- docname.remove(0, 2);
- unsavedDocs.insert(i, docname);
+ doc_name.remove(0, 2);
+ unsavedDocs.insert(i, doc_name);
}
}
return unsavedDocs;
diff --git a/test/data/pv3.key b/test/data/pv3.key
index 6162ceef..616bc4d8 100644
--- a/test/data/pv3.key
+++ b/test/data/pv3.key
@@ -1,106 +1,106 @@
------BEGIN PGP PRIVATE KEY BLOCK-----
-
-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
-s68=
-=u5ok
------END PGP PRIVATE KEY BLOCK-----
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+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
+s68=
+=u5ok
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/test/data/pv4.key b/test/data/pv4.key
index 67edc9e1..8b79e893 100644
--- a/test/data/pv4.key
+++ b/test/data/pv4.key
@@ -1,82 +1,82 @@
------BEGIN PGP PRIVATE KEY BLOCK-----
-
-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
-T15m3mvre/E=
-=h5NI
------END PGP PRIVATE KEY BLOCK-----
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+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
+T15m3mvre/E=
+=h5NI
+-----END PGP PRIVATE KEY BLOCK-----