aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSaturn&Eric <[email protected]>2021-12-13 18:46:23 +0000
committerGitHub <[email protected]>2021-12-13 18:46:23 +0000
commit5d8e24b7ce4620164c3268b4f1de43a30df19a86 (patch)
tree6defd5d68468a95de980752ccf2c4ef8a0753617
parentCreate SECURITY.md (diff)
parentUpdate Translations & README. (diff)
downloadGpgFrontend-5d8e24b7ce4620164c3268b4f1de43a30df19a86.tar.gz
GpgFrontend-5d8e24b7ce4620164c3268b4f1de43a30df19a86.zip
Merge pull request #32 from saturneric/developv2.0.2
v2.0.2-beta.2
-rw-r--r--.github/workflows/debug.yml7
-rw-r--r--.github/workflows/release-ci.yml11
-rw-r--r--.github/workflows/release.yml3
-rw-r--r--CMakeLists.txt12
-rw-r--r--README.md79
-rw-r--r--README_CN.md186
-rw-r--r--gpgfrontend.qrc1
-rw-r--r--resource/icons/ssh-key.pngbin0 -> 6510 bytes
-rw-r--r--src/gpg/GpgConstants.cpp36
-rw-r--r--src/gpg/function/BasicOperator.cpp20
-rw-r--r--src/gpg/function/BasicOperator.h3
-rw-r--r--src/gpg/function/GpgFileOpera.cpp6
-rw-r--r--src/gpg/function/GpgKeyImportExportor.cpp28
-rw-r--r--src/gpg/function/GpgKeyImportExportor.h5
-rw-r--r--src/gpg/result_analyse/DecryptResultAnalyse.cpp3
-rw-r--r--src/main.cpp83
-rw-r--r--src/ui/CMakeLists.txt7
-rwxr-xr-xsrc/ui/KeyMgmt.cpp52
-rwxr-xr-xsrc/ui/KeyMgmt.h3
-rw-r--r--src/ui/MainWindow.cpp14
-rw-r--r--src/ui/MainWindow.h29
-rw-r--r--src/ui/keypair_details/KeyDetailsDialog.cpp6
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.cpp122
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.h5
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.cpp37
-rw-r--r--src/ui/keypair_details/KeyPairUIDTab.cpp4
-rw-r--r--src/ui/main_window/MainWindowFileSlotFunction.cpp60
-rw-r--r--src/ui/main_window/MainWindowSlotFunction.cpp76
-rw-r--r--src/ui/main_window/MainWindowUI.cpp31
-rw-r--r--src/ui/settings/SettingsGeneral.cpp5
-rw-r--r--src/ui/widgets/FilePage.cpp256
-rw-r--r--src/ui/widgets/FilePage.h18
-rw-r--r--src/ui/widgets/InfoBoardWidget.cpp134
-rw-r--r--src/ui/widgets/InfoBoardWidget.h31
-rw-r--r--src/ui/widgets/KeyList.cpp1
-rw-r--r--src/ui/widgets/TextEdit.cpp6
-rw-r--r--ui/FilePage.ui151
-rw-r--r--ui/InfoBoard.ui121
-rw-r--r--ui/KeyDeatils.ui48
-rw-r--r--ui/VerifyDetails.ui150
40 files changed, 1187 insertions, 663 deletions
diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml
index 2a0f6319..b88b607e 100644
--- a/.github/workflows/debug.yml
+++ b/.github/workflows/debug.yml
@@ -2,12 +2,13 @@ name: Debug Build & Package
on:
push:
- branches: [ develop ]
+ branches: [ develop, develop_ui ]
paths-ignore:
- '**/README.md'
- '**/README_CN.md'
- 'resource/ts/**'
- 'docs/**'
+ - '**.md'
pull_request:
branches: [ develop ]
paths-ignore:
@@ -15,6 +16,7 @@ on:
- '**/README_CN.md'
- 'resource/ts/**'
- 'docs/**'
+ - '**.md'
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
@@ -90,8 +92,9 @@ jobs:
- name: Set up Dependence (Windows)
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 mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake autoconf automake mingw-w64-x86_64-gpgme
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
+ pacman --noconfirm -S --needed mingw-w64-x86_64-qt5
if: matrix.os == 'windows-latest'
- name: Build gpg-error (Linux)
diff --git a/.github/workflows/release-ci.yml b/.github/workflows/release-ci.yml
index 92a12869..13e4b733 100644
--- a/.github/workflows/release-ci.yml
+++ b/.github/workflows/release-ci.yml
@@ -2,19 +2,21 @@ name: Build & Package CI Test
on:
push:
- branches: [develop-ci]
+ branches: [ develop-ci ]
paths-ignore:
- "**/README.md"
- "**/README_CN.md"
- "resource/ts/**"
- "docs/**"
+ - "**.md"
pull_request:
- branches: [develop-ci]
+ branches: [ develop-ci ]
paths-ignore:
- "**/README.md"
- "**/README_CN.md"
- "resource/ts/**"
- "docs/**"
+ - "**.md"
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
@@ -25,7 +27,7 @@ jobs:
build:
strategy:
matrix:
- os: ["ubuntu-18.04", "macos-10.15", "windows-latest"]
+ os: [ "ubuntu-18.04", "macos-10.15", "windows-latest" ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v2
@@ -92,8 +94,9 @@ jobs:
- name: Set up Dependence (Windows)
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 mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake autoconf automake mingw-w64-x86_64-gpgme
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
+ pacman --noconfirm -S --needed mingw-w64-x86_64-qt5
if: matrix.os == 'windows-latest'
- name: Build gpg-error (Linux)
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index c707ac2a..187b2399 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -93,8 +93,9 @@ jobs:
- name: Set up Dependence (Windows)
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 mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake autoconf automake mingw-w64-x86_64-gpgme
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
+ pacman --noconfirm -S --needed mingw-w64-x86_64-qt5
if: matrix.os == 'windows-latest'
- name: Build gpg-error (Linux)
diff --git a/CMakeLists.txt b/CMakeLists.txt
index c73e14ed..377f627c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
-project(GpgFrontend VERSION 2.0.1 LANGUAGES CXX)
+project(GpgFrontend VERSION 2.0.2 LANGUAGES CXX)
message(STATUS "GpgFrontend Build Configuration Started CMAKE Version ${CMAKE_VERSION}")
@@ -153,7 +153,6 @@ IF (MINGW)
set(Boost_USE_STATIC_LIBS ON)
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
-
include_directories(
${CMAKE_CURRENT_SOURCE_DIR}/src
${CMAKE_CURRENT_SOURCE_DIR}/third_party
@@ -162,7 +161,6 @@ IF (MINGW)
link_directories(
/mingw64/lib
)
-
endif ()
if (APPLE)
@@ -227,7 +225,6 @@ set(ESAY_LOGGING_PP 1)
if (FULL_APPLICATION_BUILD)
message(STATUS "Build Full Application")
set(QT5_ENV_SUPPORT 1)
- set(QT_MOC_CONFIG 1)
set(GPG_CORE 1)
set(UI_CORE 1)
set(SMTP_SUPPORT 1)
@@ -238,7 +235,6 @@ if (FULL_APPLICATION_BUILD)
set(MULTI_LANG_SUPPORT 1)
elseif (MINIMUM_APPLICATION_BUILD)
set(QT5_ENV_SUPPORT 1)
- set(QT_MOC_CONFIG 1)
set(GPG_CORE 1)
set(UI_CORE 1)
set(APPLICATION_BUILD 1)
@@ -250,7 +246,6 @@ elseif (MINIMUM_APPLICATION_BUILD)
# endif ()
elseif (STABLE_APPLICATION_BUILD)
set(QT5_ENV_SUPPORT 1)
- set(QT_MOC_CONFIG 1)
set(GPG_CORE 1)
set(UI_CORE 1)
set(APPLICATION_BUILD 1)
@@ -279,6 +274,11 @@ if (QT5_ENV_SUPPORT)
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
+
+ set(CMAKE_AUTORCC_OPTIONS "--compress;9")
+ set(CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS} ${CMAKE_SOURCE_DIR}/ui)
+ message(STATUS "CMAKE_AUTOUIC_SEARCH_PATHS ${CMAKE_AUTOUIC_SEARCH_PATHS}")
+
endif ()
diff --git a/README.md b/README.md
index 85ac643c..cc855d60 100644
--- a/README.md
+++ b/README.md
@@ -9,31 +9,29 @@
![GitHub release (latest by date)](https://img.shields.io/github/v/release/saturneric/gpgfrontend)
[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fsaturneric%2FGpgFrontend.svg?type=small)](https://app.fossa.com/projects/git%2Bgithub.com%2Fsaturneric%2FGpgFrontend?ref=badge_small)
-GpgFrontend is a Powerful, Easy-to-Use, Compact, Cross-Platform, and
-Installation-Free [OpenPGP](https://www.openpgp.org/)
+GpgFrontend is a Free, Open Source, Powerful, Easy-to-Use, Compact, Cross-Platform [OpenPGP](https://www.openpgp.org/)
Crypto Tool.
By using GpgFrontend, you can quickly encrypt and decrypt text or files. Or at the same time as the above operations,
you can add your own signature to let others know that this document or this paragraph of text was issued by you.
Please **take the initiative to protect privacy in your own hands**, instead of relying on servers and algorithms
-provided by large companies.
+provided by large companies. Please use this tool to transmit or store information that you regard as very precious. You
+can also use it to securely guarantee the authenticity of your information.
-**Notice:** GpgFrontend does not provide an embedded [gnupg](https://gnupg.org/) binary library and needs to be
-installed by the user. **This is to ensure safety and avoid code or binary files involved in encryption and decryption
-being implanted in the backdoor during the delivery process.**
+GpgFrontned [supports languages](#languages-support) that are widely used in most countries and regions around the
+world, including English, Chinese, French, Russian, German, Spanish, Portuguese, Arabic, etc.
+
+**Notice:** GpgFrontend does not provide an embedded [gnupg](https://gnupg.org/) (gpg) binary and needs to be installed
+by the user. **This is to ensure safety and avoid code or binary files involved in encryption and decryption being
+implanted in the backdoor during the delivery process.**
If you find this tool useful and promising, welcome to encourage me through STAR this project. Thanks!
[>> Quick Start <<](#quick-start) |
-[>> Code & Binary Security <<](https://gpgfrontend.pub/#/about/code-binary-verify) |
-[>> 简中README <<](https://github.com/saturneric/GpgFrontend/blob/main/README_CN.md)
+[>> Code & Binary Security <<](https://gpgfrontend.pub/#/about/code-binary-verify)
<div align="center">
-<img width="640" src="https://github.com/saturneric/Blob/blob/master/screenshots/main_mac.jpg?raw=true" alt="macOS Screenshot"/>
-</div>
-<div align="center">
-<img width="320" src="https://github.com/saturneric/Blob/blob/master/screenshots/key_info.PNG?raw=true" alt="Windows Screenshot"/>
-<img width="320" src="https://github.com/saturneric/Blob/blob/master/screenshots/keygen_ubuntu.png?raw=true" alt="Ubuntu Screenshot"/>
+<img src="https://github.com/saturneric/Blob/blob/master/screenshots/main-ubuntu.png?raw=true" alt="Ubuntu Main Screenshot"/>
</div>
#### Workflows Status:
@@ -44,7 +42,6 @@ If you find this tool useful and promising, welcome to encourage me through STAR
## Table of Contents
-- [Features](#features)
- [Usage](#usage)
- [Quick Start](#quick-start)
- [How to Run it](#how-to-run-it)
@@ -60,13 +57,6 @@ If you find this tool useful and promising, welcome to encourage me through STAR
- [Maintainers](#maintainers)
- [Licenses](#LICENSES)
-## Features
-
-- Can run on **Windows, Linux and macOS**.
-- Open source, free, no need to install.
-- Just double-click, and then you can use it freely.
-- Supports multiple [languages](#languages-support).
-
## Usage
### Quick Start
@@ -75,13 +65,13 @@ If you find this tool useful and promising, welcome to encourage me through STAR
Encryption can be done in just a few clicks.
-![GIF](https://github.com/saturneric/Blob/blob/master/gif/encrypt.gif?raw=true)
+![GIF](https://github.com/saturneric/Blob/blob/master/gif/encrypt-sign.gif?raw=true)
### Fast Text Decryption
I want to see what you wrote right away.
-![GIF](https://github.com/saturneric/Blob/blob/master/gif/decrypt.gif?raw=true)
+![GIF](https://github.com/saturneric/Blob/blob/master/gif/decrypt-verify.gif?raw=true)
### Fast File Encryption & Sign
@@ -95,7 +85,7 @@ Read the animated pictures in the [Document](https://gpgfrontend.pub/#/quick-sta
### How to Run it
-#### Windows
+#### Windows (No Setup)
0. If you haven't installed gnupg,
please [Download](https://gnupg.org/ftp/gcrypt/binary/gnupg-w32-2.3.1_20210420.exe) `gnupg-w32-******.exe` and
@@ -104,9 +94,17 @@ Read the animated pictures in the [Document](https://gpgfrontend.pub/#/quick-sta
2. Unzip `gpgfrontend-windows-latest-*******.zip`
3. Go into the directory and double click `GpgFrontend.exe`.
+#### Windows (Setup)
+
+0. Double click `GpgFrontend-...-Setup.exe`.
+1. Use GpgFrontend.
+
#### macOS
0. If command `gpg` is not available, please use homebrew to install it first.
+ ```shell
+ $ sudo brew install gpg
+ ```
1. [Download GpgFrontend](https://github.com/saturneric/GpgFrontend/releases) macOS edition from the latest release
2. Double-Click GpgFrontend.dmg to load it
3. Double click and run it
@@ -132,11 +130,11 @@ Read the animated pictures in the [Document](https://gpgfrontend.pub/#/quick-sta
```shell
$ chmod u+x ./GpgFrontend-***.AppImage
```
-3. Just double-click `GpgFrontend-***.AppImage` to run it.
+3. Just double-click `GpgFrontend-***.AppImage` to run it. (If you installed AppImage Launcher, it's better.)
## Document
-for more usage information, please read [document](https://gpgfrontend.pub/#/overview).
+For more usage information, please read [document](https://gpgfrontend.pub/#/overview).
## Purpose
@@ -162,17 +160,14 @@ The supported languages are listed here. Some languages use machine translation
to join translation and verification work, please refer to
the [translate the interface](https://gpgfrontend.pub/#/translate-interface).
-Notice: The verification may not be complete and rigorous.
+### Supported Languages
-| Language | English | 简体中文 | français | Французский | Español |
-| ---- | ---- | ---- | ---- | ---- | ---- |
-| Support | Support | 支持 | Etre prêt | ожидать | apoyar |
-| Verification | Origin | 不完全 | Jamais |Никогда | Nunca |
+'zh_CN', 'es_ES', 'zh_TW', 'zh_HK', 'fr_FR', 'de_DE', 'pl_PL', 'ru_RU', 'ja_JP', 'it_IT',
+'ko_KR', 'pt_BR', 'ar_SA', 'ar_IQ', 'hi_IN', 'af_ZA', 'sq_AL', 'be_BY', 'bg_BG', 'ca_ES',
+'hr_HR', 'cs_CZ', 'da_DK', 'nl_NL', 'et_EE', 'fa_IR', 'fi_FI', 'fr_CA', 'he_IL', 'id_ID',
+'lt_LT', 'De_AT', 'De_CH', 'El_GR', 'Es_MX', 'Iw_IL', 'UK_UA'
-| Language | 日本語 | 繁體中文 | عربى | português |
-| ---- | ---- | ---- | ---- | ---- |
-| Support | 未だに | 尚未 | ليس بعد | Ainda não |
-| Verification | | | | |
+Notice: The verification may not be complete and rigorous.
## Contract
@@ -201,19 +196,21 @@ GpgFrontend itself is licensed under the [GPLv3](COPYING).
There are some libraries and binary included in the zip-file which (may) have different licenses, for more information
check their homepages. You can also obtain the sources from there.
-gnupg: https://gnupg.org/
+gnupg: https://gnupg.org
+
+gpgme: https://gnupg.org/software/gpgme/index.html
-gpg4usb: https://www.gpg4usb.org/
+gpg4usb: https://www.gpg4usb.org
-QT 5.15.2(opensource): https://www.qt.io/
+QT 5.15.2(opensource): https://www.qt.io
-MSYS2: https://www.msys2.org/
+MSYS2: https://www.msys2.org
mingw-w64: http://mingw-w64.org/doku.php
-AppImage: https://appimage.org/
+AppImage: https://appimage.org
-rapidjson: https://github.com/Tencent/rapidjson
+JSON for Modern C++: https://github.com/nlohmann/json
Application
Bundles: [Link](https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1)
diff --git a/README_CN.md b/README_CN.md
deleted file mode 100644
index e86a62e3..00000000
--- a/README_CN.md
+++ /dev/null
@@ -1,186 +0,0 @@
-<img width="100" height="100" align="right" src="https://github.com/saturneric/Blob/blob/master/logos/icon.png?raw=true" alt="ICON"/>
-
-# GpgFrontend
-
-![Language](https://img.shields.io/badge/language-C%2B%2B-green)
-![License](https://img.shields.io/badge/License-GPL--3.0-orange)
-![CodeSize](https://img.shields.io/github/languages/code-size/saturneric/GpgFrontend)
-[![Codacy Badge](https://app.codacy.com/project/badge/Grade/d1750e052a85430a8f1f84e58a0fceda)](https://www.codacy.com/gh/saturneric/GpgFrontend/dashboard?utm_source=github.com&utm_medium=referral&utm_content=saturneric/GpgFrontend&utm_campaign=Badge_Grade)
-![GitHub release (latest by date)](https://img.shields.io/github/v/release/saturneric/gpgfrontend)
-[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fsaturneric%2FGpgFrontend.svg?type=small)](https://app.fossa.com/projects/git%2Bgithub.com%2Fsaturneric%2FGpgFrontend?ref=badge_small)
-
-GpgFrontend 是一个易于使用、小巧、跨平台和免安装的 [OpenPGP](https://www.openpgp.org/) 加密解密签名工具。
-
-通过使用 GpgFrontend,你可以快速加密和解密文本或文件。或者在进行上述操作的同时加上自己的签名,让别人知道这个文件或者这段文字是出自你之手。 请将隐私保护的主动权掌握在自己手上,而不是依赖大公司提供的服务器和算法。
-
-注意:GpgFrontend 不提供嵌入式 gnupg 二进制库,需要用户自行安装。这是为了确保安全,避免涉及加密解密的代码或二进制文件在传递过程中被植入后门。
-
-如果你觉得这款工具有用或者有希望,`欢迎通过STAR这个项目来鼓励我`。
-
-[>> 快速开始](#quick-start)
-
-[>> 代码与二进制文件安全](https://gpgfrontend.pub/#/about/code-binary-verify)
-
-<div align="center">
-<img width="640" src="https://github.com/saturneric/Blob/blob/master/screenshots/main_mac.jpg?raw=true" alt="macOS Screenshot"/>
-</div>
-<div align="center">
-<img width="320" src="https://github.com/saturneric/Blob/blob/master/screenshots/key_info.PNG?raw=true" alt="Windows Screenshot"/>
-<img width="320" src="https://github.com/saturneric/Blob/blob/master/screenshots/keygen_ubuntu.png?raw=true" alt="Ubuntu Screenshot"/>
-</div>
-
-#### Workflows 状态:
-
-[![Build & Package](https://github.com/saturneric/GpgFrontend/actions/workflows/release.yml/badge.svg?branch=main)](https://github.com/saturneric/GpgFrontend/actions/workflows/cmake.yml)
-
----
-
-## 内容目录
-
-- [软件特性](#软件特性)
-- [使用方法](#使用方法)
- - [快速开始](#快速开始)
- - [如何安装](#如何安装)
- - [Windows](#windows)
- - [macOS](#macos)
- - [Debian/Ubuntu/CentOS](#debianubuntucentos)
-- [文档](#文档)
-- [开发宗旨](#开发宗旨)
-- [构建方法](#构建方法)
-- [联系](#联系)
- - [做出贡献或者报告问题](#做出贡献或者报告问题)
- - [关于维护者](#关于维护者)
-- [许可证](#许可证)
-
-## 软件特性
-
-- 可以在 Windows、Linux 和 macOS 上运行。
-- 开源,免费,无需安装。
-- 只需双击即可自由使用。
-- 支持多种语言。
- - 有兴趣的可以帮我 [翻译一下界面](https://gpgfrontend.pub/#/translate-interface) 。
-
-## 使用方法
-
-### 快速开始
-
-### 快速加密
-
-只需单击几下即可完成加密。
-
-![GIF](https://github.com/saturneric/Blob/blob/master/gif/encrypt.gif?raw=true)
-
-### 快速解密
-
-我想马上看看对方写了什么。
-
-![GIF](https://github.com/saturneric/Blob/blob/master/gif/decrypt.gif?raw=true)
-
-### 快速文件加密与签名
-
-对于文件,我该怎么做?
-
-![GIF](https://github.com/saturneric/Blob/blob/master/gif/encr-sign-file.gif?raw=true)
-
-### 还有那些有用的操作
-
-阅读 [文档](https://gpgfrontend.pub/#/quick-start) 中的动图,了解更多精彩操作。
-
-### 如何安装
-
-#### Windows
-
-0. 如果你还没有安装gnupg,请 [下载](https://gnupg.org/ftp/gcrypt/binary/gnupg-w32-2.3.1_20210420.exe) gnupg-w32-**\*\***.exe 并双击安装
-1. [下载 GpgFrontend](https://github.com/saturneric/GpgFrontend/releases) Windows Edition from release
-2. 解压 gpgfrontend-windows-latest-**\*\*\***.zip
-3. 进入目录,双击运行 GpgFrontend.exe
-
-#### macOS
-
-0. 如果命令 `gpg` 不可用,请先用 Homebrew 安装它.
-1. [下载 GpgFrontend](https://github.com/saturneric/GpgFrontend/releases) macOS edition from release
-2. 双击并加载 GpgFrontend-***.dmg
-3. 双击并运行
- (由于 macOS 的安全策略,在真正能运行前请遵照系统说明).
-4. 如果你满意的话,可以将本软件复制到 Application 文件夹.
-
-#### Debian/Ubuntu/CentOS
-
-1. 安装 gnupg (如果你已经安装了请跳过)
- - For Debian/Ubuntu
- ```shell
- $ sudo apt update
- $ sudo apt install gpg
- ```
- - For CentOS
- ```shell
- $ sudo yum install gnupg
- ```
-2. [下载 GpgFrontend](https://github.com/saturneric/GpgFrontend/releases) Linux edition from the latest release
-3. 赋予 `GpgFrontend-***.AppImage` 执行权限
- ```shell
- $ chmod u+x ./GpgFrontend-***.AppImage
- ```
-4. 双击运行 `GpgFrontend-***.AppImage`.
-
-## 文档
-
-如果你想获取更多信息,请阅读 [文档](https://gpgfrontend.pub/#/overview).
-
-## 开发宗旨
-
-GpgFrontend 项目继承自一个相对成熟但未维护的 [gpg4usb](https://www.gpg4usb.org/) 项目。 它继承了 gpg4usb 稳定、易用、小巧、免安装的特点。
-
-GpgFrontend 未来会增加更多功能,提高 GPG 在端到端传输中的易用性并缩短密文长度。同时,新功能的加入不影响旧的基础功能。 我个人的力量总是有限的。 GpgFrontend 欢迎志愿者加入。你可以使用 GitHub
-平台提交问题或提交 pull request。
-
-GpgFrontend 项目作为开源项目,也坚持使用开源代码和库。
-
-## 构建方法
-
-构建软件的教程将很快发布。你可以先查看本项目的 GitHub Action 文件。
-
-## 联系
-
-如果你想与我私下联系,你可以发送电子邮件到 [[email protected]](mailto:[email protected])。
-
-### 做出贡献或者报告问题
-
-欢迎!你可以通过 [提出 issue](https://github.com/saturneric/GpgFrontend/issues/new) 或提交 PR 来做出贡献。
-
-### 关于维护者
-
-该项目的维护者是 [@Saturneric](https://github.com/saturneric).
-
-## LOGO
-
-![logo](https://github.com/saturneric/Blob/blob/master/logos/gpgfrontend-logo.jpg?raw=true)
-
-## 许可证
-
-GpgFrontend 在 [GPLv3](COPYING) 许可证下。
-
-[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fsaturneric%2FGpgFrontend.svg?type=large)](https://app.fossa.com/projects/git%2Bgithub.com%2Fsaturneric%2FGpgFrontend?ref=badge_large)
-
-### 依赖
-
-项目使用到了一些库和二进制文件,它们(可能)具有不同的许可证,请查看它们的主页获取更多信息。您也可以从那里获取相关信息。
-
-gnupg: https://gnupg.org/
-
-gpg4usb: https://www.gpg4usb.org/
-
-QT 5.15.2(opensource): https://www.qt.io/
-
-MSYS2: https://www.msys2.org/
-
-mingw-w64: http://mingw-w64.org/doku.php
-
-AppImage: https://appimage.org/
-
-rapidjson: https://github.com/Tencent/rapidjson
-
-Application
-Bundles: [Link](!https://developer.apple.com/library/archive/documentation/CoreFoundation/Conceptual/CFBundles/BundleTypes/BundleTypes.html#//apple_ref/doc/uid/10000123i-CH101-SW1)
-
-本软件图标使用来自 [阿里巴巴矢量图标库](!https://www.iconfont.cn/) 的素材。免费库中的图标未注册为商标。不涉及版权问题。
diff --git a/gpgfrontend.qrc b/gpgfrontend.qrc
index 1f8953a6..c2589b83 100644
--- a/gpgfrontend.qrc
+++ b/gpgfrontend.qrc
@@ -47,6 +47,7 @@
<file alias="misc_doc.png">resource/icons/misc_doc.png</file>
<file alias="quote.png">resource/icons/quote.png</file>
<file alias="signature.png">resource/icons/signature.png</file>
+ <file alias="ssh-key.png">resource/icons/ssh-key.png</file>
<file alias="statusbar_icon.png">resource/icons/statusbar_icon.png</file>
<file alias="txt.png">resource/icons/txt.png</file>
<file alias="undo.png">resource/icons/undo.png</file>
diff --git a/resource/icons/ssh-key.png b/resource/icons/ssh-key.png
new file mode 100644
index 00000000..c3563e43
--- /dev/null
+++ b/resource/icons/ssh-key.png
Binary files differ
diff --git a/src/gpg/GpgConstants.cpp b/src/gpg/GpgConstants.cpp
index e3de1d06..2454daa2 100644
--- a/src/gpg/GpgConstants.cpp
+++ b/src/gpg/GpgConstants.cpp
@@ -28,6 +28,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/filesystem.hpp>
+#include <string>
const char* GpgFrontend::GpgConstants::PGP_CRYPT_BEGIN =
"-----BEGIN PGP MESSAGE-----";
@@ -110,16 +111,17 @@ static inline std::string trim(std::string& s) {
return s;
}
-std::string GpgFrontend::read_all_data_in_file(const std::string& path) {
+std::string GpgFrontend::read_all_data_in_file(const std::string& utf8_path) {
using namespace boost::filesystem;
- class path file_info(path.c_str());
-
- if (!exists(file_info) || !is_regular_file(path))
- throw std::runtime_error("no permission");
-
+ class path file_info(utf8_path.c_str());
+ if (!exists(file_info) || !is_regular_file(file_info)) return {};
std::ifstream in_file;
- in_file.open(path, std::ios::in);
- if (!in_file.good()) throw std::runtime_error("cannot open file");
+#ifndef WINDOWS
+ in_file.open(file_info.string(), std::ios::in);
+#else
+ in_file.open(file_info.wstring().c_str(), std::ios::in);
+#endif
+ if (!in_file.good()) return {};
std::istreambuf_iterator<char> begin(in_file);
std::istreambuf_iterator<char> end;
std::string in_buffer(begin, end);
@@ -127,9 +129,16 @@ std::string GpgFrontend::read_all_data_in_file(const std::string& path) {
return in_buffer;
}
-bool GpgFrontend::write_buffer_to_file(const std::string& path,
+bool GpgFrontend::write_buffer_to_file(const std::string& utf8_path,
const std::string& out_buffer) {
- std::ofstream out_file(boost::filesystem::path(path).string(), std::ios::out);
+ using namespace boost::filesystem;
+ class path file_info(utf8_path.c_str());
+#ifndef WINDOWS
+ std::ofstream out_file(file_info.string(), std::ios::out | std::ios::trunc);
+#else
+ std::ofstream out_file(file_info.wstring().c_str(),
+ std::ios::out | std::ios::trunc);
+#endif
if (!out_file.good()) return false;
out_file.write(out_buffer.c_str(), out_buffer.size());
out_file.close();
@@ -137,8 +146,9 @@ 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
+ // Create a path object from given string
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
@@ -149,7 +159,7 @@ 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
+ // Create a path object from given string
boost::filesystem::path path_obj(path);
// Check if file name in the path object has extension
if (path_obj.has_filename()) {
@@ -157,7 +167,7 @@ std::string GpgFrontend::get_only_file_name_with_path(const std::string& path) {
return (path_obj.parent_path() / path_obj.stem()).string();
}
// In case of no extension return empty string
- throw std::runtime_error("invalid file path");
+ return {};
}
/*
diff --git a/src/gpg/function/BasicOperator.cpp b/src/gpg/function/BasicOperator.cpp
index 912119e2..5f6ffb85 100644
--- a/src/gpg/function/BasicOperator.cpp
+++ b/src/gpg/function/BasicOperator.cpp
@@ -76,13 +76,15 @@ GpgFrontend::GpgError GpgFrontend::BasicOperator::Verify(
GpgVerifyResult& result) const {
gpgme_error_t err;
+ LOG(INFO) << "in buffer size" << in_buffer.size();
GpgData data_in(in_buffer.data(), in_buffer.size());
+ GpgData data_out;
if (sig_buffer != nullptr) {
GpgData sig_data(sig_buffer->data(), sig_buffer->size());
err = check_gpg_error(gpgme_op_verify(ctx, sig_data, data_in, nullptr));
} else
- err = check_gpg_error(gpgme_op_verify(ctx, data_in, nullptr, data_in));
+ err = check_gpg_error(gpgme_op_verify(ctx, data_in, nullptr, data_out));
auto temp_result = GpgVerifyResult(gpgme_op_verify_result(ctx));
std::swap(result, temp_result);
@@ -204,3 +206,19 @@ GpgFrontend::BasicOperator::GetSigners() {
}
return signers;
}
+gpg_error_t GpgFrontend::BasicOperator::EncryptSymmetric(
+ GpgFrontend::ByteArray& in_buffer, GpgFrontend::ByteArrayPtr& out_buffer,
+ GpgFrontend::GpgEncrResult& result) {
+ GpgData data_in(in_buffer.data(), in_buffer.size()), data_out;
+
+ gpgme_error_t err = check_gpg_error(gpgme_op_encrypt(
+ ctx, nullptr, GPGME_ENCRYPT_SYMMETRIC, data_in, data_out));
+
+ auto temp_data_out = data_out.Read2Buffer();
+ std::swap(temp_data_out, out_buffer);
+
+ auto temp_result = GpgEncrResult(gpgme_op_encrypt_result(ctx));
+ std::swap(result, temp_result);
+
+ return err;
+}
diff --git a/src/gpg/function/BasicOperator.h b/src/gpg/function/BasicOperator.h
index 39f93668..4ea70eea 100644
--- a/src/gpg/function/BasicOperator.h
+++ b/src/gpg/function/BasicOperator.h
@@ -37,6 +37,9 @@ class BasicOperator : public SingletonFunctionObject<BasicOperator> {
gpg_error_t Encrypt(KeyListPtr keys, BypeArrayRef in_buffer,
ByteArrayPtr& out_buffer, GpgEncrResult& result);
+ gpg_error_t EncryptSymmetric(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer,
+ GpgEncrResult& result);
+
gpgme_error_t EncryptSign(KeyListPtr keys, KeyListPtr signers,
BypeArrayRef in_buffer, ByteArrayPtr& out_buffer,
GpgEncrResult& encr_result,
diff --git a/src/gpg/function/GpgFileOpera.cpp b/src/gpg/function/GpgFileOpera.cpp
index c3f75cf8..42b37c71 100644
--- a/src/gpg/function/GpgFileOpera.cpp
+++ b/src/gpg/function/GpgFileOpera.cpp
@@ -41,7 +41,7 @@ GpgFrontend::GpgError GpgFrontend::GpgFileOpera::EncryptFile(
if (!write_buffer_to_file(path + ".asc", *out_buffer)) {
throw std::runtime_error("write_buffer_to_file error");
};
-
+
return err;
}
@@ -94,7 +94,6 @@ gpgme_error_t GpgFrontend::GpgFileOpera::VerifyFile(const std::string& path,
if (get_file_extension(path) == ".gpg") {
auto err =
BasicOperator::GetInstance().Verify(in_buffer, sign_buffer, result);
- assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
return err;
} else {
sign_buffer =
@@ -150,8 +149,7 @@ gpg_error_t GpgFrontend::GpgFileOpera::DecryptVerifyFile(
if (!(file_extension == ".asc" || file_extension == ".gpg"))
out_file_name = path + ".out";
- LOG(INFO) << "GpgFrontend::GpgFileOpera::DecryptVerifyFile out_file_name"
- << out_file_name;
+ LOG(INFO) << "out_file_name" << out_file_name;
if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
if (!write_buffer_to_file(out_file_name, *out_buffer)) {
diff --git a/src/gpg/function/GpgKeyImportExportor.cpp b/src/gpg/function/GpgKeyImportExportor.cpp
index d8812839..89d3b002 100644
--- a/src/gpg/function/GpgKeyImportExportor.cpp
+++ b/src/gpg/function/GpgKeyImportExportor.cpp
@@ -130,3 +130,31 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKey(
std::swap(out_buffer, temp_out_buffer);
return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
}
+
+bool GpgFrontend::GpgKeyImportExportor::ExportKeyOpenSSH(
+ const GpgFrontend::GpgKey& key,
+ GpgFrontend::ByteArrayPtr& out_buffer) const {
+ GpgData data_out;
+ auto err =
+ gpgme_op_export(ctx, key.id().c_str(), GPGME_EXPORT_MODE_SSH, data_out);
+
+ DLOG(INFO) << "read_bytes" << gpgme_data_seek(data_out, 0, SEEK_END);
+
+ auto temp_out_buffer = data_out.Read2Buffer();
+ std::swap(out_buffer, temp_out_buffer);
+ return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
+}
+
+bool GpgFrontend::GpgKeyImportExportor::ExportSecretKeyShortest(
+ const GpgFrontend::GpgKey& key,
+ GpgFrontend::ByteArrayPtr& out_buffer) const {
+ GpgData data_out;
+ auto err = gpgme_op_export(ctx, key.id().c_str(), GPGME_EXPORT_MODE_MINIMAL,
+ data_out);
+
+ DLOG(INFO) << "read_bytes" << gpgme_data_seek(data_out, 0, SEEK_END);
+
+ auto temp_out_buffer = data_out.Read2Buffer();
+ std::swap(out_buffer, temp_out_buffer);
+ return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
+}
diff --git a/src/gpg/function/GpgKeyImportExportor.h b/src/gpg/function/GpgKeyImportExportor.h
index 35a237ba..ad43d539 100644
--- a/src/gpg/function/GpgKeyImportExportor.h
+++ b/src/gpg/function/GpgKeyImportExportor.h
@@ -90,8 +90,13 @@ class GpgKeyImportExportor
bool ExportKey(const GpgKey& key, ByteArrayPtr& out_buffer) const;
+ bool ExportKeyOpenSSH(const GpgKey& key, ByteArrayPtr& out_buffer) const;
+
bool ExportSecretKey(const GpgKey& key, ByteArrayPtr& outBuffer) const;
+ bool ExportSecretKeyShortest(const GpgKey& key,
+ ByteArrayPtr& outBuffer) const;
+
private:
GpgContext& ctx =
GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel());
diff --git a/src/gpg/result_analyse/DecryptResultAnalyse.cpp b/src/gpg/result_analyse/DecryptResultAnalyse.cpp
index 4ff32c59..f7fc70fe 100644
--- a/src/gpg/result_analyse/DecryptResultAnalyse.cpp
+++ b/src/gpg/result_analyse/DecryptResultAnalyse.cpp
@@ -51,6 +51,9 @@ void GpgFrontend::DecryptResultAnalyse::do_analyse() {
stream << _("File Name") << ": " << result->file_name << std::endl;
stream << std::endl;
}
+ if (result->is_mime) {
+ stream << _("MIME") << ": " << _("true") << std::endl;
+ }
auto reci = result->recipients;
if (reci != nullptr) stream << _("Recipient(s)") << ": " << std::endl;
diff --git a/src/main.cpp b/src/main.cpp
index 1dbf1d5e..5faf34a9 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -25,7 +25,9 @@
#include <cstdlib>
#include "GpgFrontendBuildInfo.h"
+#include "gpg/GpgContext.h"
#include "ui/MainWindow.h"
+#include "ui/WaitingDialog.h"
#include "ui/settings/GlobalSettingStation.h"
// Easy Logging Cpp
@@ -40,7 +42,10 @@ int main(int argc, char* argv[]) {
// Qt App
QApplication app(argc, argv);
+
+#ifndef MACOS
QApplication::setWindowIcon(QIcon(":gpgfrontend.png"));
+#endif
#ifdef MACOS
// support retina screen
@@ -60,7 +65,7 @@ int main(int argc, char* argv[]) {
// unicode in source
QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));
-#if !defined(RELEASE)
+#if !defined(RELEASE) && defined(WINDOWS)
// css
QFile file(RESOURCE_DIR(qApp->applicationDirPath()) + "/css/default.qss");
file.open(QFile::ReadOnly);
@@ -69,6 +74,54 @@ int main(int argc, char* argv[]) {
file.close();
#endif
+ auto* init_ctx_thread = QThread::create([]() {
+ // Create & Check Gnupg Context Status
+ if (!GpgFrontend::GpgContext::GetInstance().good()) {
+ QMessageBox::critical(
+ nullptr, _("ENV Loading Failed"),
+ _("Gnupg(gpg) is not installed correctly, please follow the "
+ "ReadME "
+ "instructions in Github to install Gnupg and then open "
+ "GpgFrontend."));
+ QCoreApplication::quit();
+ exit(0);
+ }
+ });
+
+ QApplication::connect(init_ctx_thread, &QThread::finished, init_ctx_thread,
+ &QThread::deleteLater);
+
+ init_ctx_thread->start();
+
+ // Waiting Dialog
+ auto* waiting_dialog = new QProgressDialog();
+ waiting_dialog->setMaximum(0);
+ waiting_dialog->setMinimum(0);
+ auto waiting_dialog_label =
+ new QLabel(QString(_("Loading Gnupg Info...")) + "<br /><br />" +
+ _("If this process is too slow, please set the key "
+ "server address appropriately in the gnupg configuration "
+ "file (depending "
+ "on the network situation in your country or region)."));
+ waiting_dialog_label->setWordWrap(true);
+ waiting_dialog->setLabel(waiting_dialog_label);
+ waiting_dialog->resize(420, 120);
+ QApplication::connect(waiting_dialog, &QProgressDialog::canceled, [=]() {
+ LOG(INFO) << "cancel clicked";
+ init_ctx_thread->terminate();
+ QCoreApplication::quit();
+ exit(0);
+ });
+
+ // Show Waiting Dialog
+ waiting_dialog->show();
+ waiting_dialog->setFocus();
+ while (init_ctx_thread->isRunning()) {
+ QApplication::processEvents();
+ }
+ waiting_dialog->finished(0);
+ waiting_dialog->deleteLater();
+
/**
* internationalisation. loop to restart main window
* with changed translation when settings change.
@@ -76,16 +129,24 @@ int main(int argc, char* argv[]) {
int return_from_event_loop_code;
do {
- // i18n
- init_locale();
-
- QApplication::setQuitOnLastWindowClosed(true);
-
- auto main_window = std::make_unique<GpgFrontend::UI::MainWindow>();
- main_window->init();
- main_window->show();
- return_from_event_loop_code = QApplication::exec();
-
+ try {
+ // i18n
+ init_locale();
+
+ QApplication::setQuitOnLastWindowClosed(true);
+
+ auto main_window = std::make_unique<GpgFrontend::UI::MainWindow>();
+ main_window->init();
+ main_window->show();
+ return_from_event_loop_code = QApplication::exec();
+
+ } catch (...) {
+ QMessageBox::information(nullptr, _("Unhandled Exception Thrown"),
+ _("Oops, an unhandled exception was thrown "
+ "during the running of the "
+ "program, and now it needs to be restarted."));
+ continue;
+ }
} while (return_from_event_loop_code == RESTART_CODE);
return return_from_event_loop_code;
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index f4b00d22..7c6bf732 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -13,10 +13,11 @@ if (SMTP_SUPPORT)
aux_source_directory(./smtp UI_SOURCE)
endif ()
-
add_library(gpgfrontend-ui STATIC ${UI_SOURCE})
-
-target_link_libraries(gpgfrontend-ui
+set(GPGFRONTEND_UI_LIB_NAME gpgfrontend-ui)
+target_link_libraries(${GPGFRONTEND_UI_LIB_NAME}
Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core)
+target_include_directories(gpgfrontend-ui PUBLIC
+ ${CMAKE_CURRENT_BINARY_DIR}/${GPGFRONTEND_UI_LIB_NAME}_autogen/include)
target_compile_features(gpgfrontend-ui PUBLIC cxx_std_17) \ No newline at end of file
diff --git a/src/ui/KeyMgmt.cpp b/src/ui/KeyMgmt.cpp
index aa6df120..f28e6587 100755
--- a/src/ui/KeyMgmt.cpp
+++ b/src/ui/KeyMgmt.cpp
@@ -207,6 +207,13 @@ void KeyMgmt::createActions() {
connect(exportKeyToFileAct, SIGNAL(triggered()), this,
SLOT(slotExportKeyToFile()));
+ exportKeyAsOpenSSHFormat = new QAction(_("Export As OpenSSH"), this);
+ exportKeyAsOpenSSHFormat->setIcon(QIcon(":ssh-key.png"));
+ exportKeyAsOpenSSHFormat->setToolTip(
+ _("Export Selected Key(s) As OpenSSH Format to File"));
+ connect(exportKeyAsOpenSSHFormat, SIGNAL(triggered()), this,
+ SLOT(slotExportAsOpenSSHFormat()));
+
deleteSelectedKeysAct = new QAction(_("Delete Selected Key(s)"), this);
deleteSelectedKeysAct->setToolTip(_("Delete the Selected keys"));
connect(deleteSelectedKeysAct, SIGNAL(triggered()), this,
@@ -240,6 +247,7 @@ void KeyMgmt::createMenus() {
importKeyMenu->addAction(importKeyFromKeyServerAct);
keyMenu->addAction(exportKeyToFileAct);
keyMenu->addAction(exportKeyToClipboardAct);
+ keyMenu->addAction(exportKeyAsOpenSSHFormat);
keyMenu->addSeparator();
keyMenu->addAction(deleteCheckedKeysAct);
}
@@ -273,6 +281,7 @@ void KeyMgmt::createToolBars() {
keyToolBar->addSeparator();
keyToolBar->addAction(exportKeyToFileAct);
keyToolBar->addAction(exportKeyToClipboardAct);
+ keyToolBar->addAction(exportKeyAsOpenSSHFormat);
}
void KeyMgmt::slotDeleteSelectedKeys() {
@@ -446,4 +455,47 @@ void KeyMgmt::slotSaveWindowState() {
GlobalSettingStation::GetInstance().Sync();
}
+void KeyMgmt::slotExportAsOpenSSHFormat() {
+ ByteArrayPtr key_export_data = nullptr;
+ auto keys_checked = mKeyList->getChecked();
+
+ if (keys_checked->empty()) {
+ QMessageBox::critical(nullptr, _("Error"), _("No Key Checked."));
+ return;
+ }
+
+ auto key = GpgKeyGetter::GetInstance().GetKey(keys_checked->front());
+ if (!GpgKeyImportExportor::GetInstance().ExportKeyOpenSSH(key,
+ key_export_data)) {
+ QMessageBox::critical(nullptr, _("Error"),
+ _("An error occur in exporting."));
+ return;
+ }
+
+ if (key_export_data->empty()) {
+ QMessageBox::critical(
+ nullptr, _("Error"),
+ _("This key may not be able to export as OpenSSH format. Please check "
+ "the key-size of the subkey(s) used to sign."));
+ return;
+ }
+
+ key = GpgKeyGetter::GetInstance().GetKey(keys_checked->front());
+ if (!key.good()) {
+ QMessageBox::critical(nullptr, _("Error"), _("Key Not Found."));
+ return;
+ }
+ QString fileString = QString::fromStdString(key.name() + " " + key.email() +
+ "(" + key.id() + ").pub");
+
+ QString file_name = QFileDialog::getSaveFileName(
+ this, _("Export OpenSSH Key To File"), fileString,
+ QString(_("OpenSSH Public Key Files")) + " (*.pub);;All Files (*)");
+
+ if (!file_name.isEmpty()) {
+ write_buffer_to_file(file_name.toStdString(), *key_export_data);
+ emit signalStatusBarChanged(QString(_("key(s) exported")));
+ }
+}
+
} // namespace GpgFrontend::UI
diff --git a/src/ui/KeyMgmt.h b/src/ui/KeyMgmt.h
index bf1c9b5a..7edb1b5c 100755
--- a/src/ui/KeyMgmt.h
+++ b/src/ui/KeyMgmt.h
@@ -48,6 +48,8 @@ class KeyMgmt : public QMainWindow {
void slotExportKeyToClipboard();
+ void slotExportAsOpenSSHFormat();
+
void slotDeleteSelectedKeys();
void slotDeleteCheckedKeys();
@@ -80,6 +82,7 @@ class KeyMgmt : public QMainWindow {
QMenu* importKeyMenu{};
QAction* openKeyFileAct{};
QAction* exportKeyToFileAct{};
+ QAction* exportKeyAsOpenSSHFormat{};
QAction* exportKeyToClipboardAct{};
QAction* deleteCheckedKeysAct{};
QAction* deleteSelectedKeysAct{};
diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp
index 9aceed96..6d55aeb5 100644
--- a/src/ui/MainWindow.cpp
+++ b/src/ui/MainWindow.cpp
@@ -38,18 +38,7 @@ MainWindow::MainWindow() {
}
void MainWindow::init() noexcept {
- LOG(INFO) << _("Called");
try {
- // Check Context Status
- if (!GpgContext::GetInstance().good()) {
- QMessageBox::critical(
- nullptr, _("ENV Loading Failed"),
- _("Gnupg is not installed correctly, please follow the ReadME "
- "instructions to install gnupg and then open GpgFrontend."));
- QCoreApplication::quit();
- exit(0);
- }
-
networkAccessManager = new QNetworkAccessManager(this);
/* get path where app was started */
@@ -64,7 +53,7 @@ void MainWindow::init() noexcept {
mKeyList->slotRefresh();
- infoBoard = new InfoBoardWidget(this, mKeyList);
+ infoBoard = new InfoBoardWidget(this);
/* List of binary Attachments */
attachmentDockCreated = false;
@@ -139,7 +128,6 @@ void MainWindow::init() noexcept {
version_thread->start();
#endif
-
} catch (...) {
LOG(FATAL) << _("Critical error occur while loading GpgFrontend.");
QMessageBox::critical(nullptr, _("Loading Failed"),
diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h
index 97c5c73f..1a36bf8a 100644
--- a/src/ui/MainWindow.h
+++ b/src/ui/MainWindow.h
@@ -153,26 +153,6 @@ class MainWindow : public QMainWindow {
void slotDecryptVerify();
/**
- * @details Open dialog for encrypting file.
- */
- void slotFileEncryptCustom();
-
- /**
- * @details Open dialog for decrypting file.
- */
- void slotFileDecryptCustom();
-
- /**
- * @details Open dialog for signing file.
- */
- void slotFileSignCustom();
-
- /**
- * @details Open dialog for verifying file.
- */
- void slotFileVerifyCustom();
-
- /**
* @details Show the details of the first of the first of selected keys
*/
void slotShowKeyDetails();
@@ -338,7 +318,6 @@ class MainWindow : public QMainWindow {
QMenu* fileMenu{}; /** Submenu for file-operations*/
QMenu* editMenu{}; /** Submenu for text-operations*/
QMenu* cryptMenu{}; /** Submenu for crypt-operations */
- QMenu* fileEncMenu{}; /** Submenu for file crypt operations */
QMenu* helpMenu{}; /** Submenu for help-operations */
QMenu* keyMenu{}; /** Submenu for key-operations */
QMenu* viewMenu{}; /** Submenu for view operations */
@@ -393,12 +372,8 @@ class MainWindow : public QMainWindow {
QAction* aboutAct{}; /** Action to open about dialog */
QAction* checkUpdateAct{}; /** Action to open about dialog */
QAction* translateAct{}; /** Action to open about dialog */
- QAction* fileEncryptAct{}; /** Action to open dialog for encrypting file */
- QAction* fileDecryptAct{}; /** Action to open dialog for decrypting file */
- QAction* fileSignAct{}; /** Action to open dialog for signing file */
- QAction* fileVerifyAct{}; /** Action to open dialog for verifying file */
- QAction* openSettingsAct{}; /** Action to open settings dialog */
- QAction* showKeyDetailsAct{}; /** Action to open key-details dialog */
+ QAction* openSettingsAct{}; /** Action to open settings dialog */
+ QAction* showKeyDetailsAct{}; /** Action to open key-details dialog */
QAction* refreshKeysFromKeyserverAct{}; /** Action to refresh a key from
keyserver */
QAction* uploadKeyToServerAct{}; /** Action to append selected keys to edit */
diff --git a/src/ui/keypair_details/KeyDetailsDialog.cpp b/src/ui/keypair_details/KeyDetailsDialog.cpp
index f3cab771..3864820f 100644
--- a/src/ui/keypair_details/KeyDetailsDialog.cpp
+++ b/src/ui/keypair_details/KeyDetailsDialog.cpp
@@ -35,11 +35,15 @@ KeyDetailsDialog::KeyDetailsDialog(const GpgKey& key, QWidget* parent)
auto* mainLayout = new QVBoxLayout;
mainLayout->addWidget(tabWidget);
+#ifdef MACOS
+ setAttribute(Qt::WA_LayoutUsesWidgetRect);
+#endif
this->setAttribute(Qt::WA_DeleteOnClose, true);
this->setLayout(mainLayout);
this->setWindowTitle(_("Key Details"));
this->setModal(true);
- this->setMinimumSize(380, 620);
+ this->setMinimumSize({520, 800});
+ this->resize(this->minimumSize());
this->show();
}
} // namespace GpgFrontend::UI
diff --git a/src/ui/keypair_details/KeyPairDetailTab.cpp b/src/ui/keypair_details/KeyPairDetailTab.cpp
index de16ccf7..c0a96488 100644
--- a/src/ui/keypair_details/KeyPairDetailTab.cpp
+++ b/src/ui/keypair_details/KeyPairDetailTab.cpp
@@ -75,21 +75,35 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
vboxKD->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0);
vboxKD->addWidget(new QLabel(QString(_("Nominal Usage")) + ": "), 3, 0);
vboxKD->addWidget(new QLabel(QString(_("Actual Usage")) + ": "), 4, 0);
- vboxKD->addWidget(new QLabel(QString(_("Create Date")) + ": "), 5, 0);
- vboxKD->addWidget(new QLabel(QString(_("Expires on")) + ": "), 6, 0);
- vboxKD->addWidget(new QLabel(QString(_("Last Update")) + ": "), 7, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Create Date (Local Time)")) + ": "),
+ 5, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Expires on (Local Time)")) + ": "), 6,
+ 0);
+ vboxKD->addWidget(new QLabel(QString(_("Last Update (Local Time)")) + ": "),
+ 7, 0);
vboxKD->addWidget(new QLabel(QString(_("Master Key Existence")) + ": "), 8,
0);
- vboxKD->addWidget(keyidVarLabel, 0, 1);
- vboxKD->addWidget(algorithmVarLabel, 1, 1);
- vboxKD->addWidget(keySizeVarLabel, 2, 1);
- vboxKD->addWidget(usageVarLabel, 3, 1);
- vboxKD->addWidget(actualUsageVarLabel, 4, 1);
- vboxKD->addWidget(createdVarLabel, 5, 1);
- vboxKD->addWidget(expireVarLabel, 6, 1);
- vboxKD->addWidget(lastUpdateVarLabel, 7, 1);
- vboxKD->addWidget(masterKeyExistVarLabel, 8, 1);
+ keyidVarLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
+ vboxKD->addWidget(keyidVarLabel, 0, 1, 1, 1);
+ vboxKD->addWidget(algorithmVarLabel, 1, 1, 1, 2);
+ vboxKD->addWidget(keySizeVarLabel, 2, 1, 1, 2);
+ vboxKD->addWidget(usageVarLabel, 3, 1, 1, 2);
+ vboxKD->addWidget(actualUsageVarLabel, 4, 1, 1, 2);
+ vboxKD->addWidget(createdVarLabel, 5, 1, 1, 2);
+ vboxKD->addWidget(expireVarLabel, 6, 1, 1, 2);
+ vboxKD->addWidget(lastUpdateVarLabel, 7, 1, 1, 2);
+ vboxKD->addWidget(masterKeyExistVarLabel, 8, 1, 1, 2);
+
+ auto* copyKeyIdButton = new QPushButton(_("Copy"));
+ copyKeyIdButton->setFlat(true);
+ copyKeyIdButton->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed);
+ vboxKD->addWidget(copyKeyIdButton, 0, 2);
+ connect(copyKeyIdButton, &QPushButton::clicked, this, [=]() {
+ QString fpr = keyidVarLabel->text().trimmed();
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(fpr);
+ });
ownerBox->setLayout(vboxOD);
mvbox->addWidget(ownerBox);
@@ -116,8 +130,11 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
hboxFP->addStretch();
fingerprintBox->setLayout(hboxFP);
- mvbox->addStretch();
mvbox->addWidget(fingerprintBox);
+ mvbox->addStretch();
+
+ // Set Menu
+ createOperaMenu();
auto* opera_key_box = new QGroupBox(_("Operations"));
auto* vbox_p_k = new QVBoxLayout();
@@ -131,10 +148,9 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
SLOT(slotExportPublicKey()));
if (mKey.is_private_key()) {
- auto* export_private_button =
- new QPushButton(_("Export Private Key (Include Subkey)"));
- connect(export_private_button, SIGNAL(clicked()), this,
- SLOT(slotExportPrivateKey()));
+ auto* export_private_button = new QPushButton(_("Export Private Key"));
+ export_private_button->setStyleSheet("text-align:center;");
+ export_private_button->setMenu(secretKeyExportOperaMenu);
export_h_box_layout->addWidget(export_private_button);
if (mKey.has_master_key()) {
@@ -157,10 +173,6 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
auto* key_server_opera_button =
new QPushButton(_("Key Server Operation (Pubkey)"));
key_server_opera_button->setStyleSheet("text-align:center;");
- connect(key_server_opera_button, SIGNAL(clicked()), this,
- SLOT(slotModifyEditDatetime()));
- // Set Menu
- createKeyServerOperaMenu();
key_server_opera_button->setMenu(keyServerOperaMenu);
advance_h_box_layout->addWidget(key_server_opera_button);
@@ -194,13 +206,12 @@ KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
expBox->addWidget(expLabel);
expBox->addStretch();
mvbox->addLayout(expBox);
+ mvbox->setContentsMargins(0, 0, 0, 0);
// when key database updated
connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this,
SLOT(slotRefreshKey()));
- mvbox->setContentsMargins(0, 0, 0, 0);
-
slotRefreshKeyInfo();
setAttribute(Qt::WA_DeleteOnClose, true);
setLayout(mvbox);
@@ -230,6 +241,48 @@ void KeyPairDetailTab::slotExportPublicKey() {
}
}
+void KeyPairDetailTab::slotExportShortPrivateKey() {
+ // Show a information box with explanation about private key
+ int ret = QMessageBox::information(
+ this, _("Exporting short private Key"),
+ "<h3>" + QString(_("You are about to export your")) +
+ "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" +
+ _("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
+ _("Do you REALLY want to export your PRIVATE KEY in a Minimum "
+ "Size?") +
+ "<br />" +
+ _("For OpenPGP keys it removes all signatures except for the latest "
+ "self-signatures."),
+ QMessageBox::Cancel | QMessageBox::Ok);
+
+ // export key, if ok was clicked
+ if (ret == QMessageBox::Ok) {
+ ByteArrayPtr keyArray = nullptr;
+
+ if (!GpgKeyImportExportor::GetInstance().ExportSecretKeyShortest(
+ mKey, keyArray)) {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("An error occurred during the export operation."));
+ return;
+ }
+ auto fileString = mKey.name() + " " + mKey.email() + "(" + mKey.id() +
+ ")_short_secret.asc";
+ auto fileName =
+ QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), QString::fromStdString(fileString),
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (!write_buffer_to_file(fileName, *keyArray)) {
+ QMessageBox::critical(
+ this, _("Export Error"),
+ QString(_("Couldn't open %1 for writing")).arg(fileName.c_str()));
+ return;
+ }
+ }
+}
+
void KeyPairDetailTab::slotExportPrivateKey() {
// Show a information box with explanation about private key
int ret = QMessageBox::information(
@@ -250,8 +303,8 @@ void KeyPairDetailTab::slotExportPrivateKey() {
_("An error occurred during the export operation."));
return;
}
- auto fileString =
- mKey.name() + " " + mKey.email() + "(" + mKey.id() + ")_secret.asc";
+ auto fileString = mKey.name() + " " + mKey.email() + "(" + mKey.id() +
+ ")_full_secret.asc";
auto fileName =
QFileDialog::getSaveFileName(
this, _("Export Key To File"), QString::fromStdString(fileString),
@@ -370,7 +423,7 @@ void KeyPairDetailTab::slotRefreshKeyInfo() {
}
}
-void KeyPairDetailTab::createKeyServerOperaMenu() {
+void KeyPairDetailTab::createOperaMenu() {
keyServerOperaMenu = new QMenu(this);
auto* uploadKeyPair = new QAction(_("Upload Key Pair to Key Server"), this);
@@ -384,6 +437,21 @@ void KeyPairDetailTab::createKeyServerOperaMenu() {
keyServerOperaMenu->addAction(uploadKeyPair);
keyServerOperaMenu->addAction(updateKeyPair);
+
+ secretKeyExportOperaMenu = new QMenu(this);
+
+ auto* exportFullSecretKey = new QAction(_("Export Full Secret Key"), this);
+ connect(exportFullSecretKey, SIGNAL(triggered()), this,
+ SLOT(slotExportPrivateKey()));
+ if (!mKey.is_private_key()) exportFullSecretKey->setDisabled(true);
+
+ auto* exportShortestSecretKey =
+ new QAction(_("Export Shortest Secret Key"), this);
+ connect(exportShortestSecretKey, SIGNAL(triggered()), this,
+ SLOT(slotExportShortPrivateKey()));
+
+ secretKeyExportOperaMenu->addAction(exportFullSecretKey);
+ secretKeyExportOperaMenu->addAction(exportShortestSecretKey);
}
void KeyPairDetailTab::slotUploadKeyToServer() {
@@ -403,7 +471,7 @@ void KeyPairDetailTab::slotUpdateKeyFromServer() {
}
void KeyPairDetailTab::slotGenRevokeCert() {
- auto literal = QStringLiteral("%1 (*.rev)").arg(_("Revocation Certificates"));
+ auto literal = QString("%1 (*.rev)").arg(_("Revocation Certificates"));
QString m_output_file_name;
QFileDialog dialog(this, "Generate revocation certificate", QString(),
diff --git a/src/ui/keypair_details/KeyPairDetailTab.h b/src/ui/keypair_details/KeyPairDetailTab.h
index 68ca1ebd..3e2f2298 100644
--- a/src/ui/keypair_details/KeyPairDetailTab.h
+++ b/src/ui/keypair_details/KeyPairDetailTab.h
@@ -36,7 +36,7 @@ namespace GpgFrontend::UI {
class KeyPairDetailTab : public QWidget {
Q_OBJECT
- void createKeyServerOperaMenu();
+ void createOperaMenu();
private slots:
@@ -45,6 +45,8 @@ class KeyPairDetailTab : public QWidget {
*/
void slotExportPrivateKey();
+ void slotExportShortPrivateKey();
+
void slotExportPublicKey();
/**
@@ -95,6 +97,7 @@ class KeyPairDetailTab : public QWidget {
QLabel* expLabel;
QMenu* keyServerOperaMenu{};
+ QMenu* secretKeyExportOperaMenu{};
public:
explicit KeyPairDetailTab(const std::string& key_id,
diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
index 93e07875..8068d9a8 100644
--- a/src/ui/keypair_details/KeyPairSubkeyTab.cpp
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
@@ -62,10 +62,10 @@ KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
subkeyDetailLayout->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2,
0);
subkeyDetailLayout->addWidget(new QLabel(QString(_("Usage")) + ": "), 3, 0);
- subkeyDetailLayout->addWidget(new QLabel(QString(_("Expires On")) + ": "), 4,
- 0);
- subkeyDetailLayout->addWidget(new QLabel(QString(_("Last Update")) + ": "), 5,
- 0);
+ subkeyDetailLayout->addWidget(
+ new QLabel(QString(_("Expires On (Local Time)")) + ": "), 4, 0);
+ subkeyDetailLayout->addWidget(
+ new QLabel(QString(_("Create Date (Local Time)")) + ": "), 5, 0);
subkeyDetailLayout->addWidget(new QLabel(QString(_("Existence")) + ": "), 6,
0);
subkeyDetailLayout->addWidget(new QLabel(QString(_("Fingerprint")) + ": "), 7,
@@ -80,14 +80,23 @@ KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
masterKeyExistVarLabel = new QLabel();
fingerPrintVarLabel = new QLabel();
- subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1);
- subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1);
- subkeyDetailLayout->addWidget(expireVarLabel, 4, 1);
- subkeyDetailLayout->addWidget(algorithmVarLabel, 1, 1);
- subkeyDetailLayout->addWidget(createdVarLabel, 5, 1);
- subkeyDetailLayout->addWidget(usageVarLabel, 3, 1);
- subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1);
- subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1);
+ subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1, 1, 1);
+ subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1, 1, 2);
+ subkeyDetailLayout->addWidget(expireVarLabel, 4, 1, 1, 2);
+ subkeyDetailLayout->addWidget(algorithmVarLabel, 1, 1, 1, 2);
+ subkeyDetailLayout->addWidget(createdVarLabel, 5, 1, 1, 2);
+ subkeyDetailLayout->addWidget(usageVarLabel, 3, 1, 1, 2);
+ subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1, 1, 2);
+ subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1, 1, 2);
+
+ auto* copyKeyIdButton = new QPushButton(_("Copy"));
+ copyKeyIdButton->setFlat(true);
+ subkeyDetailLayout->addWidget(copyKeyIdButton, 0, 2);
+ connect(copyKeyIdButton, &QPushButton::clicked, this, [=]() {
+ QString fpr = keyidVarLabel->text().trimmed();
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(fpr);
+ });
listBox->setLayout(subkeyListLayout);
listBox->setContentsMargins(0, 12, 0, 0);
@@ -134,8 +143,8 @@ void KeyPairSubkeyTab::createSubkeyList() {
subkeyList->setAlternatingRowColors(true);
QStringList labels;
- labels << _("Subkey ID") << _("Key Size") << _("Algo") << _("Create Date")
- << _("Expire Date");
+ labels << _("Subkey ID") << _("Key Size") << _("Algo")
+ << _("Create Date (UTC)") << _("Expire Date (UTC)");
subkeyList->setHorizontalHeaderLabels(labels);
subkeyList->horizontalHeader()->setStretchLastSection(false);
diff --git a/src/ui/keypair_details/KeyPairUIDTab.cpp b/src/ui/keypair_details/KeyPairUIDTab.cpp
index b2aa8861..92a3c3ea 100644
--- a/src/ui/keypair_details/KeyPairUIDTab.cpp
+++ b/src/ui/keypair_details/KeyPairUIDTab.cpp
@@ -152,8 +152,8 @@ void KeyPairUIDTab::createSignList() {
sigList->setAlternatingRowColors(true);
QStringList labels;
- labels << _("Key ID") << _("Name") << _("Email") << _("Create Date")
- << _("Expired Date");
+ labels << _("Key ID") << _("Name") << _("Email") << _("Create Date (UTC)")
+ << _("Expired Date (UTC)");
sigList->setHorizontalHeaderLabels(labels);
sigList->horizontalHeader()->setStretchLastSection(false);
}
diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp
index 19be9769..535f47af 100644
--- a/src/ui/main_window/MainWindowFileSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp
@@ -245,14 +245,16 @@ void MainWindow::slotFileVerify() {
signFilePath = path + ".sig";
}
- bool ok;
- QString text =
- QInputDialog::getText(this, _("Origin file to verify"), _("Filepath"),
- QLineEdit::Normal, dataFilePath, &ok);
- if (ok && !text.isEmpty()) {
- dataFilePath = text;
- } else {
- return;
+ if (fileInfo.suffix() != "gpg") {
+ bool ok;
+ QString text =
+ QInputDialog::getText(this, _("Origin file to verify"), _("Filepath"),
+ QLineEdit::Normal, dataFilePath, &ok);
+ if (ok && !text.isEmpty()) {
+ dataFilePath = text;
+ } else {
+ return;
+ }
}
QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath);
@@ -395,13 +397,23 @@ void MainWindow::slotFileDecryptVerify() {
if (!file_pre_check(this, path)) return;
- QString outFileName, fileExtension = QFileInfo(path).suffix();
-
- if (fileExtension == "asc" || fileExtension == "gpg") {
- int pos = path.lastIndexOf(QChar('.'));
- outFileName = path.left(pos);
+ boost::filesystem::path out_path(path.toStdString());
+ if (out_path.extension() == ".asc" || out_path.extension() == ".gpg") {
+ out_path = out_path.parent_path() / out_path.filename();
} else {
- outFileName = path + ".out";
+ out_path = out_path.replace_extension(".out").string();
+ }
+ LOG(INFO) << "out path" << out_path;
+
+ if (QFile::exists(out_path.string().c_str())) {
+ auto ret =
+ QMessageBox::warning(this, _("Warning"),
+ QString(_("The output file %1 already exists, do "
+ "you need to overwrite it?"))
+ .arg(out_path.filename().string().c_str()),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel) return;
}
GpgDecrResult d_result = nullptr;
@@ -438,24 +450,4 @@ void MainWindow::slotFileDecryptVerify() {
}
}
-void MainWindow::slotFileEncryptCustom() {
- new FileEncryptionDialog(mKeyList->getChecked(),
- FileEncryptionDialog::Encrypt, this);
-}
-
-void MainWindow::slotFileDecryptCustom() {
- new FileEncryptionDialog(mKeyList->getChecked(),
- FileEncryptionDialog::Decrypt, this);
-}
-
-void MainWindow::slotFileSignCustom() {
- new FileEncryptionDialog(mKeyList->getChecked(), FileEncryptionDialog::Sign,
- this);
-}
-
-void MainWindow::slotFileVerifyCustom() {
- new FileEncryptionDialog(mKeyList->getChecked(), FileEncryptionDialog::Verify,
- this);
-}
-
} // namespace GpgFrontend::UI
diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp
index 4ad33ac3..41549182 100644
--- a/src/ui/main_window/MainWindowSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowSlotFunction.cpp
@@ -51,40 +51,56 @@ void MainWindow::slotEncrypt() {
auto key_ids = mKeyList->getChecked();
- if (key_ids->empty()) {
- QMessageBox::critical(nullptr, _("No Key Selected"), _("No Key Selected"));
- return;
- }
-
- auto key_getter = GpgFrontend::GpgKeyGetter::GetInstance();
- auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
- for (const auto& key : *keys) {
- if (!key.CanEncrActual()) {
- QMessageBox::information(
- nullptr, _("Invalid Operation"),
- QString(
- _("The selected key contains a key that does not actually have a "
- "encrypt usage.")) +
- "<br/><br/>" + _("For example the Following Key:") + " <br/>" +
- QString::fromStdString(key.uids()->front().uid()));
- return;
- }
- }
-
- auto tmp = std::make_unique<ByteArray>();
-
GpgEncrResult result = nullptr;
GpgError error;
bool if_error = false;
- process_operation(this, _("Encrypting"), [&]() {
- try {
- auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString();
- error = GpgFrontend::BasicOperator::GetInstance().Encrypt(
- std::move(keys), buffer, tmp, result);
- } catch (const std::runtime_error& e) {
- if_error = true;
+ auto tmp = std::make_unique<ByteArray>();
+
+ if (key_ids->empty()) {
+ // Symmetric Encrypt
+ auto ret =
+ QMessageBox::warning(this, _("Warning"),
+ _("No Key Selected. Do you want to encrypt with a "
+ "symmetric cipher using a passphrase?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel) return;
+
+ process_operation(this, _("Symmetrically Encrypting"), [&]() {
+ try {
+ auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString();
+ error = GpgFrontend::BasicOperator::GetInstance().EncryptSymmetric(
+ buffer, tmp, result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+ } else {
+ auto key_getter = GpgFrontend::GpgKeyGetter::GetInstance();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+ for (const auto& key : *keys) {
+ if (!key.CanEncrActual()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ QString(_(
+ "The selected key contains a key that does not actually have a "
+ "encrypt usage.")) +
+ "<br/><br/>" + _("For example the Following Key:") + " <br/>" +
+ QString::fromStdString(key.uids()->front().uid()));
+ return;
+ }
}
- });
+
+ process_operation(this, _("Encrypting"), [&]() {
+ try {
+ auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString();
+ error = GpgFrontend::BasicOperator::GetInstance().Encrypt(
+ std::move(keys), buffer, tmp, result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+ }
if (!if_error) {
auto resultAnalyse = EncryptResultAnalyse(error, std::move(result));
diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp
index 4499b9c8..a629057e 100644
--- a/src/ui/main_window/MainWindowUI.cpp
+++ b/src/ui/main_window/MainWindowUI.cpp
@@ -51,7 +51,7 @@ void MainWindow::createActions() {
browserAct->setToolTip(_("Open a file browser"));
connect(browserAct, SIGNAL(triggered()), this, SLOT(slotOpenFileTab()));
- saveAct = new QAction(_("Save"), this);
+ saveAct = new QAction(_("Save File"), this);
saveAct->setIcon(QIcon(":filesave.png"));
saveAct->setShortcut(QKeySequence::Save);
saveAct->setToolTip(_("Save the current File"));
@@ -179,28 +179,6 @@ void MainWindow::createActions() {
connect(decryptVerifyAct, SIGNAL(triggered()), this,
SLOT(slotDecryptVerify()));
- /*
- * File encryption submenu
- */
- fileEncryptAct = new QAction(_("Encrypt File"), this);
- fileEncryptAct->setToolTip(_("Encrypt File"));
- connect(fileEncryptAct, SIGNAL(triggered()), this,
- SLOT(slotFileEncryptCustom()));
-
- fileDecryptAct = new QAction(_("Decrypt File"), this);
- fileDecryptAct->setToolTip(_("Decrypt File"));
- connect(fileDecryptAct, SIGNAL(triggered()), this,
- SLOT(slotFileDecryptCustom()));
-
- fileSignAct = new QAction(_("Sign File"), this);
- fileSignAct->setToolTip(_("Sign File"));
- connect(fileSignAct, SIGNAL(triggered()), this, SLOT(slotFileSignCustom()));
-
- fileVerifyAct = new QAction(_("Verify File"), this);
- fileVerifyAct->setToolTip(_("Verify File"));
- connect(fileVerifyAct, SIGNAL(triggered()), this,
- SLOT(slotFileVerifyCustom()));
-
signAct = new QAction(_("Sign"), this);
signAct->setIcon(QIcon(":signature.png"));
signAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
@@ -363,12 +341,6 @@ void MainWindow::createMenus() {
editMenu->addSeparator();
editMenu->addAction(openSettingsAct);
- fileEncMenu = new QMenu(_("File..."));
- fileEncMenu->addAction(fileEncryptAct);
- fileEncMenu->addAction(fileDecryptAct);
- fileEncMenu->addAction(fileSignAct);
- fileEncMenu->addAction(fileVerifyAct);
-
cryptMenu = menuBar()->addMenu(_("Crypt"));
cryptMenu->addAction(encryptAct);
cryptMenu->addAction(encryptSignAct);
@@ -378,7 +350,6 @@ void MainWindow::createMenus() {
cryptMenu->addAction(signAct);
cryptMenu->addAction(verifyAct);
cryptMenu->addSeparator();
- cryptMenu->addMenu(fileEncMenu);
keyMenu = menuBar()->addMenu(_("Keys"));
importKeyMenu = keyMenu->addMenu(_("Import Key"));
diff --git a/src/ui/settings/SettingsGeneral.cpp b/src/ui/settings/SettingsGeneral.cpp
index 4f9bfbae..978a7b5f 100644
--- a/src/ui/settings/SettingsGeneral.cpp
+++ b/src/ui/settings/SettingsGeneral.cpp
@@ -81,12 +81,15 @@ GeneralTab::GeneralTab(QWidget* parent) : QWidget(parent) {
*****************************************/
auto* langBox = new QGroupBox(_("Language"));
auto* langBoxLayout = new QVBoxLayout();
- langSelectBox = new QComboBox;
+ langSelectBox = new QComboBox();
+ langSelectBox->setMaxVisibleItems(8);
+ langSelectBox->view()->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
lang = SettingsDialog::listLanguages();
for (const auto& l : lang) {
langSelectBox->addItem(l);
}
+ langSelectBox->setSizeAdjustPolicy(QComboBox::AdjustToMinimumContentsLength);
langBoxLayout->addWidget(langSelectBox);
langBoxLayout->addWidget(new QLabel(
diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp
index c51e0c76..ca6dedc1 100644
--- a/src/ui/widgets/FilePage.cpp
+++ b/src/ui/widgets/FilePage.cpp
@@ -25,94 +25,55 @@
#include "ui/widgets/FilePage.h"
#include <boost/filesystem.hpp>
+#include <string>
#include "ui/MainWindow.h"
#include "ui/SignalStation.h"
+#include "ui_FilePage.h"
namespace GpgFrontend::UI {
-FilePage::FilePage(QWidget* parent) : QWidget(parent) {
+FilePage::FilePage(QWidget* parent)
+ : QWidget(parent), ui(std::make_shared<Ui_FilePage>()) {
+ ui->setupUi(this);
+
firstParent = parent;
dirModel = new QFileSystemModel();
dirModel->setRootPath(QDir::currentPath());
+ dirModel->setFilter(QDir::AllDirs | QDir::Files | QDir::NoDotAndDotDot);
- dirTreeView = new QTreeView();
- dirTreeView->setModel(dirModel);
- dirTreeView->setAnimated(true);
- dirTreeView->setIndentation(20);
- dirTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
- dirTreeView->setColumnWidth(0, 320);
- dirTreeView->setRootIndex(dirModel->index(QDir::currentPath()));
+ ui->fileTreeView->setModel(dirModel);
+ ui->fileTreeView->setColumnWidth(0, 320);
+ ui->fileTreeView->sortByColumn(0, Qt::AscendingOrder);
mPath = boost::filesystem::path(dirModel->rootPath().toStdString());
createPopupMenu();
- upLevelButton = new QPushButton();
- connect(upLevelButton, SIGNAL(clicked(bool)), this, SLOT(slotUpLevel()));
-
- QString buttonStyle =
- "QPushButton{border:none;background-color:rgba(255, 255, 255, 0);}";
-
- auto upPixmap = QPixmap(":up.png");
- upPixmap =
- upPixmap.scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation);
- QIcon upButtonIcon(upPixmap);
- upLevelButton->setIcon(upButtonIcon);
- upLevelButton->setIconSize(upPixmap.rect().size());
- upLevelButton->setStyleSheet(buttonStyle);
-
- refreshButton = new QPushButton(_("Refresh"));
- connect(refreshButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath()));
-
- goPathButton = new QPushButton();
- connect(goPathButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath()));
+ connect(ui->upPathButton, &QPushButton::clicked, this,
+ &FilePage::slotUpLevel);
+ connect(ui->refreshButton, &QPushButton::clicked, this,
+ &FilePage::slotGoPath);
+ ui->optionsButton->setMenu(optionPopUpMenu);
- auto updatePixmap = QPixmap(":refresh.png");
- updatePixmap = updatePixmap.scaled(18, 18, Qt::KeepAspectRatio,
- Qt::SmoothTransformation);
- QIcon updateButtonIcon(updatePixmap);
- goPathButton->setIcon(updateButtonIcon);
- goPathButton->setIconSize(updatePixmap.rect().size());
- goPathButton->setStyleSheet(buttonStyle);
-
- pathEdit = new QLineEdit();
- pathEdit->setText(dirModel->rootPath());
+ ui->pathEdit->setText(dirModel->rootPath());
pathEditCompleter = new QCompleter(this);
pathCompleteModel = new QStringListModel();
pathEditCompleter->setModel(pathCompleteModel);
pathEditCompleter->setCaseSensitivity(Qt::CaseInsensitive);
pathEditCompleter->setCompletionMode(QCompleter::UnfilteredPopupCompletion);
- pathEdit->setCompleter(pathEditCompleter);
-
- auto* menuLayout = new QHBoxLayout();
- menuLayout->addWidget(upLevelButton);
- menuLayout->setStretchFactor(upLevelButton, 1);
- menuLayout->addWidget(pathEdit);
- menuLayout->setStretchFactor(pathEdit, 10);
- menuLayout->addWidget(goPathButton);
- menuLayout->setStretchFactor(goPathButton, 1);
-
- auto* layout = new QVBoxLayout();
- layout->setContentsMargins(0, 0, 0, 0);
- layout->setSpacing(0);
- layout->addLayout(menuLayout);
- layout->setStretchFactor(menuLayout, 1);
- layout->addWidget(dirTreeView);
- layout->setStretchFactor(dirTreeView, 8);
-
- this->setLayout(layout);
-
- connect(dirTreeView, &QTreeView::clicked, this,
+ ui->pathEdit->setCompleter(pathEditCompleter);
+
+ connect(ui->fileTreeView, &QTreeView::clicked, this,
&FilePage::fileTreeViewItemClicked);
- connect(dirTreeView, &QTreeView::doubleClicked, this,
+ connect(ui->fileTreeView, &QTreeView::doubleClicked, this,
&FilePage::fileTreeViewItemDoubleClicked);
- connect(dirTreeView, &QTreeView::customContextMenuRequested, this,
+ connect(ui->fileTreeView, &QTreeView::customContextMenuRequested, this,
&FilePage::onCustomContextMenu);
- connect(pathEdit, &QLineEdit::textChanged, [=]() {
- auto path = pathEdit->text();
+ connect(ui->pathEdit, &QLineEdit::textChanged, [=]() {
+ auto path = ui->pathEdit->text();
auto dir = QDir(path);
if (path.endsWith("/") && dir.isReadable()) {
auto dir_list = dir.entryInfoList(QDir::AllEntries);
@@ -139,22 +100,30 @@ void FilePage::fileTreeViewItemClicked(const QModelIndex& index) {
}
void FilePage::slotUpLevel() {
- QModelIndex currentRoot = dirTreeView->rootIndex();
+ QModelIndex currentRoot = ui->fileTreeView->rootIndex();
- mPath = boost::filesystem::path(
- dirModel->fileInfo(currentRoot).absoluteFilePath().toStdString());
+ auto utf8_path =
+ dirModel->fileInfo(currentRoot).absoluteFilePath().toStdString();
+ boost::filesystem::path path_obj(utf8_path);
+
+ mPath = path_obj;
LOG(INFO) << "get path" << mPath;
- if (mPath.has_parent_path()) {
+ if (mPath.has_parent_path() && !mPath.parent_path().empty()) {
mPath = mPath.parent_path();
LOG(INFO) << "parent path" << mPath;
- pathEdit->setText(mPath.string().c_str());
- slotGoPath();
+ ui->pathEdit->setText(mPath.string().c_str());
+ this->slotGoPath();
}
}
void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex& index) {
- pathEdit->setText(dirModel->fileInfo(index).absoluteFilePath());
- slotGoPath();
+ QFileInfo file_info(dirModel->fileInfo(index).absoluteFilePath());
+ if (file_info.isFile()) {
+ slotOpenItem();
+ } else {
+ ui->pathEdit->setText(file_info.filePath());
+ slotGoPath();
+ }
}
QString FilePage::getSelected() const {
@@ -162,19 +131,20 @@ QString FilePage::getSelected() const {
}
void FilePage::slotGoPath() {
- const auto path_edit = pathEdit->text().toStdString();
- LOG(INFO) << "get path edit" << path_edit;
- if (mPath.string() != path_edit) mPath = path_edit;
+ const auto path_edit = ui->pathEdit->text().toStdString();
+ boost::filesystem::path path_obj(path_edit);
+
+ if (mPath.string() != path_edit) mPath = path_obj;
auto fileInfo = QFileInfo(mPath.string().c_str());
if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
mPath = boost::filesystem::path(fileInfo.filePath().toStdString());
LOG(INFO) << "set path" << mPath;
- dirTreeView->setRootIndex(dirModel->index(fileInfo.filePath()));
+ ui->fileTreeView->setRootIndex(dirModel->index(fileInfo.filePath()));
+ dirModel->setRootPath(fileInfo.filePath());
for (int i = 1; i < dirModel->columnCount(); ++i) {
- dirTreeView->resizeColumnToContents(i);
+ ui->fileTreeView->resizeColumnToContents(i);
}
- pathEdit->setText(mPath.generic_path().string().c_str());
-
+ ui->pathEdit->setText(mPath.generic_path().string().c_str());
} else {
QMessageBox::critical(
this, _("Error"),
@@ -186,26 +156,35 @@ void FilePage::slotGoPath() {
void FilePage::createPopupMenu() {
popUpMenu = new QMenu();
- auto openItemAct = new QAction(_("Open"), this);
- connect(openItemAct, SIGNAL(triggered()), this, SLOT(slotOpenItem()));
- auto renameItemAct = new QAction(_("Rename"), this);
- connect(renameItemAct, SIGNAL(triggered()), this, SLOT(slotRenameItem()));
- auto deleteItemAct = new QAction(_("Delete"), this);
- connect(deleteItemAct, SIGNAL(triggered()), this, SLOT(slotDeleteItem()));
+ openItemAct = new QAction(_("Open"), this);
+ connect(openItemAct, &QAction::triggered, this, &FilePage::slotOpenItem);
+ renameItemAct = new QAction(_("Rename"), this);
+ connect(renameItemAct, &QAction::triggered, this, &FilePage::slotRenameItem);
+ deleteItemAct = new QAction(_("Delete"), this);
+ connect(deleteItemAct, &QAction::triggered, this, &FilePage::slotDeleteItem);
encryptItemAct = new QAction(_("Encrypt Sign"), this);
- connect(encryptItemAct, SIGNAL(triggered()), this, SLOT(slotEncryptItem()));
+ connect(encryptItemAct, &QAction::triggered, this,
+ &FilePage::slotEncryptItem);
decryptItemAct =
new QAction(QString(_("Decrypt Verify")) + " " + _("(.gpg .asc)"), this);
- connect(decryptItemAct, SIGNAL(triggered()), this, SLOT(slotDecryptItem()));
+ connect(decryptItemAct, &QAction::triggered, this,
+ &FilePage::slotDecryptItem);
signItemAct = new QAction(_("Sign"), this);
- connect(signItemAct, SIGNAL(triggered()), this, SLOT(slotSignItem()));
+ connect(signItemAct, &QAction::triggered, this, &FilePage::slotSignItem);
verifyItemAct =
new QAction(QString(_("Verify")) + " " + _("(.sig .gpg .asc)"), this);
- connect(verifyItemAct, SIGNAL(triggered()), this, SLOT(slotVerifyItem()));
+ connect(verifyItemAct, &QAction::triggered, this, &FilePage::slotVerifyItem);
hashCalculateAct = new QAction(_("Calculate Hash"), this);
- connect(hashCalculateAct, SIGNAL(triggered()), this,
- SLOT(slotCalculateHash()));
+ connect(hashCalculateAct, &QAction::triggered, this,
+ &FilePage::slotCalculateHash);
+
+ mkdirAct = new QAction(_("Make New Directory"), this);
+ connect(mkdirAct, &QAction::triggered, this, &FilePage::slotMkdir);
+
+ createEmptyFileAct = new QAction(_("Create Empty File"), this);
+ connect(createEmptyFileAct, &QAction::triggered, this,
+ &FilePage::slotCreateEmptyFile);
popUpMenu->addAction(openItemAct);
popUpMenu->addAction(renameItemAct);
@@ -216,15 +195,47 @@ void FilePage::createPopupMenu() {
popUpMenu->addAction(signItemAct);
popUpMenu->addAction(verifyItemAct);
popUpMenu->addSeparator();
+ popUpMenu->addAction(mkdirAct);
+ popUpMenu->addAction(createEmptyFileAct);
popUpMenu->addAction(hashCalculateAct);
+
+ optionPopUpMenu = new QMenu();
+
+ auto showHiddenAct = new QAction(_("Show Hidden File"), this);
+ showHiddenAct->setCheckable(true);
+ connect(showHiddenAct, &QAction::triggered, this, [&](bool checked) {
+ LOG(INFO) << "Set Hidden" << checked;
+ if (checked)
+ dirModel->setFilter(dirModel->filter() | QDir::Hidden);
+ else
+ dirModel->setFilter(dirModel->filter() & ~QDir::Hidden);
+ dirModel->setRootPath(mPath.string().c_str());
+ });
+ optionPopUpMenu->addAction(showHiddenAct);
+
+ auto showSystemAct = new QAction(_("Show System File"), this);
+ showSystemAct->setCheckable(true);
+ connect(showSystemAct, &QAction::triggered, this, [&](bool checked) {
+ LOG(INFO) << "Set Hidden" << checked;
+ if (checked)
+ dirModel->setFilter(dirModel->filter() | QDir::System);
+ else
+ dirModel->setFilter(dirModel->filter() & ~QDir::System);
+ dirModel->setRootPath(mPath.string().c_str());
+ });
+ optionPopUpMenu->addAction(showSystemAct);
}
void FilePage::onCustomContextMenu(const QPoint& point) {
- QModelIndex index = dirTreeView->indexAt(point);
+ QModelIndex index = ui->fileTreeView->indexAt(point);
selectedPath = boost::filesystem::path(
dirModel->fileInfo(index).absoluteFilePath().toStdString());
LOG(INFO) << "right click" << selectedPath;
if (index.isValid()) {
+ openItemAct->setEnabled(true);
+ renameItemAct->setEnabled(true);
+ deleteItemAct->setEnabled(true);
+
QFileInfo info(QString::fromStdString(selectedPath.string()));
encryptItemAct->setEnabled(
info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig"));
@@ -236,9 +247,19 @@ void FilePage::onCustomContextMenu(const QPoint& point) {
verifyItemAct->setEnabled(
info.isFile() && (info.suffix() == "sig" || info.suffix() == "gpg"));
hashCalculateAct->setEnabled(info.isFile() && info.isReadable());
-
- popUpMenu->exec(dirTreeView->viewport()->mapToGlobal(point));
+ } else {
+ openItemAct->setEnabled(false);
+ renameItemAct->setEnabled(false);
+ deleteItemAct->setEnabled(false);
+
+ encryptItemAct->setEnabled(false);
+ encryptItemAct->setEnabled(false);
+ decryptItemAct->setEnabled(false);
+ signItemAct->setEnabled(false);
+ verifyItemAct->setEnabled(false);
+ hashCalculateAct->setEnabled(false);
}
+ popUpMenu->exec(ui->fileTreeView->viewport()->mapToGlobal(point));
}
void FilePage::slotOpenItem() {
@@ -247,7 +268,7 @@ void FilePage::slotOpenItem() {
if (info.isReadable() && info.isExecutable()) {
const auto file_path = info.filePath().toStdString();
LOG(INFO) << "set path" << file_path;
- pathEdit->setText(info.filePath());
+ ui->pathEdit->setText(info.filePath());
slotGoPath();
} else {
QMessageBox::critical(this, _("Error"),
@@ -291,8 +312,8 @@ void FilePage::slotRenameItem() {
}
void FilePage::slotDeleteItem() {
- QModelIndex index = dirTreeView->currentIndex();
- QVariant data = dirTreeView->model()->data(index);
+ QModelIndex index = ui->fileTreeView->currentIndex();
+ QVariant data = ui->fileTreeView->model()->data(index);
auto ret = QMessageBox::warning(this, _("Warning"),
_("Are you sure you want to delete it?"),
@@ -300,7 +321,7 @@ void FilePage::slotDeleteItem() {
if (ret == QMessageBox::Cancel) return;
- qDebug() << "Delete Item" << data.toString();
+ LOG(INFO) << "Delete Item" << data.toString().toStdString();
if (!dirModel->remove(index)) {
QMessageBox::critical(this, _("Error"),
@@ -377,10 +398,49 @@ void FilePage::slotCalculateHash() {
}
}
+void FilePage::slotMkdir() {
+ auto index = ui->fileTreeView->rootIndex();
+
+ QString new_dir_name;
+ bool ok;
+ new_dir_name =
+ QInputDialog::getText(this, _("Make New Directory"), _("Directory Name"),
+ QLineEdit::Normal, new_dir_name, &ok);
+ if (ok && !new_dir_name.isEmpty()) {
+ dirModel->mkdir(index, new_dir_name);
+ }
+}
+
+void FilePage::slotCreateEmptyFile() {
+ auto root_path_str = dirModel->rootPath().toStdString();
+ boost::filesystem::path root_path(root_path_str);
+
+ QString new_file_name;
+ bool ok;
+ new_file_name = QInputDialog::getText(this, _("Create Empty File"),
+ _("Filename (you can given extension)"),
+ QLineEdit::Normal, new_file_name, &ok);
+ if (ok && !new_file_name.isEmpty()) {
+ auto file_path = root_path / new_file_name.toStdString();
+ QFile new_file(file_path.string().c_str());
+ if (!new_file.open(QIODevice::WriteOnly | QIODevice::NewOnly)) {
+ QMessageBox::critical(this, _("Error"), _("Unable to create the file."));
+ }
+ new_file.close();
+ }
+}
+
void FilePage::keyPressEvent(QKeyEvent* event) {
- qDebug() << "Key Press" << event->key();
- if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
+ LOG(INFO) << "Key Press" << event->key();
+ if (ui->pathEdit->hasFocus() &&
+ (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)) {
slotGoPath();
+ } else if (ui->fileTreeView->currentIndex().isValid()) {
+ if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter)
+ slotOpenItem();
+ else if (event->key() == Qt::Key_Delete ||
+ event->key() == Qt::Key_Backspace)
+ slotDeleteItem();
}
}
diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h
index 2a9f5b57..03caf36b 100644
--- a/src/ui/widgets/FilePage.h
+++ b/src/ui/widgets/FilePage.h
@@ -30,6 +30,8 @@
#include "ui/GpgFrontendUI.h"
#include "ui/widgets/InfoBoardWidget.h"
+class Ui_FilePage;
+
namespace GpgFrontend::UI {
class FilePage : public QWidget {
@@ -63,6 +65,8 @@ class FilePage : public QWidget {
void slotSignItem();
void slotVerifyItem();
void slotCalculateHash();
+ void slotMkdir();
+ void slotCreateEmptyFile();
void onCustomContextMenu(const QPoint& point);
@@ -72,9 +76,9 @@ class FilePage : public QWidget {
private:
void createPopupMenu();
+ std::shared_ptr<Ui_FilePage> ui;
+
QFileSystemModel* dirModel;
- QTreeView* dirTreeView;
- QLineEdit* pathEdit;
QCompleter* pathEditCompleter;
QStringListModel* pathCompleteModel;
@@ -82,16 +86,18 @@ class FilePage : public QWidget {
boost::filesystem::path mPath;
boost::filesystem::path selectedPath;
- QPushButton* upLevelButton;
- QPushButton* goPathButton;
- QPushButton* refreshButton;
-
QMenu* popUpMenu{};
+ QMenu* optionPopUpMenu{};
QAction* encryptItemAct{};
QAction* decryptItemAct{};
QAction* signItemAct{};
QAction* verifyItemAct{};
QAction* hashCalculateAct{};
+ QAction* mkdirAct{};
+ QAction* openItemAct{};
+ QAction* renameItemAct{};
+ QAction* deleteItemAct{};
+ QAction* createEmptyFileAct{};
QWidget* firstParent;
};
diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp
index e0de75f9..1b7dbda0 100644
--- a/src/ui/widgets/InfoBoardWidget.cpp
+++ b/src/ui/widgets/InfoBoardWidget.cpp
@@ -26,87 +26,35 @@
#include "ui/SignalStation.h"
#include "ui/settings/GlobalSettingStation.h"
+#include "ui_InfoBoard.h"
namespace GpgFrontend::UI {
-InfoBoardWidget::InfoBoardWidget(QWidget* parent, KeyList* keyList)
- : QWidget(parent), mKeyList(keyList) {
- infoBoard = new QTextEdit(this);
- infoBoard->setReadOnly(true);
- infoBoard->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
- infoBoard->setMinimumWidth(480);
- infoBoard->setContentsMargins(0, 0, 0, 0);
-
- importFromKeyserverAct =
- new QAction(_("Import missing key from Keyserver"), this);
- connect(importFromKeyserverAct, SIGNAL(triggered()), this,
- SLOT(slotImportFromKeyserver()));
-
- detailMenu = new QMenu(this);
- detailMenu->addAction(importFromKeyserverAct);
- importFromKeyserverAct->setVisible(false);
-
- auto* action_button_menu = new QWidget();
- action_button_menu->setContentsMargins(0, 0, 0, 0);
- action_button_menu->setSizePolicy(QSizePolicy::Preferred,
- QSizePolicy::Minimum);
- action_button_menu->setFixedHeight(40);
-
- actionButtonLayout = new QHBoxLayout();
- actionButtonLayout->setContentsMargins(0, 0, 0, 0);
- actionButtonLayout->setSpacing(0);
-
- auto* label = new QLabel(_("Actions"));
- label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
- label->setContentsMargins(0, 0, 0, 0);
- mButtonGroup = new QButtonGroup(this);
-
- auto* bottom_layout = new QHBoxLayout(this);
- bottom_layout->addWidget(label);
- actionButtonLayout->addStretch();
- bottom_layout->addLayout(actionButtonLayout);
- action_button_menu->setLayout(bottom_layout);
-
- QFrame* line;
- line = new QFrame(this);
- line->setFrameShape(QFrame::HLine);
- line->setFrameShadow(QFrame::Sunken);
- line->setContentsMargins(0, 0, 0, 0);
-
- auto* notificationWidgetLayout = new QVBoxLayout(this);
- notificationWidgetLayout->setContentsMargins(0, 0, 0, 0);
- notificationWidgetLayout->setSpacing(0);
-
- notificationWidgetLayout->addWidget(infoBoard);
- notificationWidgetLayout->setStretchFactor(infoBoard, 10);
- notificationWidgetLayout->addWidget(action_button_menu);
- notificationWidgetLayout->setStretchFactor(action_button_menu, 1);
- notificationWidgetLayout->addWidget(line);
- notificationWidgetLayout->setStretchFactor(line, 1);
- notificationWidgetLayout->addStretch(0);
- this->setLayout(notificationWidgetLayout);
+InfoBoardWidget::InfoBoardWidget(QWidget* parent)
+ : QWidget(parent), ui(std::make_shared<Ui_InfoBoard>()) {
+ ui->setupUi(this);
- connect(SignalStation::GetInstance(), &SignalStation::signalRefreshInfoBoard,
- this, &InfoBoardWidget::slotRefresh);
+ ui->actionButtonLayout->addStretch();
+ ui->actionLabel->setText(_("InfoBoard's Actions Menu"));
+ ui->copyButton->setText(_("Copy"));
+ ui->saveButton->setText(_("Save"));
+ ui->clearButton->setText(_("Clear"));
- // set default size
- infoBoard->resize(480, 120);
- resize(480, 120);
-}
+ connect(ui->copyButton, &QPushButton::clicked, this,
+ &InfoBoardWidget::slotCopy);
+ connect(ui->saveButton, &QPushButton::clicked, this,
+ &InfoBoardWidget::slotSave);
+ connect(ui->clearButton, &QPushButton::clicked, this,
+ &InfoBoardWidget::slotReset);
-void InfoBoardWidget::slotImportFromKeyserver() {
- auto* importDialog = new KeyServerImportDialog(false, this);
- auto key_ids = std::make_unique<KeyIdArgsList>();
- for (const auto& key_id : *keysNotInList) {
- key_ids->push_back(key_id.toStdString());
- }
- importDialog->slotImport(key_ids);
+ connect(SignalStation::GetInstance(), &SignalStation::signalRefreshInfoBoard,
+ this, &InfoBoardWidget::slotRefresh);
}
void InfoBoardWidget::setInfoBoard(const QString& text,
InfoBoardStatus verifyLabelStatus) {
QString color;
- infoBoard->clear();
+ ui->infoBoard->clear();
switch (verifyLabelStatus) {
case INFO_ERROR_OK:
color = "#008000";
@@ -120,12 +68,12 @@ void InfoBoardWidget::setInfoBoard(const QString& text,
default:
break;
}
- infoBoard->append(text);
+ ui->infoBoard->append(text);
- infoBoard->setAutoFillBackground(true);
- QPalette status = infoBoard->palette();
+ ui->infoBoard->setAutoFillBackground(true);
+ QPalette status = ui->infoBoard->palette();
status.setColor(QPalette::Text, color);
- infoBoard->setPalette(status);
+ ui->infoBoard->setPalette(status);
auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
@@ -137,13 +85,13 @@ void InfoBoardWidget::setInfoBoard(const QString& text,
} catch (...) {
LOG(ERROR) << _("Setting Operation Error") << _("info_font_size");
}
- infoBoard->setFont(QFont("Times", info_font_size));
+ ui->infoBoard->setFont(QFont("Times", info_font_size));
}
void InfoBoardWidget::slotRefresh(const QString& text, InfoBoardStatus status) {
- infoBoard->clear();
+ ui->infoBoard->clear();
setInfoBoard(text, status);
- infoBoard->verticalScrollBar()->setValue(0);
+ ui->infoBoard->verticalScrollBar()->setValue(0);
}
void InfoBoardWidget::associateTextEdit(QTextEdit* edit) {
@@ -156,9 +104,6 @@ void InfoBoardWidget::associateTextEdit(QTextEdit* edit) {
void InfoBoardWidget::associateTabWidget(QTabWidget* tab) {
if (mTextPage != nullptr)
disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset()));
- // if (mFileTreeView != nullptr)
- // disconnect(mFileTreeView, &FilePage::pathChanged, this,
- // &InfoBoardWidget::slotReset);
if (mTabWidget != nullptr) {
disconnect(mTabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset()));
connect(mTabWidget, SIGNAL(tabCloseRequested(int)), this,
@@ -173,13 +118,14 @@ void InfoBoardWidget::associateTabWidget(QTabWidget* tab) {
void InfoBoardWidget::addOptionalAction(const QString& name,
const std::function<void()>& action) {
+ LOG(INFO) << "add option" << name.toStdString();
auto actionButton = new QPushButton(name);
auto layout = new QHBoxLayout();
layout->setContentsMargins(5, 0, 5, 0);
- infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ ui->infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
// set margin from surroundings
layout->addWidget(actionButton);
- actionButtonLayout->addLayout(layout);
+ ui->actionButtonLayout->addLayout(layout);
connect(actionButton, &QPushButton::clicked, this, [=]() { action(); });
}
@@ -188,11 +134,11 @@ void InfoBoardWidget::addOptionalAction(const QString& name,
*/
void InfoBoardWidget::resetOptionActionsMenu() {
// skip stretch
- deleteWidgetsInLayout(actionButtonLayout, 1);
+ deleteWidgetsInLayout(ui->actionButtonLayout, 1);
}
void InfoBoardWidget::slotReset() {
- this->infoBoard->clear();
+ ui->infoBoard->clear();
resetOptionActionsMenu();
}
@@ -214,4 +160,24 @@ void InfoBoardWidget::deleteWidgetsInLayout(QLayout* layout, int start_index) {
}
}
+void InfoBoardWidget::slotCopy() {
+ auto* clipboard = QGuiApplication::clipboard();
+ clipboard->setText(ui->infoBoard->toPlainText());
+}
+
+void InfoBoardWidget::slotSave() {
+ auto file_path = QFileDialog::getSaveFileName(
+ this, _("Save Information Board's Content"), {}, tr("Text (*.txt)"));
+ LOG(INFO) << "file path" << file_path.toStdString();
+ QFile file(file_path);
+ if (file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
+ file.write(ui->infoBoard->toPlainText().toUtf8());
+ } else {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("The file path is not exists, unprivileged or unreachable."));
+ }
+ file.close();
+}
+
} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/InfoBoardWidget.h b/src/ui/widgets/InfoBoardWidget.h
index b7239adb..8d37be6c 100644
--- a/src/ui/widgets/InfoBoardWidget.h
+++ b/src/ui/widgets/InfoBoardWidget.h
@@ -29,6 +29,8 @@
#include "gpg/result_analyse/VerifyResultAnalyse.h"
#include "ui/details/VerifyDetailsDialog.h"
+class Ui_InfoBoard;
+
namespace GpgFrontend::UI {
/**
@@ -53,7 +55,7 @@ class InfoBoardWidget : public QWidget {
* @param ctx The GPGme-Context
* @param parent The parent widget
*/
- explicit InfoBoardWidget(QWidget* parent, KeyList* keyList);
+ explicit InfoBoardWidget(QWidget* parent);
void associateTextEdit(QTextEdit* edit);
@@ -72,17 +74,8 @@ class InfoBoardWidget : public QWidget {
*/
void setInfoBoard(const QString& text, InfoBoardStatus verifyLabelStatus);
- QStringList* keysNotInList; /** List with keys, which are in signature but not
- in keylist */
-
public slots:
- /**
- * @details Import the keys contained in keysNotInList from keyserver
- *
- */
- void slotImportFromKeyserver();
-
void slotReset();
/**
@@ -90,19 +83,17 @@ class InfoBoardWidget : public QWidget {
*/
void slotRefresh(const QString& text, InfoBoardStatus status);
+ private slots:
+
+ void slotCopy();
+
+ void slotSave();
+
private:
- QMenu* detailMenu; /** Menu for te Button in verfiyNotification */
- QAction* importFromKeyserverAct; /** Action for importing keys from keyserver
- which are notin keylist */
- QTextEdit* infoBoard;
- KeyList* mKeyList; /** Table holding the keys */
+ std::shared_ptr<Ui_InfoBoard> ui;
QTextEdit* mTextPage{nullptr}; /** TextEdit associated to the notification */
- QTabWidget* mTabWidget{
- nullptr}; /** TreeView associated to the notification */
-
- QHBoxLayout* actionButtonLayout;
- QButtonGroup* mButtonGroup;
+ QTabWidget* mTabWidget{nullptr};
void deleteWidgetsInLayout(QLayout* layout, int start_index = 0);
};
diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp
index 5931e337..02a12e80 100644
--- a/src/ui/widgets/KeyList.cpp
+++ b/src/ui/widgets/KeyList.cpp
@@ -46,6 +46,7 @@ void KeyList::init() {
mGroupTab = new QTabWidget();
mGroupTab->setMovable(true);
mGroupTab->setTabsClosable(false);
+ mGroupTab->setDocumentMode(true);
auto* layout = new QVBoxLayout;
layout->addWidget(mGroupTab);
diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp
index ec6c6c7a..036c69d4 100644
--- a/src/ui/widgets/TextEdit.cpp
+++ b/src/ui/widgets/TextEdit.cpp
@@ -77,12 +77,13 @@ void TextEdit::slotNewFileTab() const {
void TextEdit::slotOpenFile(QString& path) {
QFile file(path);
- LOG(INFO) << " path" << path.toStdString();
+ LOG(INFO) << "path" << path.toStdString();
auto result = file.open(QIODevice::ReadOnly | QIODevice::Text);
if (result) {
auto* page = new EditorPage(path);
QApplication::setOverrideCursor(Qt::WaitCursor);
- tabWidget->addTab(page, strippedName(path));
+ auto index = tabWidget->addTab(page, strippedName(path));
+ tabWidget->setTabIcon(index, QIcon(":file.png"));
tabWidget->setCurrentIndex(tabWidget->count() - 1);
QApplication::restoreOverrideCursor();
page->getTextPage()->setFocus();
@@ -96,7 +97,6 @@ void TextEdit::slotOpenFile(QString& path) {
}
file.close();
- LOG(INFO) << "done";
}
void TextEdit::slotOpen() {
diff --git a/ui/FilePage.ui b/ui/FilePage.ui
new file mode 100644
index 00000000..6d7f7d7a
--- /dev/null
+++ b/ui/FilePage.ui
@@ -0,0 +1,151 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>FilePage</class>
+ <widget class="QWidget" name="FilePage">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>1041</width>
+ <height>619</height>
+ </rect>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Expanding">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="maximumSize">
+ <size>
+ <width>1041</width>
+ <height>619</height>
+ </size>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMaximumSize</enum>
+ </property>
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetMaximumSize</enum>
+ </property>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_2" stretch="0,0,0,0">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetDefaultConstraint</enum>
+ </property>
+ <item>
+ <widget class="QLineEdit" name="pathEdit">
+ <property name="tabletTracking">
+ <bool>false</bool>
+ </property>
+ <property name="text">
+ <string/>
+ </property>
+ <property name="clearButtonEnabled">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="refreshButton">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../gpgfrontend.qrc">
+ <normaloff>:/refresh.png</normaloff>:/refresh.png</iconset>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QPushButton" name="upPathButton">
+ <property name="text">
+ <string/>
+ </property>
+ <property name="icon">
+ <iconset resource="../gpgfrontend.qrc">
+ <normaloff>:/up.png</normaloff>:/up.png</iconset>
+ </property>
+ <property name="default">
+ <bool>false</bool>
+ </property>
+ <property name="flat">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QToolButton" name="optionsButton">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Fixed">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>...</string>
+ </property>
+ <property name="icon">
+ <iconset resource="../gpgfrontend.qrc">
+ <normaloff>:/configure.png</normaloff>:/configure.png</iconset>
+ </property>
+ <property name="popupMode">
+ <enum>QToolButton::MenuButtonPopup</enum>
+ </property>
+ <property name="toolButtonStyle">
+ <enum>Qt::ToolButtonIconOnly</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="QTreeView" name="fileTreeView">
+ <property name="contextMenuPolicy">
+ <enum>Qt::CustomContextMenu</enum>
+ </property>
+ <property name="acceptDrops">
+ <bool>true</bool>
+ </property>
+ <property name="autoFillBackground">
+ <bool>false</bool>
+ </property>
+ <property name="uniformRowHeights">
+ <bool>true</bool>
+ </property>
+ <property name="sortingEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="animated">
+ <bool>true</bool>
+ </property>
+ <attribute name="headerCascadingSectionResizes">
+ <bool>true</bool>
+ </attribute>
+ <attribute name="headerShowSortIndicator" stdset="0">
+ <bool>true</bool>
+ </attribute>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources>
+ <include location="../gpgfrontend.qrc"/>
+ </resources>
+ <connections/>
+</ui>
diff --git a/ui/InfoBoard.ui b/ui/InfoBoard.ui
new file mode 100644
index 00000000..1aac29aa
--- /dev/null
+++ b/ui/InfoBoard.ui
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>InfoBoard</class>
+ <widget class="QWidget" name="InfoBoard">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>788</width>
+ <height>604</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Form</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item>
+ <widget class="QTextEdit" name="infoBoard">
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="horizontalLayout_4">
+ <property name="sizeConstraint">
+ <enum>QLayout::SetNoConstraint</enum>
+ </property>
+ <item alignment="Qt::AlignLeft">
+ <widget class="QWidget" name="horizontalWidget" native="true">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Minimum" vsizetype="Minimum">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <property name="spacing">
+ <number>5</number>
+ </property>
+ <property name="sizeConstraint">
+ <enum>QLayout::SetNoConstraint</enum>
+ </property>
+ <property name="leftMargin">
+ <number>0</number>
+ </property>
+ <property name="topMargin">
+ <number>0</number>
+ </property>
+ <property name="rightMargin">
+ <number>0</number>
+ </property>
+ <property name="bottomMargin">
+ <number>0</number>
+ </property>
+ <item alignment="Qt::AlignLeft">
+ <widget class="QLabel" name="actionLabel">
+ <property name="text">
+ <string>Actions</string>
+ </property>
+ <property name="scaledContents">
+ <bool>false</bool>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignRight">
+ <widget class="QPushButton" name="copyButton">
+ <property name="text">
+ <string>Copy</string>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignRight">
+ <widget class="QPushButton" name="saveButton">
+ <property name="text">
+ <string>Save</string>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignRight|Qt::AlignBottom">
+ <widget class="QPushButton" name="clearButton">
+ <property name="text">
+ <string>Clear</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <layout class="QHBoxLayout" name="actionButtonLayout"/>
+ </item>
+ </layout>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/KeyDeatils.ui b/ui/KeyDeatils.ui
new file mode 100644
index 00000000..c9a7421d
--- /dev/null
+++ b/ui/KeyDeatils.ui
@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>KeyDeatilsDialog</class>
+ <widget class="QDialog" name="KeyDeatilsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>423</width>
+ <height>616</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="tabPosition">
+ <enum>QTabWidget::North</enum>
+ </property>
+ <property name="currentIndex">
+ <number>0</number>
+ </property>
+ <property name="documentMode">
+ <bool>true</bool>
+ </property>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Tab 1</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>Tab 2</string>
+ </attribute>
+ </widget>
+ </widget>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>
diff --git a/ui/VerifyDetails.ui b/ui/VerifyDetails.ui
new file mode 100644
index 00000000..3f88984d
--- /dev/null
+++ b/ui/VerifyDetails.ui
@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>VerifyDetailsDialog</class>
+ <widget class="QDialog" name="VerifyDetailsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>635</width>
+ <height>829</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Dialog</string>
+ </property>
+ <layout class="QGridLayout" name="gridLayout">
+ <item row="0" column="0">
+ <layout class="QVBoxLayout" name="verticalLayout">
+ <item alignment="Qt::AlignTop">
+ <widget class="QWidget" name="horizontalWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout">
+ <item alignment="Qt::AlignTop">
+ <widget class="QLabel" name="titleLabel">
+ <property name="text">
+ <string>Verify Details</string>
+ </property>
+ <property name="textFormat">
+ <enum>Qt::AutoText</enum>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignTop">
+ <widget class="QWidget" name="verticalWidget_2" native="true">
+ <layout class="QVBoxLayout" name="verticalLayout_2">
+ <item alignment="Qt::AlignTop">
+ <widget class="QWidget" name="horizontalWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_2">
+ <item alignment="Qt::AlignLeft|Qt::AlignTop">
+ <widget class="QLabel" name="label">
+ <property name="text">
+ <string>Date: </string>
+ </property>
+ </widget>
+ </item>
+ <item alignment="Qt::AlignTop">
+ <widget class="QLabel" name="label_2">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QWidget" name="horizontalWidget" native="true">
+ <layout class="QHBoxLayout" name="horizontalLayout_3">
+ <item alignment="Qt::AlignLeft">
+ <widget class="QLabel" name="label_5">
+ <property name="text">
+ <string>Status: </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_4">
+ <property name="sizePolicy">
+ <sizepolicy hsizetype="Expanding" vsizetype="Preferred">
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>TextLabel</string>
+ </property>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ </layout>
+ </widget>
+ </item>
+ <item>
+ <widget class="QLabel" name="label_3">
+ <property name="text">
+ <string>Signer(s) List: </string>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTabWidget" name="tabWidget">
+ <property name="currentIndex">
+ <number>1</number>
+ </property>
+ <widget class="QWidget" name="tab">
+ <attribute name="title">
+ <string>Tab 1</string>
+ </attribute>
+ </widget>
+ <widget class="QWidget" name="tab_2">
+ <attribute name="title">
+ <string>Tab 2</string>
+ </attribute>
+ </widget>
+ </widget>
+ </item>
+ <item>
+ <widget class="Line" name="line_2">
+ <property name="orientation">
+ <enum>Qt::Horizontal</enum>
+ </property>
+ </widget>
+ </item>
+ <item>
+ <spacer name="verticalSpacer">
+ <property name="orientation">
+ <enum>Qt::Vertical</enum>
+ </property>
+ <property name="sizeHint" stdset="0">
+ <size>
+ <width>20</width>
+ <height>40</height>
+ </size>
+ </property>
+ </spacer>
+ </item>
+ </layout>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections/>
+</ui>