From 3d242d6bc043ddd60d468394dda1167d1579f3ae Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Thu, 14 Apr 2022 21:47:13 +0200 Subject: [PATCH 01/15] Adding global message boxes Added files for global messageboxes with the main dialog as parent and with a standardized title. In headless mode the messages will be shown on terminal instead. (Also added myself to contributors list) --- Jamulus.pro | 2 ++ src/main.cpp | 27 +++++++++++++--------- src/messages.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/messages.h | 46 ++++++++++++++++++++++++++++++++++++++ src/util.cpp | 1 + 5 files changed, 123 insertions(+), 11 deletions(-) create mode 100644 src/messages.cpp create mode 100644 src/messages.h diff --git a/Jamulus.pro b/Jamulus.pro index a6d8dbc05c..8cf5bc1a12 100644 --- a/Jamulus.pro +++ b/Jamulus.pro @@ -359,6 +359,7 @@ FORMS_GUI = src/aboutdlgbase.ui \ HEADERS += src/buffer.h \ src/channel.h \ src/global.h \ + src/messages.h \ src/protocol.h \ src/recorder/jamcontroller.h \ src/threadpool.h \ @@ -470,6 +471,7 @@ HEADERS_OPUS_X86 = libs/opus/celt/x86/celt_lpc_sse.h \ SOURCES += src/buffer.cpp \ src/channel.cpp \ src/main.cpp \ + src/messages.cpp \ src/protocol.cpp \ src/recorder/jamcontroller.cpp \ src/server.cpp \ diff --git a/src/main.cpp b/src/main.cpp index 0bc792376b..88ad252e38 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,9 +26,9 @@ #include #include #include "global.h" +#include "messages.h" #ifndef HEADLESS # include -# include # include "serverdlg.h" # ifndef SERVER_ONLY # include "clientdlg.h" @@ -901,6 +901,9 @@ int main ( int argc, char** argv ) bEnableIPv6, nullptr ); + // initialise message boxes + CMessages::init ( &ClientDlg, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + // show dialog ClientDlg.show(); pApp->exec(); @@ -911,6 +914,9 @@ int main ( int argc, char** argv ) // only start application without using the GUI qInfo() << qUtf8Printable ( GetVersionAndNameStr ( false ) ); + // initialise message boxes + CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + pApp->exec(); } } @@ -961,6 +967,9 @@ int main ( int argc, char** argv ) // GUI object for the server CServerDlg ServerDlg ( &Server, &Settings, bStartMinimized, nullptr ); + // initialise message boxes + CMessages::init ( &ServerDlg, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + // show dialog (if not the minimized flag is set) if ( !bStartMinimized ) { @@ -982,6 +991,9 @@ int main ( int argc, char** argv ) Server.SetDirectoryType ( AT_CUSTOM ); } + // initialise message boxes + CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + pApp->exec(); } } @@ -990,17 +1002,10 @@ int main ( int argc, char** argv ) catch ( const CGenErr& generr ) { // show generic error -#ifndef HEADLESS - if ( bUseGUI ) - { - QMessageBox::critical ( nullptr, APP_NAME, generr.GetErrorText(), "Quit", nullptr ); - } - else + CMessages::ShowError ( generr.GetErrorText() ); +#ifdef HEADLESS + exit ( 1 ); #endif - { - qCritical() << qUtf8Printable ( QString ( "%1: %2" ).arg ( APP_NAME ).arg ( generr.GetErrorText() ) ); - exit ( 1 ); - } } #if defined( Q_OS_MACX ) diff --git a/src/messages.cpp b/src/messages.cpp new file mode 100644 index 0000000000..c98a9e0590 --- /dev/null +++ b/src/messages.cpp @@ -0,0 +1,58 @@ +/******************************************************************************\ + * Copyright (c) 2022 + * + * Author(s): + * Peter Goderie (pgScorpio) + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * +\******************************************************************************/ + +#include "messages.h" + +tMainform* CMessages::pMainForm = NULL; +QString CMessages::strMainFormName; + +/******************************************************************************\ +* Message Boxes * +\******************************************************************************/ +void CMessages::ShowError ( QString strError ) +{ +#ifndef HEADLESS + QMessageBox::critical ( pMainForm, strMainFormName + ": " + QObject::tr ( "Error" ), strError, QObject::tr ( "Ok" ), nullptr ); +#else + qCritical() << "Error: " << strError.toLocal8Bit().data(); +#endif +} + +void CMessages::ShowWarning ( QString strWarning ) +{ +#ifndef HEADLESS + QMessageBox::warning ( pMainForm, strMainFormName + ": " + QObject::tr ( "Warning" ), strWarning, QObject::tr ( "Ok" ), nullptr ); +#else + qWarning() << "Warning: " << strWarning.toLocal8Bit().data(); +#endif +} + +void CMessages::ShowInfo ( QString strInfo ) +{ +#ifndef HEADLESS + QMessageBox::information ( pMainForm, strMainFormName + ": " + QObject::tr ( "Information" ), strInfo, QObject::tr ( "Ok" ), nullptr ); +#else + qInfo() << "Info: " << strInfo.toLocal8Bit().data(); +#endif +} diff --git a/src/messages.h b/src/messages.h new file mode 100644 index 0000000000..ac0c7de0d3 --- /dev/null +++ b/src/messages.h @@ -0,0 +1,46 @@ +#pragma once + +/******************************************************************************\ + * Copyright (c) 2022 + * Author(s): + * Peter Goderie (pgScorpio) + * + * Use this static class to show basic Error, Warning and Info messages + * + * For own created special message boxes you should always use + * CMessages::MainForm() as parent parameter + * and CMessages::MainFormName() as base of the title parameter +\******************************************************************************/ + +#include +#ifndef HEADLESS +# include +# define tMainform QDialog +#else +# define tMainform void +#endif + +// html text macro's (for use in message texts) +#define htmlBold( T ) "" + T + "" +#define htmlNewLine() "
" + +class CMessages +{ +protected: + static tMainform* pMainForm; + static QString strMainFormName; + +public: + static void init ( tMainform* theMainForm, QString theMainFormName ) + { + pMainForm = theMainForm; + strMainFormName = theMainFormName; + } + + static tMainform* MainForm() { return pMainForm; } + static const QString& MainFormName() { return strMainFormName; } + + static void ShowError ( QString strError ); + static void ShowWarning ( QString strWarning ); + static void ShowInfo ( QString strInfo ); +}; diff --git a/src/util.cpp b/src/util.cpp index d2f7d6f78b..820c758de8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -495,6 +495,7 @@ CAboutDlg::CAboutDlg ( QWidget* parent ) : CBaseDlg ( parent ) "

RobyDati (RobyDati)

" "

Rob-NY (Rob-NY)

" "

Thai Pangsakulyanont (dtinth)

" + "

Peter Goderie (pgScorpio)

" "
" + tr ( "For details on the contributions check out the %1" ) .arg ( "" + tr ( "Github Contributors list" ) + "." ) ); From eee5c8b7f6c2f12cff668cea30ffa24b39b15937 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Thu, 14 Apr 2022 21:47:13 +0200 Subject: [PATCH 02/15] Adding global message boxes Added files for global messageboxes with the main dialog as parent and with a standardized title. In headless mode the messages will be shown on terminal instead. (Also added myself to contributors list) --- Jamulus.pro | 2 ++ src/main.cpp | 27 +++++++++++++--------- src/messages.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/messages.h | 47 +++++++++++++++++++++++++++++++++++++++ src/util.cpp | 1 + 5 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 src/messages.cpp create mode 100644 src/messages.h diff --git a/Jamulus.pro b/Jamulus.pro index a6d8dbc05c..8cf5bc1a12 100644 --- a/Jamulus.pro +++ b/Jamulus.pro @@ -359,6 +359,7 @@ FORMS_GUI = src/aboutdlgbase.ui \ HEADERS += src/buffer.h \ src/channel.h \ src/global.h \ + src/messages.h \ src/protocol.h \ src/recorder/jamcontroller.h \ src/threadpool.h \ @@ -470,6 +471,7 @@ HEADERS_OPUS_X86 = libs/opus/celt/x86/celt_lpc_sse.h \ SOURCES += src/buffer.cpp \ src/channel.cpp \ src/main.cpp \ + src/messages.cpp \ src/protocol.cpp \ src/recorder/jamcontroller.cpp \ src/server.cpp \ diff --git a/src/main.cpp b/src/main.cpp index 0bc792376b..88ad252e38 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,9 +26,9 @@ #include #include #include "global.h" +#include "messages.h" #ifndef HEADLESS # include -# include # include "serverdlg.h" # ifndef SERVER_ONLY # include "clientdlg.h" @@ -901,6 +901,9 @@ int main ( int argc, char** argv ) bEnableIPv6, nullptr ); + // initialise message boxes + CMessages::init ( &ClientDlg, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + // show dialog ClientDlg.show(); pApp->exec(); @@ -911,6 +914,9 @@ int main ( int argc, char** argv ) // only start application without using the GUI qInfo() << qUtf8Printable ( GetVersionAndNameStr ( false ) ); + // initialise message boxes + CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + pApp->exec(); } } @@ -961,6 +967,9 @@ int main ( int argc, char** argv ) // GUI object for the server CServerDlg ServerDlg ( &Server, &Settings, bStartMinimized, nullptr ); + // initialise message boxes + CMessages::init ( &ServerDlg, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + // show dialog (if not the minimized flag is set) if ( !bStartMinimized ) { @@ -982,6 +991,9 @@ int main ( int argc, char** argv ) Server.SetDirectoryType ( AT_CUSTOM ); } + // initialise message boxes + CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + pApp->exec(); } } @@ -990,17 +1002,10 @@ int main ( int argc, char** argv ) catch ( const CGenErr& generr ) { // show generic error -#ifndef HEADLESS - if ( bUseGUI ) - { - QMessageBox::critical ( nullptr, APP_NAME, generr.GetErrorText(), "Quit", nullptr ); - } - else + CMessages::ShowError ( generr.GetErrorText() ); +#ifdef HEADLESS + exit ( 1 ); #endif - { - qCritical() << qUtf8Printable ( QString ( "%1: %2" ).arg ( APP_NAME ).arg ( generr.GetErrorText() ) ); - exit ( 1 ); - } } #if defined( Q_OS_MACX ) diff --git a/src/messages.cpp b/src/messages.cpp new file mode 100644 index 0000000000..c98a9e0590 --- /dev/null +++ b/src/messages.cpp @@ -0,0 +1,58 @@ +/******************************************************************************\ + * Copyright (c) 2022 + * + * Author(s): + * Peter Goderie (pgScorpio) + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * +\******************************************************************************/ + +#include "messages.h" + +tMainform* CMessages::pMainForm = NULL; +QString CMessages::strMainFormName; + +/******************************************************************************\ +* Message Boxes * +\******************************************************************************/ +void CMessages::ShowError ( QString strError ) +{ +#ifndef HEADLESS + QMessageBox::critical ( pMainForm, strMainFormName + ": " + QObject::tr ( "Error" ), strError, QObject::tr ( "Ok" ), nullptr ); +#else + qCritical() << "Error: " << strError.toLocal8Bit().data(); +#endif +} + +void CMessages::ShowWarning ( QString strWarning ) +{ +#ifndef HEADLESS + QMessageBox::warning ( pMainForm, strMainFormName + ": " + QObject::tr ( "Warning" ), strWarning, QObject::tr ( "Ok" ), nullptr ); +#else + qWarning() << "Warning: " << strWarning.toLocal8Bit().data(); +#endif +} + +void CMessages::ShowInfo ( QString strInfo ) +{ +#ifndef HEADLESS + QMessageBox::information ( pMainForm, strMainFormName + ": " + QObject::tr ( "Information" ), strInfo, QObject::tr ( "Ok" ), nullptr ); +#else + qInfo() << "Info: " << strInfo.toLocal8Bit().data(); +#endif +} diff --git a/src/messages.h b/src/messages.h new file mode 100644 index 0000000000..9982f9409c --- /dev/null +++ b/src/messages.h @@ -0,0 +1,47 @@ +#pragma once + +/******************************************************************************\ + * Copyright (c) 2022 + * Author(s): + * Peter Goderie (pgScorpio) + * + * Use this static class to show basic Error, Warning and Info messages + * + * For own created special message boxes you should always use + * CMessages::MainForm() as parent parameter + * and CMessages::MainFormName() as base of the title parameter +\******************************************************************************/ + +#include +#ifndef HEADLESS +# include +# define tMainform QDialog +#else +# include +# define tMainform void +#endif + +// html text macro's (for use in message texts) +#define htmlBold( T ) "" + T + "" +#define htmlNewLine() "
" + +class CMessages +{ +protected: + static tMainform* pMainForm; + static QString strMainFormName; + +public: + static void init ( tMainform* theMainForm, QString theMainFormName ) + { + pMainForm = theMainForm; + strMainFormName = theMainFormName; + } + + static tMainform* MainForm() { return pMainForm; } + static const QString& MainFormName() { return strMainFormName; } + + static void ShowError ( QString strError ); + static void ShowWarning ( QString strWarning ); + static void ShowInfo ( QString strInfo ); +}; diff --git a/src/util.cpp b/src/util.cpp index d2f7d6f78b..820c758de8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -495,6 +495,7 @@ CAboutDlg::CAboutDlg ( QWidget* parent ) : CBaseDlg ( parent ) "

RobyDati (RobyDati)

" "

Rob-NY (Rob-NY)

" "

Thai Pangsakulyanont (dtinth)

" + "

Peter Goderie (pgScorpio)

" "
" + tr ( "For details on the contributions check out the %1" ) .arg ( "" + tr ( "Github Contributors list" ) + "." ) ); From 7a1fffbb18fbb93519db08643f7be3ff3cd18f77 Mon Sep 17 00:00:00 2001 From: Christian Hoffmann Date: Thu, 24 Mar 2022 00:02:43 +0100 Subject: [PATCH 03/15] mac/deploy_may.sh: Replace eval magic by explicit variables The previous logic used eval to dynamically create variables. This is hard to follow. Instead, explicitly name the relevant two variables. Also, introduce readable variable names. Related: #2474 --- mac/deploy_mac.sh | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/mac/deploy_mac.sh b/mac/deploy_mac.sh index 58ec0b6c43..175641f586 100755 --- a/mac/deploy_mac.sh +++ b/mac/deploy_mac.sh @@ -41,6 +41,8 @@ cleanup() build_app() { + local client_or_server="${1}" + # Build Jamulus qmake "${project_path}" -o "${build_path}/Makefile" "CONFIG+=release" ${@:2} local target_name=$(sed -nE 's/^QMAKE_TARGET *= *(.*)$/\1/p' "${build_path}/Makefile") @@ -60,12 +62,25 @@ build_app() make -f "${build_path}/Makefile" -C "${build_path}" distclean # Return app name for installer image - eval "$1=${target_name}" + case "${client_or_server}" in + client_app) + CLIENT_TARGET_NAME="${target_name}" + ;; + server_app) + SERVER_TARGET_NAME="${target_name}" + ;; + *) + echo "build_app: invalid parameter '${client_or_server}'" + exit 1 + esac } build_installer_image() { + local client_target_name="${1}" + local server_target_name="${2}" + # Install create-dmg via brew. brew needs to be installed first. # Download and later install. This is done to make caching possible brew_install_pinned "create-dmg" "1.0.9" @@ -76,17 +91,17 @@ build_installer_image() # Build installer image create-dmg \ - --volname "${1} Installer" \ + --volname "${client_target_name} Installer" \ --background "${resources_path}/installerbackground.png" \ --window-pos 200 400 \ --window-size 900 320 \ --app-drop-link 820 210 \ --text-size 12 \ --icon-size 72 \ - --icon "${1}.app" 630 210 \ - --icon "${2}.app" 530 210 \ + --icon "${client_target_name}.app" 630 210 \ + --icon "${server_target_name}.app" 530 210 \ --eula "${root_path}/COPYING" \ - "${deploy_path}/$1-${app_version}-installer-mac.dmg" \ + "${deploy_path}/${client_target_name}-${app_version}-installer-mac.dmg" \ "${deploy_path}/" } @@ -132,4 +147,4 @@ build_app client_app build_app server_app "CONFIG+=server_bundle" # Create versioned installer image -build_installer_image "${client_app}" "${server_app}" +build_installer_image "${CLIENT_TARGET_NAME}" "${SERVER_TARGET_NAME}" From 00924c3d9315ed8b7f3f8a98e4d28854019a9da9 Mon Sep 17 00:00:00 2001 From: Christian Hoffmann Date: Thu, 24 Mar 2022 00:04:57 +0100 Subject: [PATCH 04/15] Scripts: Apply shellcheck suggestions Some suggestions do not apply. For those, a comment is added to disable the check and explain why shellcheck cannot properly judge it. Related: #2474 --- linux/deploy_deb.sh | 2 +- mac/deploy_mac.sh | 55 +++++++++---------- tools/changelog-helper.sh | 67 ++++++++++++++++-------- tools/check-wininstaller-translations.sh | 14 +++-- tools/create-translation-issues.sh | 13 +++-- tools/update-copyright-notices.sh | 5 +- 6 files changed, 91 insertions(+), 65 deletions(-) diff --git a/linux/deploy_deb.sh b/linux/deploy_deb.sh index e59ad7e23d..475463f5b7 100755 --- a/linux/deploy_deb.sh +++ b/linux/deploy_deb.sh @@ -16,7 +16,7 @@ export DEBFULLNAME=GitHubActions DEBEMAIL=noemail@example.com echo -n generating changelog rm -f debian/changelog dch --create --package jamulus --empty --newversion "${VERSION}" '' -perl .github/actions_scripts/getChangelog.pl ChangeLog "${VERSION}" --line-per-entry | while read entry +perl .github/actions_scripts/getChangelog.pl ChangeLog "${VERSION}" --line-per-entry | while read -r entry do echo -n . dch "$entry" diff --git a/mac/deploy_mac.sh b/mac/deploy_mac.sh index 175641f586..9a4514f379 100755 --- a/mac/deploy_mac.sh +++ b/mac/deploy_mac.sh @@ -1,31 +1,28 @@ #!/bin/bash -set -e +set -eu -root_path="$(pwd)" +root_path=$(pwd) project_path="${root_path}/Jamulus.pro" resources_path="${root_path}/src/res" build_path="${root_path}/build" deploy_path="${root_path}/deploy" cert_name="" - while getopts 'hs:' flag; do case "${flag}" in - s) - cert_name=$OPTARG - if [[ -z "$cert_name" ]]; then - echo "Please add the name of the certificate to use: -s \"\"" - fi - # shift 2 - ;; - h) - echo "Usage: -s for signing mac build" - exit 0 - ;; - *) - exit 1 - ;; - + s) + cert_name=$OPTARG + if [[ -z "$cert_name" ]]; then + echo "Please add the name of the certificate to use: -s \"\"" + fi + ;; + h) + echo "Usage: -s for signing mac build" + exit 0 + ;; + *) + exit 1 + ;; esac done @@ -44,9 +41,11 @@ build_app() local client_or_server="${1}" # Build Jamulus - qmake "${project_path}" -o "${build_path}/Makefile" "CONFIG+=release" ${@:2} - local target_name=$(sed -nE 's/^QMAKE_TARGET *= *(.*)$/\1/p' "${build_path}/Makefile") - local job_count="$(sysctl -n hw.ncpu)" + qmake "${project_path}" -o "${build_path}/Makefile" "CONFIG+=release" "${@:2}" + local target_name + target_name=$(sed -nE 's/^QMAKE_TARGET *= *(.*)$/\1/p' "${build_path}/Makefile") + local job_count + job_count=$(sysctl -n hw.ncpu) make -f "${build_path}/Makefile" -C "${build_path}" -j "${job_count}" @@ -75,7 +74,6 @@ build_app() esac } - build_installer_image() { local client_target_name="${1}" @@ -86,7 +84,8 @@ build_installer_image() brew_install_pinned "create-dmg" "1.0.9" # Get Jamulus version - local app_version="$(sed -nE 's/^VERSION *= *(.*)$/\1/p' "${project_path}")" + local app_version + app_version=$(sed -nE 's/^VERSION *= *(.*)$/\1/p' "${project_path}") # Build installer image @@ -103,7 +102,6 @@ build_installer_image() --eula "${root_path}/COPYING" \ "${deploy_path}/${client_target_name}-${app_version}-installer-mac.dmg" \ "${deploy_path}/" - } brew_install_pinned() { @@ -129,16 +127,13 @@ brew_install_pinned() { popd } - # Check that we are running from the correct location -if [ ! -f "${project_path}" ]; -then - echo Please run this script from the Qt project directory where $(basename "${project_path}") is located. - echo Usage: mac/$(basename "${0}") +if [[ ! -f "${project_path}" ]]; then + echo "Please run this script from the Qt project directory where $(basename "${project_path}") is located." + echo "Usage: mac/$(basename "${0}")" exit 1 fi - # Cleanup previous deployments cleanup diff --git a/tools/changelog-helper.sh b/tools/changelog-helper.sh index 0bc0b22aac..abdc8319e6 100755 --- a/tools/changelog-helper.sh +++ b/tools/changelog-helper.sh @@ -29,8 +29,10 @@ declare -A LANGS=( ) find_or_add_missing_entries() { - local changelog=$(sed -rne '/^###.*'"${target_release//./\.}"'\b/,/^### '"${prev_release//./\.}"'\b/p' ChangeLog) - local changelog_begin_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n1 | cut -d: -f1) + local changelog + changelog=$(sed -rne '/^###.*'"${target_release//./\.}"'\b/,/^### '"${prev_release//./\.}"'\b/p' ChangeLog) + local changelog_begin_position + changelog_begin_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n1 | cut -d: -f1) echo "Checking if all merged Github PRs since ${prev_release} are included for ${target_release}..." for id in $(gh pr list --limit "${PR_LIST_LIMIT}" --search 'milestone:"Release '"${target_release}"'"' --state merged | awk '{print $1}'); do @@ -57,17 +59,22 @@ find_or_add_missing_entries() { } group_entries() { - local changelog_begin_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n1 | cut -d: -f1) - local changelog_prev_release_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n2 | tail -n1 | cut -d: -f1) + local changelog_begin_position + changelog_begin_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n1 | cut -d: -f1) + local changelog_prev_release_position + changelog_prev_release_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n2 | tail -n1 | cut -d: -f1) # Save everything before the actual release changelog content: - local changelog_header=$(head -n "${changelog_begin_position}" ChangeLog) + local changelog_header + changelog_header=$(head -n "${changelog_begin_position}" ChangeLog) # Save everything after the actual release changelog content: - local changelog_prev_releases=$(tail -n "+${changelog_prev_release_position}" ChangeLog) + local changelog_prev_releases + changelog_prev_releases=$(tail -n "+${changelog_prev_release_position}" ChangeLog) # Save the current release's changelog content: - local changelog=$(sed -rne '/^###.*'"${target_release//./\.}"'\b/,/^### '"${prev_release//./\.}"'\b/p' ChangeLog | tail -n +2 | head -n -1) + local changelog + changelog=$(sed -rne '/^###.*'"${target_release//./\.}"'\b/,/^### '"${prev_release//./\.}"'\b/p' ChangeLog | tail -n +2 | head -n -1) # Remove trailing whitespace on all lines of the current changelog: changelog=$(sed -re 's/\s+$//' <<<"$changelog") @@ -100,7 +107,7 @@ group_entries() { local index=0 for category in "${category_order[@]}"; do changelog=$(sed -re 's/^(- '"${category}"')/'"${index}"' \1/' <<<"${changelog}") - index=$(($index+1)) + index=$((index+1)) done # Reduce blocks ("entries") to a single line by replacing \n with \v. @@ -131,15 +138,21 @@ check_or_add_pr() { # (\> ensures that we only match full, standalone IDs) return fi - local json=$(gh pr view "${id/#/}" --json title,author,state) - local state=$(jq -r .state <<<"${json}") - local title=$(jq -r .title <<<"${json}" | sanitize_title) - local author=$(jq -r .author.login <<<"${json}") + local json + json=$(gh pr view "${id/#/}" --json title,author,state) + local state + state=$(jq -r .state <<<"${json}") + local title + title=$(jq -r .title <<<"${json}" | sanitize_title) + local author + author=$(jq -r .author.login <<<"${json}") if [[ "${state}" != "MERGED" ]]; then echo "-> Ignoring PR #${id} as state ${state} != MERGED" return fi - local title_suggestion_in_pr=$(gh pr view "$id" --json body,comments,reviews --jq '(.body), (.comments[] .body), (.reviews[] .body)' | grep -oP '\bCHANGELOG:\s*\K([^\\]{5,})' | tail -n1 | sanitize_title) + local title_suggestion_in_pr + title_suggestion_in_pr=$(gh pr view "$id" --json body,comments,reviews --jq '(.body), (.comments[] .body), (.reviews[] .body)' | + grep -oP '\bCHANGELOG:\s*\K([^\\]{5,})' | tail -n1 | sanitize_title) if [[ "${title_suggestion_in_pr}" ]]; then title="${title_suggestion_in_pr}" if [[ "${title_suggestion_in_pr}" == "SKIP" ]]; then @@ -153,7 +166,8 @@ check_or_add_pr() { fi echo ", adding new entry" local new_entry="" - local lang=$(grep -oP 'Updated? \K(\S+)(?= app translations? for )' <<<"$title" || true) + local lang + lang=$(grep -oP 'Updated? \K(\S+)(?= app translations? for )' <<<"$title" || true) if [[ "${lang}" ]]; then # Note: This creates a top-level entry for each language. # group-entries can merge those to a single one. @@ -165,8 +179,10 @@ check_or_add_pr() { echo "- ${title} (#${id})." echo " (contributed by @${author})" ) - local changelog_before=$(head -n "${changelog_begin_position}" ChangeLog) - local changelog_after=$(tail -n "+$((${changelog_begin_position}+1))" ChangeLog) + local changelog_before + changelog_before=$(head -n "${changelog_begin_position}" ChangeLog) + local changelog_after + changelog_after=$(tail -n "+$((changelog_begin_position+1))" ChangeLog) (echo "$changelog_before"; echo; echo "$new_entry"; echo "$changelog_after") > ChangeLog } @@ -174,17 +190,22 @@ add_translation_pr() { local lang="${1}" local author="${2}" local id="${3}" - local changelog_begin_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n1 | cut -d: -f1) - local changelog_prev_release_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n2 | tail -n1 | cut -d: -f1) + local changelog_begin_position + changelog_begin_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n1 | cut -d: -f1) + local changelog_prev_release_position + changelog_prev_release_position=$(grep -nP '^### .*\d+\.\d+\.\d+\b' ChangeLog | head -n2 | tail -n1 | cut -d: -f1) # Save everything before the actual release changelog content: - local changelog_header=$(head -n "${changelog_begin_position}" ChangeLog) + local changelog_header + changelog_header=$(head -n "${changelog_begin_position}" ChangeLog) # Save everything after the actual release changelog content: - local changelog_prev_releases=$(tail -n "+${changelog_prev_release_position}" ChangeLog) + local changelog_prev_releases + changelog_prev_releases=$(tail -n "+${changelog_prev_release_position}" ChangeLog) # Save the current release's changelog content: - local changelog=$(sed -rne '/^###.*'"${target_release//./\.}"'\b/,/^### '"${prev_release//./\.}"'\b/p' ChangeLog | tail -n +2 | head -n -1) + local changelog + changelog=$(sed -rne '/^###.*'"${target_release//./\.}"'\b/,/^### '"${prev_release//./\.}"'\b/p' ChangeLog | tail -n +2 | head -n -1) local changelog_orig="${changelog}" # Is there an existing entry for this language already? @@ -227,12 +248,12 @@ add_translation_pr() { changelog_after_translations="${changelog_after_translations}${line}"$'\n' fi done <<< "${changelog}" - changelog="$( + changelog=$( # echo -n strips whitespace. we need that here. echo -n "${changelog_before_translations}" echo -n "$(grep -vP '^$' <<< "${changelog_translations}" | sort)" echo -n "${changelog_after_translations}" - )" + ) fi fi # Rebuild the changelog and write back to file: diff --git a/tools/check-wininstaller-translations.sh b/tools/check-wininstaller-translations.sh index c72782ed8e..ff7ca8b545 100755 --- a/tools/check-wininstaller-translations.sh +++ b/tools/check-wininstaller-translations.sh @@ -6,12 +6,16 @@ BASE_LANG=en INSTALLERLNG=installerlng.nsi BASE_LANGSTRINGS=$(grep LangString "${BASE_DIR}/${BASE_LANG}.nsi" | cut -d' ' -f2) EXIT=0 -LANGUAGE_FILES="$(ls -1 src/res/translation/wininstaller/{??.nsi,??_??.nsi} | grep -vF "${BASE_LANG}.nsi")" -for LANGUAGE_FILE in ${LANGUAGE_FILES}; do +for LANGUAGE_FILE in src/res/translation/wininstaller/{??.nsi,??_??.nsi}; do + if [[ ${LANGUAGE_FILE} =~ /${BASE_LANG}.nsi$ ]]; then + continue + fi echo echo "* ${LANGUAGE_FILE}" echo -n " - Checking language file is included in ${INSTALLERLNG}... " - if grep -q '^!include "\${ROOT_PATH}\\'$(sed -re 's|/|\\\\|g' <<<"${LANGUAGE_FILE}")'"' "${BASE_DIR}/${INSTALLERLNG}"; then + # shellcheck disable=SC2016 # shellcheck is confused here as NSI files use variables which look like shell variables + # shellcheck disable=SC1003 # shellcheck misinterprets the verbatim backslash as an attempt to escape the single quote. it's not. + if grep -q '^!include "\${ROOT_PATH}\\'"$(sed -re 's|/|\\\\|g' <<<"${LANGUAGE_FILE}")"'"' "${BASE_DIR}/${INSTALLERLNG}"; then echo "ok" else echo "ERROR" @@ -35,7 +39,7 @@ for LANGUAGE_FILE in ${LANGUAGE_FILES}; do fi echo -n " - Checking for wrong macros... " - LANG_MACROS="$(grep -oP '\$\{LANG_[^}]+\}' "${LANGUAGE_FILE}")" + LANG_MACROS=$(grep -oP '\$\{LANG_[^}]+\}' "${LANGUAGE_FILE}") if grep ENGLISH <<<"$LANG_MACROS"; then echo "ERROR, found LANG_ENGLISH" EXIT=1 @@ -52,7 +56,7 @@ for LANGUAGE_FILE in ${LANGUAGE_FILES}; do fi echo -n " - Checking if LANG_ macro is in ${INSTALLERLNG}..." - LANG_NAME="$(sort -u <<<"${LANG_MACROS}" | sed -rne 's/\$\{LANG_(.*)\}/\1/p')" + LANG_NAME=$(sort -u <<<"${LANG_MACROS}" | sed -rne 's/\$\{LANG_(.*)\}/\1/p') if grep -qi '^!insertmacro MUI_LANGUAGE "'"${LANG_NAME}"'"' "$BASE_DIR/${INSTALLERLNG}"; then echo "ok" else diff --git a/tools/create-translation-issues.sh b/tools/create-translation-issues.sh index 0fd7469b7b..5a4b0d904d 100755 --- a/tools/create-translation-issues.sh +++ b/tools/create-translation-issues.sh @@ -64,6 +64,7 @@ declare -A TRANSLATORS_BY_LANG=( [web_pt]="Snayler,melcon,ewarning" ) +# shellcheck disable=SC2016 # shellcheck can't know that this will be used with envsubst, so verbatim variables are correct here. BODY_TEMPLATE_APP='Hi ${SPLIT_TRANSLATORS}, We are getting ready for the ${RELEASE} release. No further changes to translatable strings are currently planned for this release. @@ -89,6 +90,7 @@ Further documentation can be found in [TRANSLATING.md](https://github.com/jamulu Thanks for contributing to Jamulus!' +# shellcheck disable=SC2016 # shellcheck can't know that this will be used with envsubst, so verbatim variables are correct here. BODY_TEMPLATE_WEB='Hi ${SPLIT_TRANSLATORS}, We are getting ready for the ${RELEASE} release and have created the [${TRANSLATE_BRANCH}](https://github.com/jamulussoftware/jamuluswebsite/tree/${TRANSLATE_BRANCH}) branch ([full diff](https://github.com/jamulussoftware/jamuluswebsite/compare/release..${TRANSLATE_BRANCH})). @@ -149,7 +151,7 @@ get_languages() { echo "Error: Please ensure that you are at the root of a jamuluswebsite checkout" >/dev/stderr exit 1 fi - for LANG in $(cd _translator-files/po/ && ls -d *); do + for LANG in $(cd _translator-files/po/ && ls -d -- *); do [[ -d _translator-files/po/$LANG ]] || continue [[ $LANG == en ]] && continue # does not have to be translated echo "$LANG" @@ -184,7 +186,8 @@ create_translation_issue_for_lang() { multiple_translators_text="" [[ $translators == *,* ]] && multiple_translators_text=$'\n\n''This Issue is assigned to multiple people. Please coordinate who will translate what part.' [[ $TYPE == app ]] && body_template="$BODY_TEMPLATE_APP" || body_template="$BODY_TEMPLATE_WEB" - local body=$( + local body + body=$( # Note: Those line continuation backslashes are required for variables # to be passed through: DEADLINE="$DEADLINE" \ @@ -199,7 +202,8 @@ create_translation_issue_for_lang() { ) # Check for an existing issue - local existing_issue=$(gh issue list --milestone "$MILESTONE" --state all --search "$title" --json number --jq '.[0].number' || true) + local existing_issue + existing_issue=$(gh issue list --milestone "$MILESTONE" --state all --search "$title" --json number --jq '.[0].number' || true) # If there's no existing issue, create one if [[ -z $existing_issue ]]; then @@ -214,7 +218,8 @@ create_translation_issue_for_lang() { # update the issue if the bodies differ. # This is used on initial creation to fill in the issue number and it # can be used to update the body text afterwards. - local online_body=$(gh issue view "$existing_issue" --json body --jq .body) + local online_body + online_body=$(gh issue view "$existing_issue" --json body --jq .body) body=${body///${existing_issue}} if [[ "$online_body" != "$body" ]]; then echo "Updating Issue to translate $lang for $RELEASE" diff --git a/tools/update-copyright-notices.sh b/tools/update-copyright-notices.sh index 249a82c204..35045ce7ed 100755 --- a/tools/update-copyright-notices.sh +++ b/tools/update-copyright-notices.sh @@ -6,8 +6,9 @@ echo "Updating global copyright strings..." sed -re 's/(Copyright.*2[0-9]{3}-)[0-9]{4}/\1'"${YEAR}"'/g' -i src/res/translation/*.ts src/util.cpp src/aboutdlgbase.ui echo "Updating copyright comment headers..." -for file in $(find android ios linux mac src windows -regex '.*\.\(cpp\|h\|mm\)' -not -regex '\./\(\.git\|libs/\|moc_\|ui_\).*'); do - sed -re 's/(\*.*Copyright.*[^-][0-9]{4})(\s*-\s*\b[0-9]{4})?\s*$/\1-'"${YEAR}"'/' -i "${file}" +find android ios linux mac src windows -regex '.*\.\(cpp\|h\|mm\)' -not -regex '\./\(\.git\|libs/\|moc_\|ui_\).*' | while read -r file; do + sed -re 's/(\*.*Copyright.*[^-][0-9]{4})(\s*-\s*\b[0-9]{4})?\s*$/\1-'"${YEAR}"'/' -i "${file}" done + sed -re 's/^( [0-9]{4}-)[0-9]{4}( The Jamulus)/\1'"${YEAR}"'\2/' -i distributions/debian/copyright From a441d5c770c945b916d809d3750ee7f709df5d87 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Thu, 14 Apr 2022 21:47:13 +0200 Subject: [PATCH 05/15] Adding global message boxes Added files for global messageboxes with the main dialog as parent and with a standardized title. In headless mode the messages will be shown on terminal instead. (Also added myself to contributors list) --- Jamulus.pro | 2 ++ src/main.cpp | 27 +++++++++++++--------- src/messages.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/messages.h | 47 +++++++++++++++++++++++++++++++++++++++ src/util.cpp | 1 + 5 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 src/messages.cpp create mode 100644 src/messages.h diff --git a/Jamulus.pro b/Jamulus.pro index a6d8dbc05c..8cf5bc1a12 100644 --- a/Jamulus.pro +++ b/Jamulus.pro @@ -359,6 +359,7 @@ FORMS_GUI = src/aboutdlgbase.ui \ HEADERS += src/buffer.h \ src/channel.h \ src/global.h \ + src/messages.h \ src/protocol.h \ src/recorder/jamcontroller.h \ src/threadpool.h \ @@ -470,6 +471,7 @@ HEADERS_OPUS_X86 = libs/opus/celt/x86/celt_lpc_sse.h \ SOURCES += src/buffer.cpp \ src/channel.cpp \ src/main.cpp \ + src/messages.cpp \ src/protocol.cpp \ src/recorder/jamcontroller.cpp \ src/server.cpp \ diff --git a/src/main.cpp b/src/main.cpp index 05f245afc3..b2c4db4e55 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,9 +26,9 @@ #include #include #include "global.h" +#include "messages.h" #ifndef HEADLESS # include -# include # include "serverdlg.h" # ifndef SERVER_ONLY # include "clientdlg.h" @@ -900,6 +900,9 @@ int main ( int argc, char** argv ) bEnableIPv6, nullptr ); + // initialise message boxes + CMessages::init ( &ClientDlg, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + // show dialog ClientDlg.show(); pApp->exec(); @@ -910,6 +913,9 @@ int main ( int argc, char** argv ) // only start application without using the GUI qInfo() << qUtf8Printable ( GetVersionAndNameStr ( false ) ); + // initialise message boxes + CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + pApp->exec(); } } @@ -960,6 +966,9 @@ int main ( int argc, char** argv ) // GUI object for the server CServerDlg ServerDlg ( &Server, &Settings, bStartMinimized, nullptr ); + // initialise message boxes + CMessages::init ( &ServerDlg, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + // show dialog (if not the minimized flag is set) if ( !bStartMinimized ) { @@ -981,6 +990,9 @@ int main ( int argc, char** argv ) Server.SetDirectoryType ( AT_CUSTOM ); } + // initialise message boxes + CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + pApp->exec(); } } @@ -989,17 +1001,10 @@ int main ( int argc, char** argv ) catch ( const CGenErr& generr ) { // show generic error -#ifndef HEADLESS - if ( bUseGUI ) - { - QMessageBox::critical ( nullptr, APP_NAME, generr.GetErrorText(), "Quit", nullptr ); - } - else + CMessages::ShowError ( generr.GetErrorText() ); +#ifdef HEADLESS + exit ( 1 ); #endif - { - qCritical() << qUtf8Printable ( QString ( "%1: %2" ).arg ( APP_NAME ).arg ( generr.GetErrorText() ) ); - exit ( 1 ); - } } #if defined( Q_OS_MACX ) diff --git a/src/messages.cpp b/src/messages.cpp new file mode 100644 index 0000000000..c98a9e0590 --- /dev/null +++ b/src/messages.cpp @@ -0,0 +1,58 @@ +/******************************************************************************\ + * Copyright (c) 2022 + * + * Author(s): + * Peter Goderie (pgScorpio) + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * +\******************************************************************************/ + +#include "messages.h" + +tMainform* CMessages::pMainForm = NULL; +QString CMessages::strMainFormName; + +/******************************************************************************\ +* Message Boxes * +\******************************************************************************/ +void CMessages::ShowError ( QString strError ) +{ +#ifndef HEADLESS + QMessageBox::critical ( pMainForm, strMainFormName + ": " + QObject::tr ( "Error" ), strError, QObject::tr ( "Ok" ), nullptr ); +#else + qCritical() << "Error: " << strError.toLocal8Bit().data(); +#endif +} + +void CMessages::ShowWarning ( QString strWarning ) +{ +#ifndef HEADLESS + QMessageBox::warning ( pMainForm, strMainFormName + ": " + QObject::tr ( "Warning" ), strWarning, QObject::tr ( "Ok" ), nullptr ); +#else + qWarning() << "Warning: " << strWarning.toLocal8Bit().data(); +#endif +} + +void CMessages::ShowInfo ( QString strInfo ) +{ +#ifndef HEADLESS + QMessageBox::information ( pMainForm, strMainFormName + ": " + QObject::tr ( "Information" ), strInfo, QObject::tr ( "Ok" ), nullptr ); +#else + qInfo() << "Info: " << strInfo.toLocal8Bit().data(); +#endif +} diff --git a/src/messages.h b/src/messages.h new file mode 100644 index 0000000000..9982f9409c --- /dev/null +++ b/src/messages.h @@ -0,0 +1,47 @@ +#pragma once + +/******************************************************************************\ + * Copyright (c) 2022 + * Author(s): + * Peter Goderie (pgScorpio) + * + * Use this static class to show basic Error, Warning and Info messages + * + * For own created special message boxes you should always use + * CMessages::MainForm() as parent parameter + * and CMessages::MainFormName() as base of the title parameter +\******************************************************************************/ + +#include +#ifndef HEADLESS +# include +# define tMainform QDialog +#else +# include +# define tMainform void +#endif + +// html text macro's (for use in message texts) +#define htmlBold( T ) "" + T + "" +#define htmlNewLine() "
" + +class CMessages +{ +protected: + static tMainform* pMainForm; + static QString strMainFormName; + +public: + static void init ( tMainform* theMainForm, QString theMainFormName ) + { + pMainForm = theMainForm; + strMainFormName = theMainFormName; + } + + static tMainform* MainForm() { return pMainForm; } + static const QString& MainFormName() { return strMainFormName; } + + static void ShowError ( QString strError ); + static void ShowWarning ( QString strWarning ); + static void ShowInfo ( QString strInfo ); +}; diff --git a/src/util.cpp b/src/util.cpp index d2f7d6f78b..820c758de8 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -495,6 +495,7 @@ CAboutDlg::CAboutDlg ( QWidget* parent ) : CBaseDlg ( parent ) "

RobyDati (RobyDati)

" "

Rob-NY (Rob-NY)

" "

Thai Pangsakulyanont (dtinth)

" + "

Peter Goderie (pgScorpio)

" "
" + tr ( "For details on the contributions check out the %1" ) .arg ( "" + tr ( "Github Contributors list" ) + "." ) ); From cb9a5e6820d3b8369daedc2c979dcacac42a3414 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Sat, 30 Apr 2022 01:26:22 +0200 Subject: [PATCH 06/15] No html output to console. Now translating html text to plain text before sending it to console. --- src/messages.cpp | 33 ++++++++++++++++++++++++++++++--- src/messages.h | 2 ++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/messages.cpp b/src/messages.cpp index c98a9e0590..e8e35b475d 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -23,19 +23,46 @@ \******************************************************************************/ #include "messages.h" +#include tMainform* CMessages::pMainForm = NULL; QString CMessages::strMainFormName; +QString CMessages::ToUtf8Printable ( const QString& text ) +{ + QString plainText; + + { + QTextEdit textEdit; + + textEdit.setText ( text ); // Text can be html... + plainText = textEdit.toPlainText(); // Text will be plain Text ! + } + + // no multiple newlines + while ( plainText.contains ( "\n\n" ) ) + { + plainText.replace ( "\n\n", "\n" ); + } + +#ifdef _WIN32 + // LF to CRLF + plainText.replace ( "\n", "\r\n" ); +#endif + + return qUtf8Printable ( plainText ); +} + /******************************************************************************\ * Message Boxes * \******************************************************************************/ + void CMessages::ShowError ( QString strError ) { #ifndef HEADLESS QMessageBox::critical ( pMainForm, strMainFormName + ": " + QObject::tr ( "Error" ), strError, QObject::tr ( "Ok" ), nullptr ); #else - qCritical() << "Error: " << strError.toLocal8Bit().data(); + qCritical().noquote() << "Error: " << ToUtf8Printable ( strError ); #endif } @@ -44,7 +71,7 @@ void CMessages::ShowWarning ( QString strWarning ) #ifndef HEADLESS QMessageBox::warning ( pMainForm, strMainFormName + ": " + QObject::tr ( "Warning" ), strWarning, QObject::tr ( "Ok" ), nullptr ); #else - qWarning() << "Warning: " << strWarning.toLocal8Bit().data(); + qWarning().noquote() << "Warning: " << ToUtf8Printable ( strWarning ); #endif } @@ -53,6 +80,6 @@ void CMessages::ShowInfo ( QString strInfo ) #ifndef HEADLESS QMessageBox::information ( pMainForm, strMainFormName + ": " + QObject::tr ( "Information" ), strInfo, QObject::tr ( "Ok" ), nullptr ); #else - qInfo() << "Info: " << strInfo.toLocal8Bit().data(); + qInfo().noquote() << "Info: " << ToUtf8Printable ( strInfo ); #endif } diff --git a/src/messages.h b/src/messages.h index 9982f9409c..7287ac36ab 100644 --- a/src/messages.h +++ b/src/messages.h @@ -31,6 +31,8 @@ class CMessages static tMainform* pMainForm; static QString strMainFormName; + static QString ToUtf8Printable ( const QString& text ); + public: static void init ( tMainform* theMainForm, QString theMainFormName ) { From 424f66730340401ddcd294daea774eefe83f80f5 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Sat, 30 Apr 2022 21:03:12 +0200 Subject: [PATCH 07/15] Added ShowXxxWait messageboxes. ShowXxxWait messageboxes will wait for the/a button to be pressed in gui mode. ShowXxxWait messageboxes also have an optional 'abort' button and a default selection. In HEADLESS mode there is NO wait, and the default selection is returned. --- src/messages.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ src/messages.h | 26 ++++++++++++-- 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/src/messages.cpp b/src/messages.cpp index e8e35b475d..94c9f3739a 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -83,3 +83,96 @@ void CMessages::ShowInfo ( QString strInfo ) qInfo().noquote() << "Info: " << ToUtf8Printable ( strInfo ); #endif } + +bool CMessages::ShowErrorWait ( QString strError, const QString strActionButtonText, const QString strAbortButtonText, bool bDefault ) +{ +#ifndef HEADLESS + QMessageBox msgBox ( pMainForm ); + QPushButton* actionButton = msgBox.addButton ( strActionButtonText, QMessageBox::ActionRole ); + QPushButton* abortButton = NULL; + if ( !strAbortButtonText.isEmpty() ) + { + abortButton = msgBox.addButton ( strAbortButtonText, QMessageBox::ActionRole ); + if ( bDefault ) + { + msgBox.setDefaultButton ( actionButton ); + } + else + { + msgBox.setDefaultButton ( abortButton ); + } + } + + msgBox.setIcon ( QMessageBox::Icon::Critical ); + msgBox.setWindowTitle ( strMainFormName + ": " + QObject::tr ( "Error" ) ); + msgBox.setText ( strError ); + return ( msgBox.exec() == 0 ); +#else + Q_UNUSED ( strActionText ) + Q_UNUSED ( strAbortText ) + qCritical().noquote() << "Error: " << ToUtf8Printable ( strError ); + return bDefault; +#endif +} + +bool CMessages::ShowWarningWait ( QString strWarning, const QString strActionButtonText, const QString strAbortButtonText, bool bDefault ) +{ +#ifndef HEADLESS + QMessageBox msgBox ( pMainForm ); + QPushButton* actionButton = msgBox.addButton ( strActionButtonText, QMessageBox::ActionRole ); + QPushButton* abortButton = NULL; + if ( !strAbortButtonText.isEmpty() ) + { + abortButton = msgBox.addButton ( strAbortButtonText, QMessageBox::ActionRole ); + if ( bDefault ) + { + msgBox.setDefaultButton ( actionButton ); + } + else + { + msgBox.setDefaultButton ( abortButton ); + } + } + + msgBox.setIcon ( QMessageBox::Icon::Warning ); + msgBox.setWindowTitle ( strMainFormName + ": " + QObject::tr ( "Warning" ) ); + msgBox.setText ( strWarning ); + return ( msgBox.exec() == 0 ); +#else + Q_UNUSED ( strActionText ) + Q_UNUSED ( strAbortText ) + qWarning().noquote() << "Warning: " << ToUtf8Printable ( strWarning ); + return bDefault; +#endif +} + +bool CMessages::ShowInfoWait ( QString strInfo, const QString strActionButtonText, const QString strAbortButtonText, bool bDefault ) +{ +#ifndef HEADLESS + QMessageBox msgBox ( pMainForm ); + QPushButton* actionButton = msgBox.addButton ( strActionButtonText, QMessageBox::ActionRole ); + QPushButton* abortButton = NULL; + if ( !strAbortButtonText.isEmpty() ) + { + abortButton = msgBox.addButton ( strAbortButtonText, QMessageBox::ActionRole ); + if ( bDefault ) + { + msgBox.setDefaultButton ( actionButton ); + } + else + { + msgBox.setDefaultButton ( abortButton ); + } + } + + msgBox.setIcon ( QMessageBox::Icon::Warning ); + msgBox.setWindowTitle ( strMainFormName + ": " + QObject::tr ( "Info" ) ); + msgBox.setText ( strInfo ); + return ( msgBox.exec() == 0 ); +#else + Q_UNUSED ( strActionText ) + Q_UNUSED ( strAbortText ) + qInfo().noquote() << "Info: " << ToUtf8Printable ( strInfo ); + return bDefault; +#endif +} diff --git a/src/messages.h b/src/messages.h index 7287ac36ab..0286745bfa 100644 --- a/src/messages.h +++ b/src/messages.h @@ -31,9 +31,9 @@ class CMessages static tMainform* pMainForm; static QString strMainFormName; - static QString ToUtf8Printable ( const QString& text ); - public: + static QString ToUtf8Printable ( const QString& text ); // Converts html to plain utf8 text + static void init ( tMainform* theMainForm, QString theMainFormName ) { pMainForm = theMainForm; @@ -46,4 +46,26 @@ class CMessages static void ShowError ( QString strError ); static void ShowWarning ( QString strWarning ); static void ShowInfo ( QString strInfo ); + + // Modal message boxes (wait for user confirmation in gui mode) + // Returns true if action button is pressed + // Returns false if abort button is pressed + // + // NOTE: The abort button is only present if a non empty strAbortButtonText is given + // if this is the case bDefault pre-selects the default Button. + // + // NOTE: In HEADLESS mode there is NO wait and always bDefault is returned. + + static bool ShowErrorWait ( QString strError, + const QString strActionButtonText = "Ok", + const QString strAbortButtonText = "", + bool bDefault = true ); + static bool ShowWarningWait ( QString strWarning, + const QString strActionButtonText = "Ok", + const QString strAbortButtonText = "", + bool bDefault = true ); + static bool ShowInfoWait ( QString strInfo, + const QString strActionButtonText = "Ok", + const QString strAbortButtonText = "", + bool bDefault = true ); }; From 5837a93da34e98c7fda5144df40a109d569bd3b3 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Sat, 30 Apr 2022 21:21:39 +0200 Subject: [PATCH 08/15] Use ShowErrorWait in main Also added catching of generic exceptions withusing a ShowErrorWait --- src/main.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 88ad252e38..3fbbaa50de 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,7 +57,7 @@ extern void qt_set_sequence_auto_mnemonic ( bool bEnable ); int main ( int argc, char** argv ) { - + int exit_code = 0; #if defined( Q_OS_MACX ) // Mnemonic keys are default disabled in Qt for MacOS. The following function enables them. // Qt will not show these with underline characters in the GUI on MacOS. @@ -906,7 +906,7 @@ int main ( int argc, char** argv ) // show dialog ClientDlg.show(); - pApp->exec(); + exit_code = pApp->exec(); } else # endif @@ -917,7 +917,7 @@ int main ( int argc, char** argv ) // initialise message boxes CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); - pApp->exec(); + exit_code = pApp->exec(); } } else @@ -976,7 +976,7 @@ int main ( int argc, char** argv ) ServerDlg.show(); } - pApp->exec(); + exit_code = pApp->exec(); } else #endif @@ -994,7 +994,7 @@ int main ( int argc, char** argv ) // initialise message boxes CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); - pApp->exec(); + exit_code = pApp->exec(); } } } @@ -1002,17 +1002,22 @@ int main ( int argc, char** argv ) catch ( const CGenErr& generr ) { // show generic error - CMessages::ShowError ( generr.GetErrorText() ); -#ifdef HEADLESS - exit ( 1 ); -#endif + CMessages::ShowErrorWait ( generr.GetErrorText(), QObject::tr ( "Exit" ) ); + exit_code = 1; + } + + catch ( ... ) + { + // show generic error + CMessages::ShowErrorWait ( QObject::tr ( "Unhandled exception !" ), QObject::tr ( "Exit" ) ); + exit_code = -1; } #if defined( Q_OS_MACX ) activity.EndActivity(); #endif - return 0; + return exit_code; } /******************************************************************************\ From 3ff4ad85968cca87f6cd1446c101cdcab3fa5696 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Sun, 1 May 2022 00:05:26 +0200 Subject: [PATCH 09/15] Fixing HEADLESS build... Can't use QTextEdit in messages Unused variables in main --- src/main.cpp | 3 +++ src/messages.cpp | 26 +++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 3fbbaa50de..bbd1ad8b11 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -921,6 +921,9 @@ int main ( int argc, char** argv ) } } else +#else + Q_UNUSED ( bUseTranslation ) + Q_UNUSED ( bNoAutoJackConnect ) #endif { // Server: diff --git a/src/messages.cpp b/src/messages.cpp index 94c9f3739a..3b289bb5bb 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -23,7 +23,10 @@ \******************************************************************************/ #include "messages.h" -#include + +#ifndef HEADLESS +# include +#endif tMainform* CMessages::pMainForm = NULL; QString CMessages::strMainFormName; @@ -32,18 +35,27 @@ QString CMessages::ToUtf8Printable ( const QString& text ) { QString plainText; +#ifndef HEADLESS { QTextEdit textEdit; textEdit.setText ( text ); // Text can be html... plainText = textEdit.toPlainText(); // Text will be plain Text ! } +#else + plainText = text; + // Remove htmlBold + plainText.replace ( "", "" ); + plainText.replace ( "", "" ); + // Translate htmlNewLine + plainText.replace ( "
", "\n" ); // no multiple newlines while ( plainText.contains ( "\n\n" ) ) { plainText.replace ( "\n\n", "\n" ); } +#endif #ifdef _WIN32 // LF to CRLF @@ -108,8 +120,8 @@ bool CMessages::ShowErrorWait ( QString strError, const QString strActionButtonT msgBox.setText ( strError ); return ( msgBox.exec() == 0 ); #else - Q_UNUSED ( strActionText ) - Q_UNUSED ( strAbortText ) + Q_UNUSED ( strActionButtonText ) + Q_UNUSED ( strAbortButtonText ) qCritical().noquote() << "Error: " << ToUtf8Printable ( strError ); return bDefault; #endif @@ -139,8 +151,8 @@ bool CMessages::ShowWarningWait ( QString strWarning, const QString strActionBut msgBox.setText ( strWarning ); return ( msgBox.exec() == 0 ); #else - Q_UNUSED ( strActionText ) - Q_UNUSED ( strAbortText ) + Q_UNUSED ( strActionButtonText ) + Q_UNUSED ( strAbortButtonText ) qWarning().noquote() << "Warning: " << ToUtf8Printable ( strWarning ); return bDefault; #endif @@ -170,8 +182,8 @@ bool CMessages::ShowInfoWait ( QString strInfo, const QString strActionButtonTex msgBox.setText ( strInfo ); return ( msgBox.exec() == 0 ); #else - Q_UNUSED ( strActionText ) - Q_UNUSED ( strAbortText ) + Q_UNUSED ( strActionButtonText ) + Q_UNUSED ( strAbortButtonText ) qInfo().noquote() << "Info: " << ToUtf8Printable ( strInfo ); return bDefault; #endif From cebc2b442e8624cdac6ea445bcc17606fb731fd0 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Fri, 6 May 2022 17:17:30 +0200 Subject: [PATCH 10/15] rebase to upstream --- tools/check-wininstaller-translations.sh | 4 ++-- tools/update-copyright-notices.sh | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tools/check-wininstaller-translations.sh b/tools/check-wininstaller-translations.sh index ff7ca8b545..098110a657 100755 --- a/tools/check-wininstaller-translations.sh +++ b/tools/check-wininstaller-translations.sh @@ -1,12 +1,12 @@ #!/bin/bash set -eu -BASE_DIR=src/res/translation/wininstaller/ +BASE_DIR=src/translation/wininstaller/ BASE_LANG=en INSTALLERLNG=installerlng.nsi BASE_LANGSTRINGS=$(grep LangString "${BASE_DIR}/${BASE_LANG}.nsi" | cut -d' ' -f2) EXIT=0 -for LANGUAGE_FILE in src/res/translation/wininstaller/{??.nsi,??_??.nsi}; do +for LANGUAGE_FILE in src/translation/wininstaller/{??.nsi,??_??.nsi}; do if [[ ${LANGUAGE_FILE} =~ /${BASE_LANG}.nsi$ ]]; then continue fi diff --git a/tools/update-copyright-notices.sh b/tools/update-copyright-notices.sh index 35045ce7ed..7eb3cbdd4f 100755 --- a/tools/update-copyright-notices.sh +++ b/tools/update-copyright-notices.sh @@ -3,7 +3,7 @@ set -eu YEAR=$(date +%Y) echo "Updating global copyright strings..." -sed -re 's/(Copyright.*2[0-9]{3}-)[0-9]{4}/\1'"${YEAR}"'/g' -i src/res/translation/*.ts src/util.cpp src/aboutdlgbase.ui +sed -re 's/(Copyright.*2[0-9]{3}-)[0-9]{4}/\1'"${YEAR}"'/g' -i src/translation/*.ts src/util.cpp src/aboutdlgbase.ui echo "Updating copyright comment headers..." find android ios linux mac src windows -regex '.*\.\(cpp\|h\|mm\)' -not -regex '\./\(\.git\|libs/\|moc_\|ui_\).*' | while read -r file; do From dca5145fd8f64f6fe713db55da28846b7be52797 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Thu, 14 Apr 2022 21:47:13 +0200 Subject: [PATCH 11/15] Adding global message boxes Added files for global messageboxes with the main dialog as parent and with a standardized title. In headless mode the messages will be shown on terminal instead. (Also added myself to contributors list) --- Jamulus.pro | 2 ++ src/main.cpp | 27 +++++++++++++--------- src/messages.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++++++++ src/messages.h | 47 +++++++++++++++++++++++++++++++++++++++ src/util.cpp | 1 + 5 files changed, 124 insertions(+), 11 deletions(-) create mode 100644 src/messages.cpp create mode 100644 src/messages.h diff --git a/Jamulus.pro b/Jamulus.pro index 13206c8113..bae06896d6 100644 --- a/Jamulus.pro +++ b/Jamulus.pro @@ -366,6 +366,7 @@ FORMS_GUI = src/aboutdlgbase.ui \ HEADERS += src/buffer.h \ src/channel.h \ src/global.h \ + src/messages.h \ src/protocol.h \ src/recorder/jamcontroller.h \ src/threadpool.h \ @@ -477,6 +478,7 @@ HEADERS_OPUS_X86 = libs/opus/celt/x86/celt_lpc_sse.h \ SOURCES += src/buffer.cpp \ src/channel.cpp \ src/main.cpp \ + src/messages.cpp \ src/protocol.cpp \ src/recorder/jamcontroller.cpp \ src/server.cpp \ diff --git a/src/main.cpp b/src/main.cpp index 86a37e40e3..388968fea9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -26,9 +26,9 @@ #include #include #include "global.h" +#include "messages.h" #ifndef HEADLESS # include -# include # include "serverdlg.h" # ifndef SERVER_ONLY # include "clientdlg.h" @@ -901,6 +901,9 @@ int main ( int argc, char** argv ) bEnableIPv6, nullptr ); + // initialise message boxes + CMessages::init ( &ClientDlg, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + // show dialog ClientDlg.show(); pApp->exec(); @@ -911,6 +914,9 @@ int main ( int argc, char** argv ) // only start application without using the GUI qInfo() << qUtf8Printable ( GetVersionAndNameStr ( false ) ); + // initialise message boxes + CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + pApp->exec(); } } @@ -961,6 +967,9 @@ int main ( int argc, char** argv ) // GUI object for the server CServerDlg ServerDlg ( &Server, &Settings, bStartMinimized, nullptr ); + // initialise message boxes + CMessages::init ( &ServerDlg, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + // show dialog (if not the minimized flag is set) if ( !bStartMinimized ) { @@ -982,6 +991,9 @@ int main ( int argc, char** argv ) Server.SetDirectoryType ( AT_CUSTOM ); } + // initialise message boxes + CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); + pApp->exec(); } } @@ -990,17 +1002,10 @@ int main ( int argc, char** argv ) catch ( const CGenErr& generr ) { // show generic error -#ifndef HEADLESS - if ( bUseGUI ) - { - QMessageBox::critical ( nullptr, APP_NAME, generr.GetErrorText(), "Quit", nullptr ); - } - else + CMessages::ShowError ( generr.GetErrorText() ); +#ifdef HEADLESS + exit ( 1 ); #endif - { - qCritical() << qUtf8Printable ( QString ( "%1: %2" ).arg ( APP_NAME ).arg ( generr.GetErrorText() ) ); - exit ( 1 ); - } } #if defined( Q_OS_MACX ) diff --git a/src/messages.cpp b/src/messages.cpp new file mode 100644 index 0000000000..c98a9e0590 --- /dev/null +++ b/src/messages.cpp @@ -0,0 +1,58 @@ +/******************************************************************************\ + * Copyright (c) 2022 + * + * Author(s): + * Peter Goderie (pgScorpio) + * + ****************************************************************************** + * + * This program is free software; you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by the Free Software + * Foundation; either version 2 of the License, or (at your option) any later + * version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA + * +\******************************************************************************/ + +#include "messages.h" + +tMainform* CMessages::pMainForm = NULL; +QString CMessages::strMainFormName; + +/******************************************************************************\ +* Message Boxes * +\******************************************************************************/ +void CMessages::ShowError ( QString strError ) +{ +#ifndef HEADLESS + QMessageBox::critical ( pMainForm, strMainFormName + ": " + QObject::tr ( "Error" ), strError, QObject::tr ( "Ok" ), nullptr ); +#else + qCritical() << "Error: " << strError.toLocal8Bit().data(); +#endif +} + +void CMessages::ShowWarning ( QString strWarning ) +{ +#ifndef HEADLESS + QMessageBox::warning ( pMainForm, strMainFormName + ": " + QObject::tr ( "Warning" ), strWarning, QObject::tr ( "Ok" ), nullptr ); +#else + qWarning() << "Warning: " << strWarning.toLocal8Bit().data(); +#endif +} + +void CMessages::ShowInfo ( QString strInfo ) +{ +#ifndef HEADLESS + QMessageBox::information ( pMainForm, strMainFormName + ": " + QObject::tr ( "Information" ), strInfo, QObject::tr ( "Ok" ), nullptr ); +#else + qInfo() << "Info: " << strInfo.toLocal8Bit().data(); +#endif +} diff --git a/src/messages.h b/src/messages.h new file mode 100644 index 0000000000..9982f9409c --- /dev/null +++ b/src/messages.h @@ -0,0 +1,47 @@ +#pragma once + +/******************************************************************************\ + * Copyright (c) 2022 + * Author(s): + * Peter Goderie (pgScorpio) + * + * Use this static class to show basic Error, Warning and Info messages + * + * For own created special message boxes you should always use + * CMessages::MainForm() as parent parameter + * and CMessages::MainFormName() as base of the title parameter +\******************************************************************************/ + +#include +#ifndef HEADLESS +# include +# define tMainform QDialog +#else +# include +# define tMainform void +#endif + +// html text macro's (for use in message texts) +#define htmlBold( T ) "" + T + "" +#define htmlNewLine() "
" + +class CMessages +{ +protected: + static tMainform* pMainForm; + static QString strMainFormName; + +public: + static void init ( tMainform* theMainForm, QString theMainFormName ) + { + pMainForm = theMainForm; + strMainFormName = theMainFormName; + } + + static tMainform* MainForm() { return pMainForm; } + static const QString& MainFormName() { return strMainFormName; } + + static void ShowError ( QString strError ); + static void ShowWarning ( QString strWarning ); + static void ShowInfo ( QString strInfo ); +}; diff --git a/src/util.cpp b/src/util.cpp index 4f7d6e1122..97f809dc33 100644 --- a/src/util.cpp +++ b/src/util.cpp @@ -495,6 +495,7 @@ CAboutDlg::CAboutDlg ( QWidget* parent ) : CBaseDlg ( parent ) "

RobyDati (RobyDati)

" "

Rob-NY (Rob-NY)

" "

Thai Pangsakulyanont (dtinth)

" + "

Peter Goderie (pgScorpio)

" "
" + tr ( "For details on the contributions check out the %1" ) .arg ( "" + tr ( "Github Contributors list" ) + "." ) ); From 41999f6ffb1948de4f421d3c84ea500657ffa735 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Sat, 30 Apr 2022 01:26:22 +0200 Subject: [PATCH 12/15] No html output to console. Now translating html text to plain text before sending it to console. --- src/messages.cpp | 33 ++++++++++++++++++++++++++++++--- src/messages.h | 2 ++ 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/messages.cpp b/src/messages.cpp index c98a9e0590..e8e35b475d 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -23,19 +23,46 @@ \******************************************************************************/ #include "messages.h" +#include tMainform* CMessages::pMainForm = NULL; QString CMessages::strMainFormName; +QString CMessages::ToUtf8Printable ( const QString& text ) +{ + QString plainText; + + { + QTextEdit textEdit; + + textEdit.setText ( text ); // Text can be html... + plainText = textEdit.toPlainText(); // Text will be plain Text ! + } + + // no multiple newlines + while ( plainText.contains ( "\n\n" ) ) + { + plainText.replace ( "\n\n", "\n" ); + } + +#ifdef _WIN32 + // LF to CRLF + plainText.replace ( "\n", "\r\n" ); +#endif + + return qUtf8Printable ( plainText ); +} + /******************************************************************************\ * Message Boxes * \******************************************************************************/ + void CMessages::ShowError ( QString strError ) { #ifndef HEADLESS QMessageBox::critical ( pMainForm, strMainFormName + ": " + QObject::tr ( "Error" ), strError, QObject::tr ( "Ok" ), nullptr ); #else - qCritical() << "Error: " << strError.toLocal8Bit().data(); + qCritical().noquote() << "Error: " << ToUtf8Printable ( strError ); #endif } @@ -44,7 +71,7 @@ void CMessages::ShowWarning ( QString strWarning ) #ifndef HEADLESS QMessageBox::warning ( pMainForm, strMainFormName + ": " + QObject::tr ( "Warning" ), strWarning, QObject::tr ( "Ok" ), nullptr ); #else - qWarning() << "Warning: " << strWarning.toLocal8Bit().data(); + qWarning().noquote() << "Warning: " << ToUtf8Printable ( strWarning ); #endif } @@ -53,6 +80,6 @@ void CMessages::ShowInfo ( QString strInfo ) #ifndef HEADLESS QMessageBox::information ( pMainForm, strMainFormName + ": " + QObject::tr ( "Information" ), strInfo, QObject::tr ( "Ok" ), nullptr ); #else - qInfo() << "Info: " << strInfo.toLocal8Bit().data(); + qInfo().noquote() << "Info: " << ToUtf8Printable ( strInfo ); #endif } diff --git a/src/messages.h b/src/messages.h index 9982f9409c..7287ac36ab 100644 --- a/src/messages.h +++ b/src/messages.h @@ -31,6 +31,8 @@ class CMessages static tMainform* pMainForm; static QString strMainFormName; + static QString ToUtf8Printable ( const QString& text ); + public: static void init ( tMainform* theMainForm, QString theMainFormName ) { From ad3194c7a8c29dff06b43c8890bbb58cbfed0c47 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Sat, 30 Apr 2022 21:03:12 +0200 Subject: [PATCH 13/15] Added ShowXxxWait messageboxes. ShowXxxWait messageboxes will wait for the/a button to be pressed in gui mode. ShowXxxWait messageboxes also have an optional 'abort' button and a default selection. In HEADLESS mode there is NO wait, and the default selection is returned. --- src/messages.cpp | 93 ++++++++++++++++++++++++++++++++++++++++++++++++ src/messages.h | 26 ++++++++++++-- 2 files changed, 117 insertions(+), 2 deletions(-) diff --git a/src/messages.cpp b/src/messages.cpp index e8e35b475d..94c9f3739a 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -83,3 +83,96 @@ void CMessages::ShowInfo ( QString strInfo ) qInfo().noquote() << "Info: " << ToUtf8Printable ( strInfo ); #endif } + +bool CMessages::ShowErrorWait ( QString strError, const QString strActionButtonText, const QString strAbortButtonText, bool bDefault ) +{ +#ifndef HEADLESS + QMessageBox msgBox ( pMainForm ); + QPushButton* actionButton = msgBox.addButton ( strActionButtonText, QMessageBox::ActionRole ); + QPushButton* abortButton = NULL; + if ( !strAbortButtonText.isEmpty() ) + { + abortButton = msgBox.addButton ( strAbortButtonText, QMessageBox::ActionRole ); + if ( bDefault ) + { + msgBox.setDefaultButton ( actionButton ); + } + else + { + msgBox.setDefaultButton ( abortButton ); + } + } + + msgBox.setIcon ( QMessageBox::Icon::Critical ); + msgBox.setWindowTitle ( strMainFormName + ": " + QObject::tr ( "Error" ) ); + msgBox.setText ( strError ); + return ( msgBox.exec() == 0 ); +#else + Q_UNUSED ( strActionText ) + Q_UNUSED ( strAbortText ) + qCritical().noquote() << "Error: " << ToUtf8Printable ( strError ); + return bDefault; +#endif +} + +bool CMessages::ShowWarningWait ( QString strWarning, const QString strActionButtonText, const QString strAbortButtonText, bool bDefault ) +{ +#ifndef HEADLESS + QMessageBox msgBox ( pMainForm ); + QPushButton* actionButton = msgBox.addButton ( strActionButtonText, QMessageBox::ActionRole ); + QPushButton* abortButton = NULL; + if ( !strAbortButtonText.isEmpty() ) + { + abortButton = msgBox.addButton ( strAbortButtonText, QMessageBox::ActionRole ); + if ( bDefault ) + { + msgBox.setDefaultButton ( actionButton ); + } + else + { + msgBox.setDefaultButton ( abortButton ); + } + } + + msgBox.setIcon ( QMessageBox::Icon::Warning ); + msgBox.setWindowTitle ( strMainFormName + ": " + QObject::tr ( "Warning" ) ); + msgBox.setText ( strWarning ); + return ( msgBox.exec() == 0 ); +#else + Q_UNUSED ( strActionText ) + Q_UNUSED ( strAbortText ) + qWarning().noquote() << "Warning: " << ToUtf8Printable ( strWarning ); + return bDefault; +#endif +} + +bool CMessages::ShowInfoWait ( QString strInfo, const QString strActionButtonText, const QString strAbortButtonText, bool bDefault ) +{ +#ifndef HEADLESS + QMessageBox msgBox ( pMainForm ); + QPushButton* actionButton = msgBox.addButton ( strActionButtonText, QMessageBox::ActionRole ); + QPushButton* abortButton = NULL; + if ( !strAbortButtonText.isEmpty() ) + { + abortButton = msgBox.addButton ( strAbortButtonText, QMessageBox::ActionRole ); + if ( bDefault ) + { + msgBox.setDefaultButton ( actionButton ); + } + else + { + msgBox.setDefaultButton ( abortButton ); + } + } + + msgBox.setIcon ( QMessageBox::Icon::Warning ); + msgBox.setWindowTitle ( strMainFormName + ": " + QObject::tr ( "Info" ) ); + msgBox.setText ( strInfo ); + return ( msgBox.exec() == 0 ); +#else + Q_UNUSED ( strActionText ) + Q_UNUSED ( strAbortText ) + qInfo().noquote() << "Info: " << ToUtf8Printable ( strInfo ); + return bDefault; +#endif +} diff --git a/src/messages.h b/src/messages.h index 7287ac36ab..0286745bfa 100644 --- a/src/messages.h +++ b/src/messages.h @@ -31,9 +31,9 @@ class CMessages static tMainform* pMainForm; static QString strMainFormName; - static QString ToUtf8Printable ( const QString& text ); - public: + static QString ToUtf8Printable ( const QString& text ); // Converts html to plain utf8 text + static void init ( tMainform* theMainForm, QString theMainFormName ) { pMainForm = theMainForm; @@ -46,4 +46,26 @@ class CMessages static void ShowError ( QString strError ); static void ShowWarning ( QString strWarning ); static void ShowInfo ( QString strInfo ); + + // Modal message boxes (wait for user confirmation in gui mode) + // Returns true if action button is pressed + // Returns false if abort button is pressed + // + // NOTE: The abort button is only present if a non empty strAbortButtonText is given + // if this is the case bDefault pre-selects the default Button. + // + // NOTE: In HEADLESS mode there is NO wait and always bDefault is returned. + + static bool ShowErrorWait ( QString strError, + const QString strActionButtonText = "Ok", + const QString strAbortButtonText = "", + bool bDefault = true ); + static bool ShowWarningWait ( QString strWarning, + const QString strActionButtonText = "Ok", + const QString strAbortButtonText = "", + bool bDefault = true ); + static bool ShowInfoWait ( QString strInfo, + const QString strActionButtonText = "Ok", + const QString strAbortButtonText = "", + bool bDefault = true ); }; From ea5553ae62f90aa3c153424c5f800f7cffcc61c1 Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Sat, 30 Apr 2022 21:21:39 +0200 Subject: [PATCH 14/15] Use ShowErrorWait in main Also added catching of generic exceptions withusing a ShowErrorWait --- src/main.cpp | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 388968fea9..845e0ed44b 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -57,7 +57,7 @@ extern void qt_set_sequence_auto_mnemonic ( bool bEnable ); int main ( int argc, char** argv ) { - + int exit_code = 0; #if defined( Q_OS_MACX ) // Mnemonic keys are default disabled in Qt for MacOS. The following function enables them. // Qt will not show these with underline characters in the GUI on MacOS. (#1873) @@ -906,7 +906,7 @@ int main ( int argc, char** argv ) // show dialog ClientDlg.show(); - pApp->exec(); + exit_code = pApp->exec(); } else # endif @@ -917,7 +917,7 @@ int main ( int argc, char** argv ) // initialise message boxes CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); - pApp->exec(); + exit_code = pApp->exec(); } } else @@ -976,7 +976,7 @@ int main ( int argc, char** argv ) ServerDlg.show(); } - pApp->exec(); + exit_code = pApp->exec(); } else #endif @@ -994,7 +994,7 @@ int main ( int argc, char** argv ) // initialise message boxes CMessages::init ( NULL, strClientName.isEmpty() ? QString ( APP_NAME ) : QString ( APP_NAME ) + " " + strClientName ); - pApp->exec(); + exit_code = pApp->exec(); } } } @@ -1002,17 +1002,22 @@ int main ( int argc, char** argv ) catch ( const CGenErr& generr ) { // show generic error - CMessages::ShowError ( generr.GetErrorText() ); -#ifdef HEADLESS - exit ( 1 ); -#endif + CMessages::ShowErrorWait ( generr.GetErrorText(), QObject::tr ( "Exit" ) ); + exit_code = 1; + } + + catch ( ... ) + { + // show generic error + CMessages::ShowErrorWait ( QObject::tr ( "Unhandled exception !" ), QObject::tr ( "Exit" ) ); + exit_code = -1; } #if defined( Q_OS_MACX ) activity.EndActivity(); #endif - return 0; + return exit_code; } /******************************************************************************\ From 28a042b57897bf3281a2ce440206905e6877d9ab Mon Sep 17 00:00:00 2001 From: pgScorpio Date: Sun, 1 May 2022 00:05:26 +0200 Subject: [PATCH 15/15] Fixing HEADLESS build... Can't use QTextEdit in messages Unused variables in main --- src/main.cpp | 3 +++ src/messages.cpp | 26 +++++++++++++++++++------- 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index 845e0ed44b..a7c664cbf4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -921,6 +921,9 @@ int main ( int argc, char** argv ) } } else +#else + Q_UNUSED ( bUseTranslation ) + Q_UNUSED ( bNoAutoJackConnect ) #endif { // Server: diff --git a/src/messages.cpp b/src/messages.cpp index 94c9f3739a..3b289bb5bb 100644 --- a/src/messages.cpp +++ b/src/messages.cpp @@ -23,7 +23,10 @@ \******************************************************************************/ #include "messages.h" -#include + +#ifndef HEADLESS +# include +#endif tMainform* CMessages::pMainForm = NULL; QString CMessages::strMainFormName; @@ -32,18 +35,27 @@ QString CMessages::ToUtf8Printable ( const QString& text ) { QString plainText; +#ifndef HEADLESS { QTextEdit textEdit; textEdit.setText ( text ); // Text can be html... plainText = textEdit.toPlainText(); // Text will be plain Text ! } +#else + plainText = text; + // Remove htmlBold + plainText.replace ( "", "" ); + plainText.replace ( "", "" ); + // Translate htmlNewLine + plainText.replace ( "
", "\n" ); // no multiple newlines while ( plainText.contains ( "\n\n" ) ) { plainText.replace ( "\n\n", "\n" ); } +#endif #ifdef _WIN32 // LF to CRLF @@ -108,8 +120,8 @@ bool CMessages::ShowErrorWait ( QString strError, const QString strActionButtonT msgBox.setText ( strError ); return ( msgBox.exec() == 0 ); #else - Q_UNUSED ( strActionText ) - Q_UNUSED ( strAbortText ) + Q_UNUSED ( strActionButtonText ) + Q_UNUSED ( strAbortButtonText ) qCritical().noquote() << "Error: " << ToUtf8Printable ( strError ); return bDefault; #endif @@ -139,8 +151,8 @@ bool CMessages::ShowWarningWait ( QString strWarning, const QString strActionBut msgBox.setText ( strWarning ); return ( msgBox.exec() == 0 ); #else - Q_UNUSED ( strActionText ) - Q_UNUSED ( strAbortText ) + Q_UNUSED ( strActionButtonText ) + Q_UNUSED ( strAbortButtonText ) qWarning().noquote() << "Warning: " << ToUtf8Printable ( strWarning ); return bDefault; #endif @@ -170,8 +182,8 @@ bool CMessages::ShowInfoWait ( QString strInfo, const QString strActionButtonTex msgBox.setText ( strInfo ); return ( msgBox.exec() == 0 ); #else - Q_UNUSED ( strActionText ) - Q_UNUSED ( strAbortText ) + Q_UNUSED ( strActionButtonText ) + Q_UNUSED ( strAbortButtonText ) qInfo().noquote() << "Info: " << ToUtf8Printable ( strInfo ); return bDefault; #endif