diff --git a/.ci/Debian10/Dockerfile b/.ci/Debian10/Dockerfile index 5dda090e..9b8cb557 100644 --- a/.ci/Debian10/Dockerfile +++ b/.ci/Debian10/Dockerfile @@ -19,6 +19,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ qt5-default \ qtbase5-dev \ qtmultimedia5-dev \ + qttools5-dev \ qttools5-dev-tools \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/.ci/Fedora36/Dockerfile b/.ci/Fedora36/Dockerfile new file mode 100644 index 00000000..8225060a --- /dev/null +++ b/.ci/Fedora36/Dockerfile @@ -0,0 +1,14 @@ +FROM fedora:36 + +RUN dnf install -y \ + ccache \ + cmake \ + gcc-c++ \ + git \ + mariadb-devel \ + protobuf-devel \ + qt6-{qttools,qtsvg,qtmultimedia,qtwebsockets,qt5compat}-devel \ + rpm-build \ + xz-devel \ + zlib-devel \ + && dnf clean all diff --git a/.ci/UbuntuHirsute/Dockerfile b/.ci/UbuntuJammy/Dockerfile similarity index 57% rename from .ci/UbuntuHirsute/Dockerfile rename to .ci/UbuntuJammy/Dockerfile index e6d8998b..78279b32 100644 --- a/.ci/UbuntuHirsute/Dockerfile +++ b/.ci/UbuntuJammy/Dockerfile @@ -1,4 +1,4 @@ -FROM ubuntu:hirsute +FROM ubuntu:jammy RUN apt-get update && \ DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ @@ -9,16 +9,19 @@ RUN apt-get update && \ file \ g++ \ git \ + libgl-dev \ liblzma-dev \ libmariadb-dev-compat \ libprotobuf-dev \ - libqt5multimedia5-plugins \ - libqt5sql5-mysql \ - libqt5svg5-dev \ - libqt5websockets5-dev \ + libqt6core5compat6-dev \ + libqt6multimedia6 \ + libqt6sql6-mysql \ + libqt6svg6-dev \ + libqt6websockets6-dev \ protobuf-compiler \ - qtmultimedia5-dev \ - qttools5-dev \ - qttools5-dev-tools \ + qt6-l10n-tools \ + qt6-multimedia-dev \ + qt6-tools-dev \ + qt6-tools-dev-tools \ && apt-get clean \ && rm -rf /var/lib/apt/lists/* diff --git a/.ci/compile.sh b/.ci/compile.sh index 72c73781..a6bd6475 100755 --- a/.ci/compile.sh +++ b/.ci/compile.sh @@ -3,18 +3,18 @@ # This script is to be used by the ci environment from the project root directory, do not use it from somewhere else. # Compiles cockatrice inside of a ci environment -# --format runs the clang-format script first # --install runs make install # --package [] runs make package, optionally force the type # --suffix renames package with this suffix, requires arg # --server compiles servatrice # --test runs tests -# --debug or --release or sets the build type ie CMAKE_BUILD_TYPE -# --ccache uses ccache and shows stats +# --debug or --release sets the build type ie CMAKE_BUILD_TYPE +# --ccache [] uses ccache and shows stats, optionally provide size # --dir sets the name of the build dir, default is "build" -# uses env: BUILDTYPE CHECK_FORMAT MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_TEST USE_CCACHE BUILD_DIR (correspond to args: /--debug/--release --format --install --package --suffix --server --test --ccache --dir ) +# --parallel sets how many cores cmake should build with in parallel +# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_TEST USE_CCACHE CCACHE_SIZE BUILD_DIR PARALLEL_COUNT +# (correspond to args: --debug/--release --install --package --suffix --server --test --ccache --dir --parallel ) # exitcode: 1 for failure, 3 for invalid arguments -LINT_SCRIPT=".ci/lint_cpp.sh" # Read arguments while [[ $# != 0 ]]; do @@ -22,10 +22,6 @@ while [[ $# != 0 ]]; do '--') shift ;; - '--format') - CHECK_FORMAT=1 - shift - ;; '--install') MAKE_INSTALL=1 shift @@ -33,7 +29,7 @@ while [[ $# != 0 ]]; do '--package') MAKE_PACKAGE=1 shift - if [[ $# != 0 && $1 != -* ]]; then + if [[ $# != 0 && ${1:0:1} != - ]]; then PACKAGE_TYPE="$1" shift fi @@ -66,6 +62,10 @@ while [[ $# != 0 ]]; do '--ccache') USE_CCACHE=1 shift + if [[ $# != 0 && ${1:0:1} != - ]]; then + CCACHE_SIZE="$1" + shift + fi ;; '--dir') shift @@ -76,67 +76,81 @@ while [[ $# != 0 ]]; do BUILD_DIR="$1" shift ;; - *) - if [[ $1 == -* ]]; then - echo "::error file=$0::unrecognized option: $1" + '--parallel') + shift + if [[ $# == 0 ]]; then + echo "::error file=$0::--parallel expects an argument" exit 3 fi - BUILDTYPE="$1" + PARALLEL_COUNT="$1" shift ;; + *) + echo "::error file=$0::unrecognized option: $1" + exit 3 + ;; esac done -# Check formatting using clang-format -if [[ $CHECK_FORMAT ]]; then - echo "::group::Run linter" - source "$LINT_SCRIPT" - echo "::endgroup::" -fi - set -e # Setup ./servatrice/check_schema_version.sh +if [[ ! $BUILDTYPE ]]; then + BUILDTYPE=Release +fi if [[ ! $BUILD_DIR ]]; then BUILD_DIR="build" fi mkdir -p "$BUILD_DIR" cd "$BUILD_DIR" -if [[ ! $CMAKE_BUILD_PARALLEL_LEVEL ]]; then - CMAKE_BUILD_PARALLEL_LEVEL=2 # default machines have 2 cores -fi - # Add cmake flags -flags=() +flags=("-DCMAKE_BUILD_TYPE=$BUILDTYPE") if [[ $MAKE_SERVER ]]; then flags+=("-DWITH_SERVER=1") fi if [[ $MAKE_TEST ]]; then flags+=("-DTEST=1") fi -if [[ ! $BUILDTYPE ]]; then - BUILDTYPE=Release +if [[ $USE_CCACHE ]]; then + flags+=("-DUSE_CCACHE=1") + if [[ $CCACHE_SIZE ]]; then + # note, this setting persists after running the script + ccache --max-size "$CCACHE_SIZE" + fi fi -flags+=("-DCMAKE_BUILD_TYPE=$BUILDTYPE") if [[ $PACKAGE_TYPE ]]; then flags+=("-DCPACK_GENERATOR=$PACKAGE_TYPE") fi -if [[ $(uname) == "Darwin" ]]; then - if [[ $USE_CCACHE ]]; then - # prepend ccache compiler binaries to path - PATH="/usr/local/opt/ccache/libexec:$PATH" +# Add cmake --build flags +buildflags=(--config "$BUILDTYPE") +if [[ $PARALLEL_COUNT ]]; then + if [[ $(cmake --build /not_a_dir --parallel |& head -1) =~ parallel ]]; then + # workaround for bionic having an old cmake + echo "this version of cmake does not support --parallel, using native build tool -j instead" + buildflags+=(-- -j "$PARALLEL_COUNT") + # note, no normal build flags should be added after this + else + buildflags+=(--parallel "$PARALLEL_COUNT") fi - # Add qt install location when using homebrew - flags+=("-DCMAKE_PREFIX_PATH=/usr/local/opt/qt5/") fi +function ccachestatsverbose() { + # note, verbose only works on newer ccache, discard the error + local got + if got="$(ccache --show-stats --verbose 2>/dev/null)"; then + echo "$got" + else + ccache --show-stats + fi +} + # Compile if [[ $USE_CCACHE ]]; then echo "::group::Show ccache stats" - ccache --show-stats + ccachestatsverbose echo "::endgroup::" fi @@ -146,12 +160,12 @@ cmake .. "${flags[@]}" echo "::endgroup::" echo "::group::Build project" -cmake --build . --config "$BUILDTYPE" +cmake --build . "${buildflags[@]}" echo "::endgroup::" if [[ $USE_CCACHE ]]; then echo "::group::Show ccache stats again" - ccache --show-stats + ccachestatsverbose echo "::endgroup::" fi @@ -174,7 +188,8 @@ if [[ $MAKE_PACKAGE ]]; then if [[ $PACKAGE_SUFFIX ]]; then echo "::group::Update package name" - ../.ci/name_build.sh "$PACKAGE_SUFFIX" + cd .. + BUILD_DIR="$BUILD_DIR" .ci/name_build.sh "$PACKAGE_SUFFIX" echo "::endgroup::" fi fi diff --git a/.ci/docker.sh b/.ci/docker.sh index 12052309..c6ec1b77 100644 --- a/.ci/docker.sh +++ b/.ci/docker.sh @@ -10,7 +10,8 @@ # --interactive immediately starts the image interactively for debugging # --set-cache sets the location to cache the image or for ccache # requires: docker -# uses env: NAME CACHE BUILD GET SAVE INTERACTIVE (correspond to args: --set-cache --build --get --save --interactive) +# uses env: NAME CACHE BUILD GET SAVE INTERACTIVE +# (correspond to args: --set-cache --build --get --save --interactive) # sets env: RUN CCACHE_DIR IMAGE_NAME RUN_ARGS RUN_OPTS BUILD_SCRIPT # exitcode: 1 for failure, 2 for missing dockerfile, 3 for invalid arguments export BUILD_SCRIPT=".ci/compile.sh" @@ -48,7 +49,7 @@ while [[ $# != 0 ]]; do shift 2 ;; *) - if [[ $1 == -* ]]; then + if [[ ${1:0:1} == - ]]; then echo "unrecognized option: $1" return 3 fi @@ -74,26 +75,27 @@ fi if ! [[ $CACHE ]]; then echo "cache dir is not set!" >&2 -else - if ! [[ -d $CACHE ]]; then - echo "could not find cache dir: $CACHE" >&2 - mkdir -p "$CACHE" - unset GET # the dir is empty - fi - if [[ $GET || $SAVE ]]; then - img_dir="$CACHE/$image_cache" - img_save="$img_dir/$IMAGE_NAME$save_extension" - if ! [[ -d $img_dir ]]; then - echo "could not find image dir: $img_dir" >&2 - mkdir -p "$img_dir" - fi - fi - export CCACHE_DIR="$CACHE/$ccache_cache" - if ! [[ -d $CCACHE_DIR ]]; then - echo "could not find ccache dir: $CCACHE_DIR" >&2 - mkdir -p "$CCACHE_DIR" + CACHE="$(mktemp -d)" + echo "set cache dir to $CACHE" >&2 +fi +if ! [[ -d $CACHE ]]; then + echo "could not find cache dir: $CACHE" >&2 + mkdir -p "$CACHE" + unset GET # the dir is empty +fi +if [[ $GET || $SAVE ]]; then + img_dir="$CACHE/$image_cache" + img_save="$img_dir/$IMAGE_NAME$save_extension" + if ! [[ -d $img_dir ]]; then + echo "could not find image dir: $img_dir" >&2 + mkdir -p "$img_dir" fi fi +export CCACHE_DIR="$CACHE/$ccache_cache" +if ! [[ -d $CCACHE_DIR ]]; then + echo "could not find ccache dir: $CCACHE_DIR" >&2 + mkdir -p "$CCACHE_DIR" +fi # Get the docker image from previously stored save if [[ $GET ]]; then @@ -138,7 +140,7 @@ fi function RUN () { echo "running image:" - if docker images | grep "$IMAGE_NAME"; then + if [[ $(docker images) =~ "$IMAGE_NAME" ]]; then local args=(--mount "type=bind,source=$PWD,target=/src") args+=(--workdir "/src") args+=(--user "$(id -u):$(id -g)") diff --git a/.ci/download_openssl.sh b/.ci/download_openssl.sh new file mode 100644 index 00000000..c6c75eb8 --- /dev/null +++ b/.ci/download_openssl.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Read arguments +while [[ $# != 0 ]]; do + case "$1" in + '--') + shift + ;; + '--arch') + shift + if [[ $# == 0 ]]; then + echo "::error file=$0::--arch expects an argument" + exit 3 + fi + OS_ARCH="$1" + shift + ;; + *) + echo "::error file=$0::unrecognized option: $1" + exit 3 + ;; + esac +done + +set -e + +OPEN_SSL_VERSION="1.1.1n" +DEST_PATH="C:\OpenSSL-Win$OS_ARCH" + +curl -JLSs "https://github.com/CristiFati/Prebuilt-Binaries/raw/master/OpenSSL/v1.1.1/OpenSSL-$OPEN_SSL_VERSION-Win-pc0$OS_ARCH.zip" -o OpenSSL.zip +unzip -q "OpenSSL.zip" +rm "OpenSSL.zip" +mv "OpenSSL\OpenSSL\\$OPEN_SSL_VERSION" "$DEST_PATH" +rm -r "OpenSSL" +echo "Installed OpenSSL v$OPEN_SSL_VERSION to $DEST_PATH" \ No newline at end of file diff --git a/.ci/lint_cpp.sh b/.ci/lint_cpp.sh index e8939da9..0c06972a 100755 --- a/.ci/lint_cpp.sh +++ b/.ci/lint_cpp.sh @@ -42,11 +42,11 @@ ${diff#* Exiting... EOM - exit 2 - ;; + exit 2 + ;; - 0) - cat <&2 - echo "" - ;; - esac + *) + echo "" + echo "Something went wrong in our formatting checks: clangify returned $err" >&2 + echo "" + ;; +esac diff --git a/.ci/name_build.sh b/.ci/name_build.sh index d322f727..b7413b29 100755 --- a/.ci/name_build.sh +++ b/.ci/name_build.sh @@ -3,8 +3,8 @@ # renames the file to [original name][SUFFIX].[original extension] # where SUFFIX is either available in the environment or as the first arg # if MAKE_ZIP is set instead a zip is made -# expected to be run in the build directory -builddir="." +# expected to be run in the build directory unless BUILD_DIR is set +builddir="${BUILD_DIR:=.}" findrx="Cockatrice-*.*" if [[ $1 ]]; then @@ -27,6 +27,7 @@ if [[ ! $file ]]; then echo "::error file=$0::could not find package" exit 1 fi +oldpwd="$PWD" if ! cd "$path"; then echo "::error file=$0::could not get file path" exit 1 @@ -45,6 +46,9 @@ else echo "renaming '$file' to '$filename'" mv "$file" "$filename" fi -ls -l "$PWD/$filename" -echo "::set-output name=path::$PWD/$filename" + +cd "$oldpwd" +relative_path="$path/$filename" +ls -l "$relative_path" +echo "::set-output name=path::$relative_path" echo "::set-output name=name::$filename" diff --git a/.ci/release_template.md b/.ci/release_template.md index 3c8c9d9d..e831fb15 100644 --- a/.ci/release_template.md +++ b/.ci/release_template.md @@ -8,18 +8,20 @@ git push -d origin --REPLACE-WITH-BETA-LIST-- include different targets -->
 Pre-compiled binaries we serve:
- - Windows 7/8/10 (32-bit)
- - Windows 7/8/10 (64-bit)
- - macOS 10.14 ("Mojave")
- - macOS 10.15 ("Catalina")
- - macOS 11.0 ("Big Sur")
- - Ubuntu 18.04 ("Bionic Beaver")
- - Ubuntu 20.04 ("Focal Fossa")
- - Ubuntu 20.10 ("Groovy Gorilla")
- - Ubuntu 21.04 ("Hirsute Hippo")
- - Debian 10 ("Buster")
- - Fedora 33
- - Fedora 34
+ - Windows 7/8/10/11 (32-bit)
+ - Windows 7/8/10/11 (64-bit)
+ - macOS 10.14 ("Mojave")
+ - macOS 10.15 ("Catalina")
+ - macOS 11.0 ("Big Sur")
+ - Ubuntu 18.04 ("Bionic Beaver")
+ - Ubuntu 20.04 ("Focal Fossa")
+ - Ubuntu 21.10 ("Impish Indri")
+ - Ubuntu 22.04 ("Jammy Jellyfish")
+ - Debian 10 ("Buster")
+ - Debian 11 ("Bullseye")
+ - Fedora 34
+ - Fedora 35
+ - Fedora 36
 We are also packaged in Arch Linux's official community repository, courtesy of @FFY00
 General linux support is available via a flatpak package (Flathub)
 
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index dc8c1d20..bb8dba57 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -19,9 +19,7 @@ on: jobs: configure: name: Configure - runs-on: ubuntu-latest - outputs: tag: ${{steps.configure.outputs.tag}} sha: ${{steps.configure.outputs.sha}} @@ -55,7 +53,7 @@ jobs: with: fetch-depth: 0 - - name: Prepare release paramaters + - name: Prepare release parameters id: prepare if: steps.configure.outputs.tag != null shell: bash @@ -88,6 +86,7 @@ jobs: - distro: Debian10 package: DEB + test: skip # running tests on all distros is superfluous - distro: Debian11 package: DEB @@ -98,6 +97,10 @@ jobs: - distro: Fedora35 package: RPM + test: skip + + - distro: Fedora36 + package: RPM - distro: UbuntuBionic package: DEB @@ -106,24 +109,23 @@ jobs: package: DEB test: skip # UbuntuFocal has a broken qt for debug builds - - distro: UbuntuHirsute + - distro: UbuntuImpish package: DEB test: skip - - distro: UbuntuImpish + - distro: UbuntuJammy package: DEB name: ${{matrix.distro}} - needs: configure - runs-on: ubuntu-latest - continue-on-error: ${{matrix.allow-failure == 'yes'}} - env: NAME: ${{matrix.distro}} CACHE: /tmp/${{matrix.distro}}-cache # ${{runner.temp}} does not work? + # cache size over the entire repo is 10Gi link: + # https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy + CCACHE_SIZE: 200M steps: - name: Checkout @@ -151,9 +153,11 @@ jobs: - name: Build debug and test if: matrix.test != 'skip' shell: bash + env: + distro: '${{matrix.distro}}' run: | source .ci/docker.sh - RUN --server --debug --test --ccache + RUN --server --debug --test --ccache "$CCACHE_SIZE" --parallel 2 - name: Build release package id: package @@ -162,16 +166,18 @@ jobs: env: suffix: '-${{matrix.distro}}' type: '${{matrix.package}}' + distro: '${{matrix.distro}}' run: | source .ci/docker.sh - RUN --server --release --package "$type" --suffix "$suffix" + RUN --server --release --package "$type" --suffix "$suffix" \ + --ccache "$CCACHE_SIZE" --parallel 2 - name: Upload artifact if: matrix.package != 'skip' uses: actions/upload-artifact@v2 with: name: ${{matrix.distro}}-package - path: ./build/${{steps.package.outputs.name}} + path: ${{steps.package.outputs.path}} if-no-files-found: error - name: Upload to release @@ -181,7 +187,7 @@ jobs: GITHUB_TOKEN: ${{github.token}} with: upload_url: ${{needs.configure.outputs.upload_url}} - asset_path: ./build/${{steps.package.outputs.name}} + asset_path: ${{steps.package.outputs.path}} asset_name: ${{steps.package.outputs.name}} asset_content_type: application/octet-stream @@ -193,39 +199,46 @@ jobs: - target: Debug # tests only os: macos-latest xcode: 12.5.1 + qt_version: 6 type: Debug - do_tests: 0 # tests do not work yet on mac - make_package: false + do_tests: 1 - target: 10.14_Mojave os: macos-10.15 # runs on Catalina xcode: 10.3 # allows compatibility with macOS 10.14 + qt_version: 5 type: Release - do_tests: 0 - make_package: true + # do_tests: 1 # tests do not work on qt5? + make_package: 1 - target: 10.15_Catalina os: macos-10.15 - xcode: 12.1 + xcode: 12.4 + qt_version: 6 type: Release - do_tests: 0 - make_package: true + do_tests: 1 + make_package: 1 - target: 11_Big_Sur os: macos-11 - xcode: 12.5.1 + xcode: 13.2 + qt_version: 6 type: Release - do_tests: 0 - make_package: true + do_tests: 1 + make_package: 1 + +# - target: 12_Monterey +# os: macos-12 +# xcode: 13.3 +# qt_version: 6 +# type: Release +# do_tests: 1 +# make_package: 1 name: macOS ${{matrix.target}} - needs: configure - runs-on: ${{matrix.os}} - continue-on-error: ${{matrix.allow-failure == 'yes'}} - env: DEVELOPER_DIR: /Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer @@ -238,45 +251,32 @@ jobs: shell: bash # cmake cannot find the mysql connector # neither of these works: mariadb-connector-c mysql-connector-c++ - run: brew update && brew install protobuf - - - name: Install QT using homebrew - id: brew_install_qt - continue-on-error: true - shell: bash - run: brew install qt@5 --force-bottle - - - name: Install QT using actions - if: steps.brew_install_qt.outcome != 'success' - uses: jurplel/install-qt-action@v2 + env: + qt_version: 'qt@${{matrix.qt_version}}' + run: | + brew update + brew install protobuf + brew install "$qt_version" --force-bottle - name: Build on Xcode ${{matrix.xcode}} shell: bash + id: build env: - CMAKE_BUILD_PARALLEL_LEVEL: 3 # mac machines actually have 3 cores - run: .ci/compile.sh ${{matrix.type}} --server - - - name: Test - if: matrix.do_tests == 1 - shell: bash - working-directory: build - run: cmake --build . --target test - - - name: Package for ${{matrix.target}} - id: package - if: matrix.make_package - shell: bash - working-directory: build - run: | - cmake --build . --target package - ../.ci/name_build.sh "-macOS-${{matrix.target}}" + BUILDTYPE: '${{matrix.type}}' + MAKE_TEST: '${{matrix.do_tests}}' + MAKE_PACKAGE: '${{matrix.make_package}}' + PACKAGE_SUFFIX: '-macOS-${{matrix.target}}' + # set QTDIR to find qt5, qt6 can be found without this + QTDIR: '/usr/local/opt/qt5' + # Mac machines actually have 3 cores + run: .ci/compile.sh --server --parallel 3 - name: Upload artifact if: matrix.make_package uses: actions/upload-artifact@v2 with: name: macOS-${{matrix.target}}-dmg - path: ${{steps.package.outputs.path}} + path: ${{steps.build.outputs.path}} if-no-files-found: error - name: Upload to release @@ -286,8 +286,8 @@ jobs: GITHUB_TOKEN: ${{github.token}} with: upload_url: ${{needs.configure.outputs.upload_url}} - asset_path: ${{steps.package.outputs.path}} - asset_name: ${{steps.package.outputs.name}} + asset_path: ${{steps.build.outputs.path}} + asset_name: ${{steps.build.outputs.name}} asset_content_type: application/octet-stream build-windows: @@ -296,24 +296,22 @@ jobs: matrix: include: - arch: 32 - triplet: x86 - cmake: Win32 - + vcpkg_default_triplet: x86 + qt_version: '5.15.2' + cmake_generator_platform: Win32 + qt_arch: msvc2019 - arch: 64 - triplet: x64 - cmake: x64 - append: _64 - - name: Windows ${{matrix.arch}}-bit + vcpkg_default_triplet: x64 + qt_version: '6.3.0' + cmake_generator_platform: x64 + qt_arch: msvc2019_64 + qt_modules: "qt5compat qtmultimedia qtwebsockets" + name: Windows (${{matrix.arch}}-bit) needs: configure - runs-on: windows-2019 - env: - QT_VERSION: '5.15.2' - QT_ARCH: msvc2022${{matrix.append}} - CMAKE_GENERATOR: 'Visual Studio 17 2022' + CMAKE_GENERATOR: 'Visual Studio 16 2019' steps: - name: Add msbuild to PATH @@ -321,46 +319,57 @@ jobs: uses: microsoft/setup-msbuild@v1.1 - name: Checkout - uses: actions/checkout@v2 + uses: actions/checkout@v3 with: submodules: recursive - - name: Restore Qt ${{env.QT_VERSION}} ${{matrix.arch}}-bit from cache + - name: Restore Qt ${{matrix.qt_version}} (${{matrix.arch}}-bit) from cache id: cache-qt - uses: actions/cache@v2 + uses: actions/cache@v1 # Intentionally v1, based on jurplel documentation with: - key: ${{runner.os}}-QtCache-${{env.QT_VERSION}}-${{matrix.arch}} - path: ${{runner.workspace}}/Qt + key: ${{runner.os}}-QtCache-${{matrix.qt_version}}-${{matrix.arch}} + path: '${{github.workspace}}/../Qt' - - name: Install ${{matrix.arch}}-bit Qt - uses: jurplel/install-qt-action@v2 + - name: Install Qt ${{matrix.qt_version}} (${{matrix.arch}}-bit) + uses: jurplel/install-qt-action@v3 with: cached: ${{steps.cache-qt.outputs.cache-hit}} - version: ${{env.QT_VERSION}} - arch: win${{matrix.arch}}_${{env.QT_ARCH}} + version: ${{matrix.qt_version}} + arch: win${{matrix.arch}}_${{matrix.qt_arch}} + modules: ${{matrix.qt_modules}} - - name: Restore or setup vcpkg - uses: lukka/run-vcpkg@v6 + - name: Run vcpkg + uses: lukka/run-vcpkg@v10.2 with: - vcpkgArguments: '@${{github.workspace}}/vcpkg.txt' - vcpkgDirectory: ${{github.workspace}}/vcpkg - appendedCacheKey: ${{hashFiles('**/vcpkg.txt')}} - vcpkgTriplet: ${{matrix.triplet}}-windows + runVcpkgInstall: true + appendedCacheKey: ${{matrix.arch}}-bit + env: + VCPKG_DEFAULT_TRIPLET: '${{matrix.vcpkg_default_triplet}}-windows' + VCPKG_DISABLE_METRICS: 1 - - name: Build Cockatrice ${{matrix.arch}}-bit + - name: Install OpenSSL (${{matrix.arch}}-bit) + shell: bash + run: .ci/download_openssl.sh --arch ${{matrix.arch}} + + - name: Build Cockatrice (${{matrix.arch}}-bit) id: build shell: bash env: PACKAGE_SUFFIX: '-win${{matrix.arch}}' CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}' - CMAKE_GENERATOR_PLATFORM: '${{matrix.cmake}}' - run: ./.ci/compile.sh --server --release --test --package + CMAKE_GENERATOR_PLATFORM: '${{matrix.cmake_generator_platform}}' + QTDIR: '${{github.workspace}}\Qt\${{matrix.qt_version}}\win${{matrix.arch}}_${{matrix.qt_arch}}' + run: .ci/compile.sh --server --release --test --package --parallel 2 + + - name: Setup tmate session + if: ${{ failure() }} + uses: mxschmitt/action-tmate@v3 - name: Upload artifact - uses: actions/upload-artifact@v2 + uses: actions/upload-artifact@v3 with: name: Windows-${{matrix.arch}}bit-installer - path: ./build/${{steps.build.outputs.name}} + path: ${{steps.build.outputs.path}} if-no-files-found: error - name: Upload to release @@ -370,6 +379,6 @@ jobs: GITHUB_TOKEN: ${{github.token}} with: upload_url: ${{needs.configure.outputs.upload_url}} - asset_path: ./build/${{steps.build.outputs.name}} + asset_path: ${{steps.build.outputs.path}} asset_name: ${{steps.build.outputs.name}} asset_content_type: application/octet-stream diff --git a/.gitignore b/.gitignore index 48263d80..2f4277ab 100644 --- a/.gitignore +++ b/.gitignore @@ -6,7 +6,7 @@ mysql.cnf .DS_Store .idea/ *.aps -cmake-build-debug/ +cmake-build-debug* preferences compile_commands.json .vs/ diff --git a/CMakeLists.txt b/CMakeLists.txt index 38759aad..2a701481 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,9 +5,26 @@ # This file sets all the variables shared between the projects # like the installation path, compilation flags etc.. -# Cmake 3.1 is required to enable C++11 support correctly +# cmake 3.16 is required if using qt6 cmake_minimum_required(VERSION 3.10) +# Early detect ccache +option(USE_CCACHE "Cache the build results with ccache" ON) +# Treat warnings as errors (Debug builds only) +option(WARNING_AS_ERROR "Treat warnings as errors in debug builds" ON) +# Check for translation updates +option(UPDATE_TRANSLATIONS "Update translations on compile" OFF) +# Compile servatrice +option(WITH_SERVER "build servatrice" OFF) +# Compile cockatrice +option(WITH_CLIENT "build cockatrice" ON) +# Compile oracle +option(WITH_ORACLE "build oracle" ON) +# Compile dbconverter +option(WITH_DBCONVERTER "build dbconverter" ON) +# Compile tests +option(TEST "build tests" OFF) + # Default to "Release" build type # User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call IF(DEFINED CMAKE_BUILD_TYPE) @@ -16,8 +33,6 @@ ELSE() SET(CMAKE_BUILD_TYPE Release CACHE STRING "Type of build") ENDIF() -# Early detect ccache -OPTION(USE_CCACHE "Cache the build results with ccache" ON) if(USE_CCACHE) find_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) @@ -41,22 +56,23 @@ endif() # A project name is needed for CPack # Version can be overriden by git tags, see cmake/getversion.cmake -PROJECT("Cockatrice" VERSION 2.8.1) +project("Cockatrice" VERSION 2.8.1) # Set release name if not provided via env/cmake var if(NOT DEFINED GIT_TAG_RELEASENAME) set(GIT_TAG_RELEASENAME "Prismatic Bridge") endif() -# Use c++11 for all targets -set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ ISO Standard") +# Use c++17 for all targets +set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ ISO Standard") set(CMAKE_CXX_STANDARD_REQUIRED True) # Set conventional loops set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) # Search path for cmake modules -SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) +set(COCKATRICE_CMAKE_PATH "${PROJECT_SOURCE_DIR}/cmake") +list(INSERT CMAKE_MODULE_PATH 0 "${COCKATRICE_CMAKE_PATH}") include(getversion) @@ -76,8 +92,8 @@ if(UNIX) if(RULE_LAUNCH_COMPILE) MESSAGE(STATUS "Force enabling CCache usage under macOS") # Set up wrapper scripts - configure_file(${CMAKE_MODULE_PATH}/launch-c.in launch-c) - configure_file(${CMAKE_MODULE_PATH}/launch-cxx.in launch-cxx) + configure_file("${COCKATRICE_CMAKE_PATH}/launch-c.in" launch-c) + configure_file("${COCKATRICE_CMAKE_PATH}/launch-cxx.in" launch-cxx) execute_process(COMMAND chmod a+rx "${CMAKE_BINARY_DIR}/launch-c" "${CMAKE_BINARY_DIR}/launch-cxx") @@ -103,13 +119,10 @@ elseif(WIN32) set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/rundir/${CMAKE_BUILD_TYPE}) endif() -# Treat warnings as errors (Debug builds only) -option(WARNING_AS_ERROR "Treat warnings as errors in debug builds" ON) - # Define proper compilation flags IF(MSVC) - # Visual Studio: Maximum optimization, disable warning C4251 - set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251 ") + # Visual Studio: Maximum optimization, disable warning C4251, establish C++17 compatibility + SET(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251 /Zc:__cplusplus /std:c++17 /permissive-") # Generate complete debugging information #set(CMAKE_CXX_FLAGS_DEBUG "/Zi") ELSEIF (CMAKE_COMPILER_IS_GNUCXX) @@ -123,6 +136,10 @@ ELSEIF (CMAKE_COMPILER_IS_GNUCXX) set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -Wall -Wextra") endif() + IF(APPLE) + SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17") + ENDIF() + set(ADDITIONAL_DEBUG_FLAGS -Wcast-align -Wmissing-declarations -Wno-long-long -Wno-error=extra -Wno-error=delete-non-virtual-dtor -Wno-error=sign-compare -Wno-error=missing-declarations) FOREACH(FLAG ${ADDITIONAL_DEBUG_FLAGS}) @@ -148,7 +165,7 @@ ENDIF() FIND_PACKAGE(Threads REQUIRED) -# Find Qt5 +# Determine 32 or 64 bit build if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(_lib_suffix 64) else() @@ -165,28 +182,9 @@ elseif(DEFINED ENV{QTDIR}) list(APPEND CMAKE_PREFIX_PATH "$ENV{QTDIR}") endif() -FIND_PACKAGE(Qt5Core 5.5.0 REQUIRED) +MESSAGE(STATUS "Update Translations: ${UPDATE_TRANSLATIONS}") -IF(Qt5Core_FOUND) - MESSAGE(STATUS "Found Qt ${Qt5Core_VERSION_STRING}") - - # FIX: Qt was built with -reduce-relocations - if (Qt5_POSITION_INDEPENDENT_CODE) - SET(CMAKE_POSITION_INDEPENDENT_CODE ON) - endif() - - # guess plugins and libraries directory - set(QT_PLUGINS_DIR "${Qt5Core_DIR}/../../../plugins") - get_target_property(QT_LIBRARY_DIR Qt5::Core LOCATION) - get_filename_component(QT_LIBRARY_DIR ${QT_LIBRARY_DIR} PATH) - -ELSE() - MESSAGE(FATAL_ERROR "No Qt5 found!") -ENDIF() - -# Check for translation updates -OPTION(UPDATE_TRANSLATIONS "Update translations on compile" OFF) -MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}") +include(FindQtRuntime) set(CMAKE_AUTOMOC TRUE) @@ -195,7 +193,7 @@ FIND_PACKAGE(Protobuf REQUIRED) IF(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}") MESSAGE(FATAL_ERROR "No protoc command found!") ELSE() - MESSAGE(STATUS "Protoc version ${Protobuf_VERSION} found!") + MESSAGE(STATUS "Found Protobuf ${Protobuf_VERSION} at: ${Protobuf_LIBRARIES}") ENDIF() #Find OpenSSL @@ -209,8 +207,8 @@ IF(MSVC) ENDIF() # Package builder -set(CPACK_PACKAGE_CONTACT "Zach Halpern ") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_NAME}) +set(CPACK_PACKAGE_CONTACT "Zach Halpern ") +set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_NAME}") set(CPACK_PACKAGE_VENDOR "Cockatrice Development Team") set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md") set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") @@ -231,15 +229,33 @@ if(UNIX) # linux IF(CPACK_GENERATOR STREQUAL "RPM") set(CPACK_RPM_PACKAGE_LICENSE "GPLv2") - set(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt5-qttools, qt5-qtsvg, qt5-qtmultimedia") + set(CPACK_RPM_MAIN_COMPONENT "cockatrice") + IF(Qt6_FOUND) + SET(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt6-qttools, qt6-qtsvg, qt6-qtmultimedia") + ELSEIF(Qt5_FOUND) + SET(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt5-qttools, qt5-qtsvg, qt5-qtmultimedia") + ENDIF() set(CPACK_RPM_PACKAGE_GROUP "Amusements/Games") set(CPACK_RPM_PACKAGE_URL "http://github.com/Cockatrice/Cockatrice") + # stop directories from making package conflicts + set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION + /usr/share/applications + /usr/share/icons + /usr/share/icons/hicolor + /usr/share/icons/hicolor/48x48 + /usr/share/icons/hicolor/48x48/apps + /usr/share/icons/hicolor/scalable + /usr/share/icons/hicolor/scalable/apps) ELSE() set(CPACK_GENERATOR DEB) set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) set(CPACK_DEBIAN_PACKAGE_SECTION "games") set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://github.com/Cockatrice/Cockatrice") - set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5") + IF(Qt6_FOUND) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins") + ELSEIF(Qt5_FOUND) + set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5") + ENDIF() ENDIF() endif() elseif(WIN32) @@ -252,8 +268,8 @@ elseif(WIN32) # Configure file with custom definitions for NSIS. configure_file( - ${CMAKE_MODULE_PATH}/NSIS.definitions.nsh.in - ${PROJECT_BINARY_DIR}/NSIS.definitions.nsh + "${COCKATRICE_CMAKE_PATH}/NSIS.definitions.nsh.in" + "${PROJECT_BINARY_DIR}/NSIS.definitions.nsh" ) # include vcredist into the package; NSIS will take care of running it @@ -264,38 +280,33 @@ endif() include(CPack) -# Compile servatrice (default off) -option(WITH_SERVER "build servatrice" OFF) add_subdirectory(common) if(WITH_SERVER) add_subdirectory(servatrice) SET(CPACK_INSTALL_CMAKE_PROJECTS "Servatrice;Servatrice;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS}) endif() -# Compile cockatrice (default on) -option(WITH_CLIENT "build cockatrice" ON) if(WITH_CLIENT) add_subdirectory(cockatrice) SET(CPACK_INSTALL_CMAKE_PROJECTS "Cockatrice;Cockatrice;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS}) endif() -# Compile oracle (default on) -option(WITH_ORACLE "build oracle" ON) if(WITH_ORACLE) add_subdirectory(oracle) SET(CPACK_INSTALL_CMAKE_PROJECTS "Oracle;Oracle;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS}) endif() -# Compile dbconverter (default on) -option(WITH_DBCONVERTER "build dbconverter" ON) if(WITH_DBCONVERTER) add_subdirectory(dbconverter) SET(CPACK_INSTALL_CMAKE_PROJECTS "Dbconverter;Dbconverter;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS}) endif() -# Compile tests (default off) -option(TEST "build tests" OFF) if(TEST) include(CTest) add_subdirectory(tests) endif() + +if(Qt6Found AND Qt6_VERSION_MINOR GREATER_EQUAL 3) + # Qt6.3+ requires project finalization to support translations + qt6_finalize_project() +endif() diff --git a/README.md b/README.md index 06ec7ed5..965dafba 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,7 @@ The following flags can be passed to `cmake`: - `-DWARNING_AS_ERROR=0` Whether to treat compilation warnings as errors in debug mode (default 1 = yes). - `-DUPDATE_TRANSLATIONS=1` Configure `make` to update the translation .ts files for new strings in the source code. Note: Running `make clean` will remove the .ts files (default 0 = no). - `-DTEST=1` Enable regression tests (default 0 = no). Note: needs googletest, will be downloaded on the fly if unavailable. To run tests: ```make test```. +- `-DFORCE_USE_QT5=1` Skip looking for Qt6 before trying to find Qt5 # Run diff --git a/cmake/FindQtRuntime.cmake b/cmake/FindQtRuntime.cmake new file mode 100644 index 00000000..8fe736cd --- /dev/null +++ b/cmake/FindQtRuntime.cmake @@ -0,0 +1,118 @@ +# Find a compatible Qt version +# Inputs: WITH_SERVER, WITH_CLIENT, WITH_ORACLE, WITH_DBCONVERTER, FORCE_USE_QT5 +# Optional Input: QT6_DIR -- Hint as to where Qt6 lives on the system +# Optional Input: QT5_DIR -- Hint as to where Qt5 lives on the system +# Output: COCKATRICE_QT_VERSION_NAME -- Example values: Qt5, Qt6 +# Output: SERVATRICE_QT_MODULES +# Output: COCKATRICE_QT_MODULES +# Output: ORACLE_QT_MODULES +# Output: DBCONVERTER_QT_MODULES +# Output: TEST_QT_MODULES + +set(REQUIRED_QT_COMPONENTS Core) +if(WITH_SERVER) + set(_SERVATRICE_NEEDED Network Sql WebSockets) +endif() +if(WITH_CLIENT) + set(_COCKATRICE_NEEDED Concurrent Gui Multimedia Network PrintSupport Svg Widgets WebSockets) +endif() +if(WITH_ORACLE) + set(_ORACLE_NEEDED Concurrent Network Svg Widgets) +endif() +if(WITH_DBCONVERTER) + set(_DBCONVERTER_NEEDED Network Widgets) +endif() +if(TEST) + set(_TEST_NEEDED Widgets) +endif() + +set(REQUIRED_QT_COMPONENTS + ${REQUIRED_QT_COMPONENTS} + ${_SERVATRICE_NEEDED} + ${_COCKATRICE_NEEDED} + ${_ORACLE_NEEDED} + ${_DBCONVERTER_NEEDED} + ${_TEST_NEEDED}) +list(REMOVE_DUPLICATES REQUIRED_QT_COMPONENTS) + +if(NOT FORCE_USE_QT5) + # Core5Compat is Qt6 Only, Linguist is now a component in Qt6 instead of an external package + find_package(Qt6 6.2.3 + COMPONENTS Core5Compat ${REQUIRED_QT_COMPONENTS} + OPTIONAL_COMPONENTS Linguist + QUIET + HINTS ${Qt6_DIR}) +endif() +if(Qt6_FOUND) + set(COCKATRICE_QT_VERSION_NAME Qt6) + + if(Qt6LinguistTools_FOUND) + list(FIND Qt6LinguistTools_TARGETS Qt6::lrelease QT6_LRELEASE_INDEX) + if(QT6_LRELEASE_INDEX EQUAL -1) + message(WARNING "Qt6 lrelease not found.") + endif() + + list(FIND Qt6LinguistTools_TARGETS Qt6::lupdate QT6_LUPDATE_INDEX) + if(QT6_LUPDATE_INDEX EQUAL -1) + message(WARNING "Qt6 lupdate not found.") + endif() + endif() +else() + find_package(Qt5 5.8.0 + COMPONENTS ${REQUIRED_QT_COMPONENTS} + QUIET + HINTS ${Qt5_DIR}) + if(Qt5_FOUND) + set(COCKATRICE_QT_VERSION_NAME Qt5) + else() + message(FATAL_ERROR "No suitable version of Qt was found") + endif() + + # Qt5 Linguist is in a separate package + find_package(Qt5LinguistTools QUIET) + if (Qt5LinguistTools_FOUND) + if(NOT Qt5_LRELEASE_EXECUTABLE) + message(WARNING "Qt5 lrelease not found.") + endif() + if(NOT Qt5_LUPDATE_EXECUTABLE) + message(WARNING "Qt5 lupdate not found.") + endif() + else() + message(WARNING "Linguist Tools not found, cannot handle translations") + endif() +endif() + +if(Qt5_POSITION_INDEPENDENT_CODE OR Qt6_FOUND) + set(CMAKE_POSITION_INDEPENDENT_CODE ON) +endif() + +# Establish Qt Plugins directory & Library directories +get_target_property(QT_LIBRARY_DIR ${COCKATRICE_QT_VERSION_NAME}::Core LOCATION) +get_filename_component(QT_LIBRARY_DIR ${QT_LIBRARY_DIR} DIRECTORY) +if(Qt6_FOUND) + get_filename_component(QT_PLUGINS_DIR "${Qt6Core_DIR}/../../../${QT6_INSTALL_PLUGINS}" ABSOLUTE) + get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/../../.." ABSOLUTE) + if(UNIX AND APPLE) + # Mac needs a bit more help finding all necessary components + list(APPEND QT_LIBRARY_DIR "/usr/local/lib") + endif() +elseif(Qt5_FOUND) + get_filename_component(QT_PLUGINS_DIR "${Qt5Core_DIR}/../../../plugins" ABSOLUTE) + get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/.." ABSOLUTE) +endif() +message(DEBUG "QT_PLUGINS_DIR = ${QT_PLUGINS_DIR}") +message(DEBUG "QT_LIBRARY_DIR = ${QT_LIBRARY_DIR}") + +# Establish exports +string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" SERVATRICE_QT_MODULES "${_SERVATRICE_NEEDED}") +string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" COCKATRICE_QT_MODULES "${_COCKATRICE_NEEDED}") +string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" ORACLE_QT_MODULES "${_ORACLE_NEEDED}") +string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" DB_CONVERTER_QT_MODULES "${_DBCONVERTER_NEEDED}") +string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" TEST_QT_MODULES "${_TEST_NEEDED}") +if(Qt6_FOUND) + list(APPEND SERVATRICE_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Core5Compat) + list(APPEND COCKATRICE_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Core5Compat) + LIST(APPEND ORACLE_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Core5Compat) +endif() + +message(STATUS "Found Qt ${${COCKATRICE_QT_VERSION_NAME}_VERSION} at: ${${COCKATRICE_QT_VERSION_NAME}_DIR}") \ No newline at end of file diff --git a/cmake/FindWin32SslRuntime.cmake b/cmake/FindWin32SslRuntime.cmake index a3a1998e..0d3506fd 100644 --- a/cmake/FindWin32SslRuntime.cmake +++ b/cmake/FindWin32SslRuntime.cmake @@ -1,66 +1,44 @@ # Find the OpenSSL runtime libraries (.dll) for Windows that # will be needed by Qt in order to access https urls. +if(NOT DEFINED WIN32 OR NOT ${WIN32}) + message(STATUS "Non-Windows device trying to execute FindWin32SslRuntime, skipping") + return() +endif() -if (WIN32) - # Get standard installation paths for OpenSSL under Windows +if("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "x64") + message(STATUS "Looking for OpenSSL for ${CMAKE_GENERATOR_PLATFORM}") + file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) + set(_OPENSSL_ROOT_PATHS + "$ENV{VCPKG_PACKAGES_DIR}/x64-windows/bin" + "C:/OpenSSL-Win64/bin" + "C:/OpenSSL-Win64" + "C:/Tools/vcpkg/installed/x64-windows/bin" + "${_programfiles}/OpenSSL-Win64" + ) + unset(_programfiles) +elseif("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "Win32") + message(STATUS "Looking for OpenSSL for ${CMAKE_GENERATOR_PLATFORM}") + file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) + set(_OPENSSL_ROOT_PATHS + "$ENV{VCPKG_PACKAGES_DIR}/x86-windows/bin" + "C:/OpenSSL-Win32/bin" + "C:/OpenSSL-Win32" + "C:/OpenSSL" + "C:/Tools/vcpkg/installed/x86-windows/bin" + "${_programfiles}/OpenSSL" + "${_programfiles}/OpenSSL-Win32" + ) + unset(_programfiles) +endif() - # http://www.slproweb.com/products/Win32OpenSSL.html - - if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) - # target win64 - set(_OPENSSL_ROOT_HINTS - ${OPENSSL_ROOT_DIR} - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]" - ENV OPENSSL_ROOT_DIR - ) - file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) - set(_OPENSSL_ROOT_PATHS - "C:/Tools/vcpkg/installed/x64-windows/bin" - "${_programfiles}/OpenSSL-Win64" - "C:/OpenSSL-Win64/" - ) - unset(_programfiles) - else( CMAKE_SIZEOF_VOID_P EQUAL 8 ) - # target win32 - set(_OPENSSL_ROOT_HINTS - ${OPENSSL_ROOT_DIR} - "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]" - ENV OPENSSL_ROOT_DIR - ) - file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles) - set(_OPENSSL_ROOT_PATHS - "C:/Tools/vcpkg/installed/x86-windows/bin" - "${_programfiles}/OpenSSL" - "${_programfiles}/OpenSSL-Win32" - "C:/OpenSSL/" - "C:/OpenSSL-Win32/" - ) - unset(_programfiles) - endif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) - -else () - set(_OPENSSL_ROOT_HINTS - ${OPENSSL_ROOT_DIR} - ENV OPENSSL_ROOT_DIR - ) -endif () - -set(_OPENSSL_ROOT_HINTS_AND_PATHS - HINTS ${_OPENSSL_ROOT_HINTS} - PATHS ${_OPENSSL_ROOT_PATHS} - ) - -# For OpenSSL < 1.1, they are named libeay32 and ssleay32 and even if the dll is 64bit, it's still suffixed as *32.dll -# For OpenSSL >= 1.1, they are named libcrypto and libssl with no suffix -if( CMAKE_SIZEOF_VOID_P EQUAL 8 ) - # target win64 - FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libcrypto-1_1-x64.dll libcrypto.dll libeay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS}) - FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES libssl-1_1-x64.dll libssl.dll ssleay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS}) -else( CMAKE_SIZEOF_VOID_P EQUAL 8 ) - # target win32 - FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libcrypto-1_1.dll libcrypto.dll libeay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS}) - FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES libssl-1_1.dll libssl.dll ssleay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS}) -endif( CMAKE_SIZEOF_VOID_P EQUAL 8 ) +message(STATUS "Looking for OpenSSL @ $ENV{CMAKE_GENERATOR_PLATFORM} in ${_OPENSSL_ROOT_PATHS}") +if("$ENV{CMAKE_GENERATOR_PLATFORM}" STREQUAL "x64") + FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libcrypto-1_1-x64.dll libcrypto.dll PATHS ${_OPENSSL_ROOT_PATHS} NO_DEFAULT_PATH) + FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES libssl-1_1-x64.dll libssl.dll PATHS ${_OPENSSL_ROOT_PATHS} NO_DEFAULT_PATH) +elseif("$ENV{CMAKE_GENERATOR_PLATFORM}" STREQUAL "Win32") + FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libcrypto-1_1.dll libcrypto.dll PATHS ${_OPENSSL_ROOT_PATHS} NO_DEFAULT_PATH) + FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES libssl-1_1.dll libssl.dll PATHS ${_OPENSSL_ROOT_PATHS} NO_DEFAULT_PATH) +endif() IF(WIN32SSLRUNTIME_LIBEAY AND WIN32SSLRUNTIME_SSLEAY) SET(WIN32SSLRUNTIME_LIBRARIES "${WIN32SSLRUNTIME_LIBEAY}" "${WIN32SSLRUNTIME_SSLEAY}") diff --git a/cockatrice/CMakeLists.txt b/cockatrice/CMakeLists.txt index 83edd6ac..b8b6b11a 100644 --- a/cockatrice/CMakeLists.txt +++ b/cockatrice/CMakeLists.txt @@ -138,7 +138,7 @@ IF(UPDATE_TRANSLATIONS) FILE(GLOB_RECURSE translate_cockatrice_SRCS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp ${CMAKE_SOURCE_DIR}/cockatrice/src/*.h) FILE(GLOB_RECURSE translate_common_SRCS ${CMAKE_SOURCE_DIR}/common/*.cpp ${CMAKE_SOURCE_DIR}/common/*.h) SET(translate_SRCS ${translate_cockatrice_SRCS} ${translate_common_SRCS}) - SET(cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/cockatrice_en@source.ts") + SET(cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/cockatrice_en@source.ts") ELSE() FILE(GLOB cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts") ENDIF(UPDATE_TRANSLATIONS) @@ -153,30 +153,11 @@ if(APPLE) set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns) ENDIF(APPLE) -# Qt5 -find_package(Qt5 COMPONENTS Concurrent Multimedia Network PrintSupport Svg WebSockets Widgets REQUIRED) -set(COCKATRICE_QT_MODULES Qt5::Concurrent Qt5::Multimedia Qt5::Network Qt5::PrintSupport Qt5::Svg Qt5::Widgets Qt5::WebSockets) - -# Qt5LinguistTools -find_package(Qt5LinguistTools) -if(Qt5LinguistTools_FOUND) - list(APPEND COCKATRICE_LIBS Qt5::LinguistTools) - - if(NOT Qt5_LRELEASE_EXECUTABLE) - MESSAGE(WARNING "Qt's lrelease not found.") - endif() - - if(UPDATE_TRANSLATIONS) - if(NOT Qt5_LUPDATE_EXECUTABLE) - MESSAGE(WARNING "Qt's lupdate not found.") - endif() - QT5_CREATE_TRANSLATION(cockatrice_QM ${translate_SRCS} ${cockatrice_TS}) - else() - QT5_ADD_TRANSLATION(cockatrice_QM ${cockatrice_TS}) - endif() -endif() - -QT5_ADD_RESOURCES(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES}) +IF(Qt6_FOUND) + Qt6_ADD_RESOURCES(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES}) +ELSEIF(Qt5_FOUND) + Qt5_ADD_RESOURCES(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES}) +ENDIF() # Declare path variables set(ICONDIR share/icons CACHE STRING "icon dir") @@ -188,10 +169,38 @@ INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR}) INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/common) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) -# Build cockatrice binary and link it -ADD_EXECUTABLE(cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_SOURCES} ${cockatrice_QM} ${cockatrice_RESOURCES_RCC} ${cockatrice_MOC_SRCS}) +set(COCKATRICE_MAC_QM_INSTALL_DIR "cockatrice.app/Contents/Resources/translations") +set(COCKATRICE_UNIX_QM_INSTALL_DIR "share/cockatrice/translations") +set(COCKATRICE_WIN32_QM_INSTALL_DIR "translations") -TARGET_LINK_LIBRARIES(cockatrice cockatrice_common ${COCKATRICE_QT_MODULES}) +if(Qt6_FOUND) + qt6_add_executable(cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_SOURCES} ${cockatrice_RESOURCES_RCC} ${cockatrice_MOC_SRCS} MANUAL_FINALIZATION) +elseif(Qt5_FOUND) + # Qt5 Translations need to be linked at executable creation time + if(Qt5LinguistTools_FOUND) + if(UPDATE_TRANSLATIONS) + qt5_create_translation(cockatrice_QM ${translate_SRCS} ${cockatrice_TS}) + else() + qt5_add_translation(cockatrice_QM ${cockatrice_TS}) + endif() + endif() + add_executable(cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_SOURCES} ${cockatrice_QM} ${cockatrice_RESOURCES_RCC} ${cockatrice_MOC_SRCS}) + if(UNIX) + if(APPLE) + install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_MAC_QM_INSTALL_DIR}) + else() + install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_UNIX_QM_INSTALL_DIR}) + endif() + elseif(WIN32) + install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_WIN32_QM_INSTALL_DIR}) + endif() +endif() + +if(Qt5_FOUND) + target_link_libraries(cockatrice cockatrice_common ${COCKATRICE_QT_MODULES}) +else() + target_link_libraries(cockatrice PUBLIC cockatrice_common ${COCKATRICE_QT_MODULES}) +endif() if(UNIX) if(APPLE) @@ -205,27 +214,23 @@ if(UNIX) set_target_properties(cockatrice PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/Info.plist) INSTALL(TARGETS cockatrice BUNDLE DESTINATION ./) - INSTALL(FILES ${cockatrice_QM} DESTINATION ./cockatrice.app/Contents/Resources/translations) else() # Assume linux INSTALL(TARGETS cockatrice RUNTIME DESTINATION bin/) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.png DESTINATION ${ICONDIR}/hicolor/48x48/apps) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.svg DESTINATION ${ICONDIR}/hicolor/scalable/apps) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cockatrice.desktop DESTINATION ${DESKTOPDIR}) - INSTALL(FILES ${cockatrice_QM} DESTINATION share/cockatrice/translations) endif() elseif(WIN32) INSTALL(TARGETS cockatrice RUNTIME DESTINATION ./) - INSTALL(FILES ${cockatrice_QM} DESTINATION ./translations) endif() if(APPLE) # these needs to be relative to CMAKE_INSTALL_PREFIX set(plugin_dest_dir cockatrice.app/Contents/Plugins) set(qtconf_dest_dir cockatrice.app/Contents/Resources) - get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/.." ABSOLUTE) - # qt5 plugins: audio, iconengines, imageformats, platforms, printsupport + # Qt plugins: audio (Qt5), iconengines, imageformats, platforms, printsupport (Qt5), styles, tls (Qt6) install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime FILES_MATCHING PATTERN "*.dSYM" EXCLUDE @@ -236,6 +241,7 @@ if(APPLE) PATTERN "platforms/*.dylib" PATTERN "printsupport/*.dylib" PATTERN "styles/*.dylib" + PATTERN "tls/*.dylib" ) install(CODE " @@ -261,9 +267,32 @@ if(WIN32) install(DIRECTORY "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${CMAKE_BUILD_TYPE}/" DESTINATION ./ FILES_MATCHING PATTERN "*.dll") - # qt5 plugins: audio, iconengines, imageformats, platforms, printsupport - install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime - FILES_MATCHING REGEX "(audio|iconengines|imageformats|platforms|printsupport|styles)/.*[^d]\\.dll") + # Qt plugins: audio (Qt5), iconengines, imageformats, platforms, printsupport (Qt5), styles, tls (Qt6) + install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime FILES_MATCHING + PATTERN "audio/qtaudio_wasapi.dll" + PATTERN "audio/qtaudio_windows.dll" + PATTERN "iconengines/qsvgicon.dll" + PATTERN "imageformats/qgif.dll" + PATTERN "imageformats/qicns.dll" + PATTERN "imageformats/qico.dll" + PATTERN "imageformats/qjpeg.dll" + PATTERN "imageformats/qsvg.dll" + PATTERN "imageformats/qtga.dll" + PATTERN "imageformats/qtiff.dll" + PATTERN "imageformats/qwbmp.dll" + PATTERN "imageformats/qwebp.dll" + PATTERN "platforms/qdirect2d.dll" + PATTERN "platforms/qminimal.dll" + PATTERN "platforms/qoffscreen.dll" + PATTERN "platforms/qwindows.dll" + PATTERN "printsupport/windowsprintersupport.dll" + PATTERN "styles/qcertonlybackend.dll" + PATTERN "styles/qopensslbackend.dll" + PATTERN "styles/qschannelbackend.dll" + PATTERN "styles/qwindowsvistastyle.dll" + PATTERN "tls/qcertonlybackend.dll" + PATTERN "tls/qopensslbackend.dll" + PATTERN "tls/qschannelbackend.dll") install(CODE " file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"[Paths] @@ -284,3 +313,26 @@ Data = Resources\") install(FILES ${WIN32SSLRUNTIME_LIBRARIES} DESTINATION ./) endif() endif() + +if(Qt6LinguistTools_FOUND) + #Qt6 Translations happen after the executable is built up + if(UPDATE_TRANSLATIONS) + qt6_add_translations(cockatrice TS_FILES ${cockatrice_TS} SOURCES ${translate_SRCS} QM_FILES_OUTPUT_VARIABLE cockatrice_QM) + else() + qt6_add_translations(cockatrice TS_FILES ${cockatrice_TS} QM_FILES_OUTPUT_VARIABLE cockatrice_QM) + endif() + + if(UNIX) + if(APPLE) + install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_MAC_QM_INSTALL_DIR}) + else() + install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_UNIX_QM_INSTALL_DIR}) + endif() + elseif(WIN32) + install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_WIN32_QM_INSTALL_DIR}) + endif() +endif() + +if(Qt6_FOUND) + qt6_finalize_target(cockatrice) +endif() diff --git a/cockatrice/translations/cockatrice_en@source.ts b/cockatrice/cockatrice_en@source.ts similarity index 100% rename from cockatrice/translations/cockatrice_en@source.ts rename to cockatrice/cockatrice_en@source.ts diff --git a/cockatrice/src/abstractclient.cpp b/cockatrice/src/abstractclient.cpp index ab0f3d25..8e95e52e 100644 --- a/cockatrice/src/abstractclient.cpp +++ b/cockatrice/src/abstractclient.cpp @@ -48,6 +48,7 @@ AbstractClient::AbstractClient(QObject *parent) qRegisterMetaType>("QList"); qRegisterMetaType("Event_ReplayAdded"); qRegisterMetaType>("missingFeatures"); + qRegisterMetaType("pendingCommand"); FeatureSet features; features.initalizeFeatureList(clientFeatures); diff --git a/cockatrice/src/arrowitem.cpp b/cockatrice/src/arrowitem.cpp index 89d016b0..4db9722a 100644 --- a/cockatrice/src/arrowitem.cpp +++ b/cockatrice/src/arrowitem.cpp @@ -16,7 +16,7 @@ #include #include #include -#include +#include ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color) : QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), color(_color), @@ -71,7 +71,7 @@ void ArrowItem::updatePath(const QPointF &endPoint) const double arrowWidth = 15.0; const double headWidth = 40.0; const double headLength = - headWidth / pow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++ + headWidth / qPow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++ const double phi = 15; if (!startItem) @@ -86,7 +86,7 @@ void ArrowItem::updatePath(const QPointF &endPoint) if (lineLength < 30) path = QPainterPath(); else { - QPointF c(lineLength / 2, tan(phi * M_PI / 180) * lineLength); + QPointF c(lineLength / 2, qTan(phi * M_PI / 180) * lineLength); QPainterPath centerLine; centerLine.moveTo(0, 0); @@ -97,22 +97,22 @@ void ArrowItem::updatePath(const QPointF &endPoint) QLineF testLine(arrowBodyEndPoint, centerLine.pointAtPercent(percentage + 0.001)); qreal alpha = testLine.angle() - 90; QPointF endPoint1 = - arrowBodyEndPoint + arrowWidth / 2 * QPointF(cos(alpha * M_PI / 180), -sin(alpha * M_PI / 180)); + arrowBodyEndPoint + arrowWidth / 2 * QPointF(qCos(alpha * M_PI / 180), -qSin(alpha * M_PI / 180)); QPointF endPoint2 = - arrowBodyEndPoint + arrowWidth / 2 * QPointF(-cos(alpha * M_PI / 180), sin(alpha * M_PI / 180)); + arrowBodyEndPoint + arrowWidth / 2 * QPointF(-qCos(alpha * M_PI / 180), qSin(alpha * M_PI / 180)); QPointF point1 = - endPoint1 + (headWidth - arrowWidth) / 2 * QPointF(cos(alpha * M_PI / 180), -sin(alpha * M_PI / 180)); + endPoint1 + (headWidth - arrowWidth) / 2 * QPointF(qCos(alpha * M_PI / 180), -qSin(alpha * M_PI / 180)); QPointF point2 = - endPoint2 + (headWidth - arrowWidth) / 2 * QPointF(-cos(alpha * M_PI / 180), sin(alpha * M_PI / 180)); + endPoint2 + (headWidth - arrowWidth) / 2 * QPointF(-qCos(alpha * M_PI / 180), qSin(alpha * M_PI / 180)); - path = QPainterPath(-arrowWidth / 2 * QPointF(cos((phi - 90) * M_PI / 180), sin((phi - 90) * M_PI / 180))); + path = QPainterPath(-arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180))); path.quadTo(c, endPoint1); path.lineTo(point1); path.lineTo(QPointF(lineLength, 0)); path.lineTo(point2); path.lineTo(endPoint2); - path.quadTo(c, arrowWidth / 2 * QPointF(cos((phi - 90) * M_PI / 180), sin((phi - 90) * M_PI / 180))); - path.lineTo(-arrowWidth / 2 * QPointF(cos((phi - 90) * M_PI / 180), sin((phi - 90) * M_PI / 180))); + path.quadTo(c, arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180))); + path.lineTo(-arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180))); } setPos(startPoint); diff --git a/cockatrice/src/carddbparser/cockatricexml3.cpp b/cockatrice/src/carddbparser/cockatricexml3.cpp index 5567426c..d13148e1 100644 --- a/cockatrice/src/carddbparser/cockatricexml3.cpp +++ b/cockatrice/src/carddbparser/cockatricexml3.cpp @@ -23,7 +23,7 @@ bool CockatriceXml3Parser::getCanParseFile(const QString &fileName, QIODevice &d QXmlStreamReader xml(&device); while (!xml.atEnd()) { if (xml.readNext() == QXmlStreamReader::StartElement) { - if (xml.name() == COCKATRICE_XML3_TAGNAME) { + if (xml.name().toString() == COCKATRICE_XML3_TAGNAME) { int version = xml.attributes().value("version").toString().toInt(); if (version == COCKATRICE_XML3_TAGVER) { return true; @@ -52,12 +52,13 @@ void CockatriceXml3Parser::parseFile(QIODevice &device) break; } - if (xml.name() == "sets") { + auto name = xml.name().toString(); + if (name == "sets") { loadSetsFromXml(xml); - } else if (xml.name() == "cards") { + } else if (name == "cards") { loadCardsFromXml(xml); - } else if (xml.name() != "") { - qDebug() << "[CockatriceXml3Parser] Unknown item" << xml.name() << ", trying to continue anyway"; + } else if (!name.isEmpty()) { + qDebug() << "[CockatriceXml3Parser] Unknown item" << name << ", trying to continue anyway"; xml.skipCurrentElement(); } } @@ -72,26 +73,27 @@ void CockatriceXml3Parser::loadSetsFromXml(QXmlStreamReader &xml) break; } - if (xml.name() == "set") { + auto name = xml.name().toString(); + if (name == "set") { QString shortName, longName, setType; QDate releaseDate; while (!xml.atEnd()) { if (xml.readNext() == QXmlStreamReader::EndElement) { break; } + name = xml.name().toString(); - if (xml.name() == "name") { + if (name == "name") { shortName = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "longname") { + } else if (name == "longname") { longName = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "settype") { + } else if (name == "settype") { setType = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "releasedate") { + } else if (name == "releasedate") { releaseDate = QDate::fromString(xml.readElementText(QXmlStreamReader::IncludeChildElements), Qt::ISODate); - } else if (xml.name() != "") { - qDebug() << "[CockatriceXml3Parser] Unknown set property" << xml.name() - << ", trying to continue anyway"; + } else if (!name.isEmpty()) { + qDebug() << "[CockatriceXml3Parser] Unknown set property" << name << ", trying to continue anyway"; xml.skipCurrentElement(); } } @@ -146,7 +148,8 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml) break; } - if (xml.name() == "card") { + auto xmlName = xml.name().toString(); + if (xmlName == "card") { QString name = QString(""); QString text = QString(""); QVariantHash properties = QVariantHash(); @@ -162,37 +165,39 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml) if (xml.readNext() == QXmlStreamReader::EndElement) { break; } + xmlName = xml.name().toString(); + // variable - assigned properties - if (xml.name() == "name") { + if (xmlName == "name") { name = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "text") { + } else if (xmlName == "text") { text = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "color") { + } else if (xmlName == "color") { colors.append(xml.readElementText(QXmlStreamReader::IncludeChildElements)); - } else if (xml.name() == "token") { + } else if (xmlName == "token") { isToken = static_cast(xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt()); // generic properties - } else if (xml.name() == "manacost") { + } else if (xmlName == "manacost") { properties.insert("manacost", xml.readElementText(QXmlStreamReader::IncludeChildElements)); - } else if (xml.name() == "cmc") { + } else if (xmlName == "cmc") { properties.insert("cmc", xml.readElementText(QXmlStreamReader::IncludeChildElements)); - } else if (xml.name() == "type") { + } else if (xmlName == "type") { QString type = xml.readElementText(QXmlStreamReader::IncludeChildElements); properties.insert("type", type); properties.insert("maintype", getMainCardType(type)); - } else if (xml.name() == "pt") { + } else if (xmlName == "pt") { properties.insert("pt", xml.readElementText(QXmlStreamReader::IncludeChildElements)); - } else if (xml.name() == "loyalty") { + } else if (xmlName == "loyalty") { properties.insert("loyalty", xml.readElementText(QXmlStreamReader::IncludeChildElements)); // positioning info - } else if (xml.name() == "tablerow") { + } else if (xmlName == "tablerow") { tableRow = xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt(); - } else if (xml.name() == "cipt") { + } else if (xmlName == "cipt") { cipt = (xml.readElementText(QXmlStreamReader::IncludeChildElements) == "1"); - } else if (xml.name() == "upsidedown") { + } else if (xmlName == "upsidedown") { upsideDown = (xml.readElementText(QXmlStreamReader::IncludeChildElements) == "1"); // sets - } else if (xml.name() == "set") { + } else if (xmlName == "set") { // NOTE: attributes must be read before readElementText() QXmlStreamAttributes attrs = xml.attributes(); QString setName = xml.readElementText(QXmlStreamReader::IncludeChildElements); @@ -217,8 +222,8 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml) setInfo.setProperty("rarity", attrs.value("rarity").toString()); } sets.insert(setName, setInfo); - // relatd cards - } else if (xml.name() == "related" || xml.name() == "reverse-related") { + // related cards + } else if (xmlName == "related" || xmlName == "reverse-related") { bool attach = false; bool exclude = false; bool variable = false; @@ -249,13 +254,13 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml) } auto *relation = new CardRelation(cardName, attach, exclude, variable, count); - if (xml.name() == "reverse-related") { + if (xmlName == "reverse-related") { reverseRelatedCards << relation; } else { relatedCards << relation; } - } else if (xml.name() != "") { - qDebug() << "[CockatriceXml3Parser] Unknown card property" << xml.name() + } else if (!xmlName.isEmpty()) { + qDebug() << "[CockatriceXml3Parser] Unknown card property" << xmlName << ", trying to continue anyway"; xml.skipCurrentElement(); } diff --git a/cockatrice/src/carddbparser/cockatricexml4.cpp b/cockatrice/src/carddbparser/cockatricexml4.cpp index e9bb4adb..281e63d0 100644 --- a/cockatrice/src/carddbparser/cockatricexml4.cpp +++ b/cockatrice/src/carddbparser/cockatricexml4.cpp @@ -23,7 +23,7 @@ bool CockatriceXml4Parser::getCanParseFile(const QString &fileName, QIODevice &d QXmlStreamReader xml(&device); while (!xml.atEnd()) { if (xml.readNext() == QXmlStreamReader::StartElement) { - if (xml.name() == COCKATRICE_XML4_TAGNAME) { + if (xml.name().toString() == COCKATRICE_XML4_TAGNAME) { int version = xml.attributes().value("version").toString().toInt(); if (version == COCKATRICE_XML4_TAGVER) { return true; @@ -52,12 +52,13 @@ void CockatriceXml4Parser::parseFile(QIODevice &device) break; } - if (xml.name() == "sets") { + auto xmlName = xml.name().toString(); + if (xmlName == "sets") { loadSetsFromXml(xml); - } else if (xml.name() == "cards") { + } else if (xmlName == "cards") { loadCardsFromXml(xml); - } else if (xml.name() != "") { - qDebug() << "[CockatriceXml4Parser] Unknown item" << xml.name() << ", trying to continue anyway"; + } else if (!xmlName.isEmpty()) { + qDebug() << "[CockatriceXml4Parser] Unknown item" << xmlName << ", trying to continue anyway"; xml.skipCurrentElement(); } } @@ -72,25 +73,27 @@ void CockatriceXml4Parser::loadSetsFromXml(QXmlStreamReader &xml) break; } - if (xml.name() == "set") { + auto xmlName = xml.name().toString(); + if (xmlName == "set") { QString shortName, longName, setType; QDate releaseDate; while (!xml.atEnd()) { if (xml.readNext() == QXmlStreamReader::EndElement) { break; } + xmlName = xml.name().toString(); - if (xml.name() == "name") { + if (xmlName == "name") { shortName = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "longname") { + } else if (xmlName == "longname") { longName = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "settype") { + } else if (xmlName == "settype") { setType = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "releasedate") { + } else if (xmlName == "releasedate") { releaseDate = QDate::fromString(xml.readElementText(QXmlStreamReader::IncludeChildElements), Qt::ISODate); - } else if (xml.name() != "") { - qDebug() << "[CockatriceXml4Parser] Unknown set property" << xml.name() + } else if (!xmlName.isEmpty()) { + qDebug() << "[CockatriceXml4Parser] Unknown set property" << xmlName << ", trying to continue anyway"; xml.skipCurrentElement(); } @@ -109,8 +112,9 @@ QVariantHash CockatriceXml4Parser::loadCardPropertiesFromXml(QXmlStreamReader &x break; } - if (xml.name() != "") { - properties.insert(xml.name().toString(), xml.readElementText(QXmlStreamReader::IncludeChildElements)); + auto xmlName = xml.name().toString(); + if (!xmlName.isEmpty()) { + properties.insert(xmlName, xml.readElementText(QXmlStreamReader::IncludeChildElements)); } } return properties; @@ -123,7 +127,9 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml) break; } - if (xml.name() == "card") { + auto xmlName = xml.name().toString(); + + if (xmlName == "card") { QString name = QString(""); QString text = QString(""); QVariantHash properties = QVariantHash(); @@ -138,25 +144,28 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml) if (xml.readNext() == QXmlStreamReader::EndElement) { break; } + + xmlName = xml.name().toString(); + // variable - assigned properties - if (xml.name() == "name") { + if (xmlName == "name") { name = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "text") { + } else if (xmlName == "text") { text = xml.readElementText(QXmlStreamReader::IncludeChildElements); - } else if (xml.name() == "token") { + } else if (xmlName == "token") { isToken = static_cast(xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt()); // generic properties - } else if (xml.name() == "prop") { + } else if (xmlName == "prop") { properties = loadCardPropertiesFromXml(xml); // positioning info - } else if (xml.name() == "tablerow") { + } else if (xmlName == "tablerow") { tableRow = xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt(); - } else if (xml.name() == "cipt") { + } else if (xmlName == "cipt") { cipt = (xml.readElementText(QXmlStreamReader::IncludeChildElements) == "1"); - } else if (xml.name() == "upsidedown") { + } else if (xmlName == "upsidedown") { upsideDown = (xml.readElementText(QXmlStreamReader::IncludeChildElements) == "1"); // sets - } else if (xml.name() == "set") { + } else if (xmlName == "set") { // NOTE: attributes but be read before readElementText() QXmlStreamAttributes attrs = xml.attributes(); QString setName = xml.readElementText(QXmlStreamReader::IncludeChildElements); @@ -171,8 +180,8 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml) } sets.insert(setName, setInfo); } - // relatd cards - } else if (xml.name() == "related" || xml.name() == "reverse-related") { + // related cards + } else if (xmlName == "related" || xmlName == "reverse-related") { bool attach = false; bool exclude = false; bool variable = false; @@ -203,13 +212,13 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml) } auto *relation = new CardRelation(cardName, attach, exclude, variable, count); - if (xml.name() == "reverse-related") { + if (xmlName == "reverse-related") { reverseRelatedCards << relation; } else { relatedCards << relation; } - } else if (xml.name() != "") { - qDebug() << "[CockatriceXml4Parser] Unknown card property" << xml.name() + } else if (!xmlName.isEmpty()) { + qDebug() << "[CockatriceXml4Parser] Unknown card property" << xmlName << ", trying to continue anyway"; xml.skipCurrentElement(); } diff --git a/cockatrice/src/cardinfowidget.cpp b/cockatrice/src/cardinfowidget.cpp index 4c0d1671..4578c8b6 100644 --- a/cockatrice/src/cardinfowidget.cpp +++ b/cockatrice/src/cardinfowidget.cpp @@ -6,13 +6,9 @@ #include "main.h" #include -#include -#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) #include -#else -#include -#endif #include +#include CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::WindowFlags flags) : QFrame(parent, flags), aspectRatio((qreal)CARD_HEIGHT / (qreal)CARD_WIDTH), info(nullptr) @@ -34,12 +30,7 @@ CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::Win setFrameStyle(QFrame::Panel | QFrame::Raised); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) - int pixmapHeight = qApp->primaryScreen()->geometry().height() / 3; -#else - QDesktopWidget desktopWidget; - int pixmapHeight = desktopWidget.screenGeometry().height() / 3; -#endif + int pixmapHeight = QGuiApplication::primaryScreen()->geometry().height() / 3; int pixmapWidth = static_cast(pixmapHeight / aspectRatio); pic->setFixedWidth(pixmapWidth); pic->setFixedHeight(pixmapHeight); diff --git a/cockatrice/src/carditem.h b/cockatrice/src/carditem.h index c480f6a0..5ef2856f 100644 --- a/cockatrice/src/carditem.h +++ b/cockatrice/src/carditem.h @@ -2,6 +2,7 @@ #define CARDITEM_H #include "abstractcarditem.h" +#include "server_card.h" class CardDatabase; class CardDragItem; diff --git a/cockatrice/src/chatview/chatview.cpp b/cockatrice/src/chatview/chatview.cpp index d323495c..2b205c31 100644 --- a/cockatrice/src/chatview/chatview.cpp +++ b/cockatrice/src/chatview/chatview.cpp @@ -321,7 +321,7 @@ void ChatView::checkTag(QTextCursor &cursor, QString &message) void ChatView::checkMention(QTextCursor &cursor, QString &message, const QString &userName, UserLevelFlags userLevel) { - const QRegExp notALetterOrNumber = QRegExp("[^a-zA-Z0-9]"); + const static auto notALetterOrNumber = QRegularExpression("[^a-zA-Z0-9]"); int firstSpace = message.indexOf(' '); QString fullMentionUpToSpaceOrEnd = (firstSpace == -1) ? message.mid(1) : message.mid(1, firstSpace - 1); @@ -510,7 +510,11 @@ void ChatView::redactMessages(const QString &userName, int amount) } } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +void ChatView::enterEvent(QEnterEvent * /*event*/) +#else void ChatView::enterEvent(QEvent * /*event*/) +#endif { setMouseTracking(true); } @@ -566,7 +570,11 @@ void ChatView::mousePressEvent(QMouseEvent *event) switch (hoveredItemType) { case HoveredCard: { if ((event->button() == Qt::MiddleButton) || (event->button() == Qt::LeftButton)) +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + emit showCardInfoPopup(event->globalPosition().toPoint(), hoveredContent); +#else emit showCardInfoPopup(event->globalPos(), hoveredContent); +#endif break; } case HoveredUser: { @@ -576,7 +584,11 @@ void ChatView::mousePressEvent(QMouseEvent *event) switch (event->button()) { case Qt::RightButton: { UserLevelFlags userLevel(hoveredContent.left(delimiterIndex).toInt()); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + userContextMenu->showContextMenu(event->globalPosition().toPoint(), userName, userLevel, this); +#else userContextMenu->showContextMenu(event->globalPos(), userName, userLevel, this); +#endif break; } case Qt::LeftButton: { diff --git a/cockatrice/src/chatview/chatview.h b/cockatrice/src/chatview/chatview.h index 23659959..3b50f78d 100644 --- a/cockatrice/src/chatview/chatview.h +++ b/cockatrice/src/chatview/chatview.h @@ -103,7 +103,11 @@ public: void redactMessages(const QString &userName, int amount); protected: +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + void enterEvent(QEnterEvent *event); +#else void enterEvent(QEvent *event); +#endif void leaveEvent(QEvent *event); void mouseMoveEvent(QMouseEvent *event); void mousePressEvent(QMouseEvent *event); diff --git a/cockatrice/src/deck_loader.cpp b/cockatrice/src/deck_loader.cpp index 2967e018..44ea3087 100644 --- a/cockatrice/src/deck_loader.cpp +++ b/cockatrice/src/deck_loader.cpp @@ -6,6 +6,7 @@ #include #include +#include #include const QStringList DeckLoader::fileNameFilters = QStringList() @@ -208,7 +209,7 @@ void DeckLoader::saveToStream_DeckHeader(QTextStream &out) } if (!getComments().isEmpty()) { - QStringList commentRows = getComments().split(QRegExp("\n|\r\n|\r")); + QStringList commentRows = getComments().split(QRegularExpression("\n|\r\n|\r")); foreach (QString row, commentRows) { out << "// " << row << "\n"; } diff --git a/cockatrice/src/deckview.cpp b/cockatrice/src/deckview.cpp index 15a677fd..1d9c41f5 100644 --- a/cockatrice/src/deckview.cpp +++ b/cockatrice/src/deckview.cpp @@ -9,8 +9,8 @@ #include #include #include +#include #include -#include DeckViewCardDragItem::DeckViewCardDragItem(DeckViewCard *_item, const QPointF &_hotSpot, @@ -238,11 +238,9 @@ int DeckViewCardContainer::getCardTypeTextWidth() const QFontMetrics fm(f); int maxCardTypeWidth = 0; - QMapIterator i(cardsByType); - while (i.hasNext()) { - int cardTypeWidth = fm.size(Qt::TextSingleLine, i.next().key()).width(); - if (cardTypeWidth > maxCardTypeWidth) - maxCardTypeWidth = cardTypeWidth; + for (const auto &key : cardsByType.keys()) { + int cardTypeWidth = fm.size(Qt::TextSingleLine, key).width(); + maxCardTypeWidth = qMax(maxCardTypeWidth, cardTypeWidth); } return maxCardTypeWidth + 15; @@ -440,7 +438,7 @@ void DeckViewScene::rearrangeItems() const int maxRows = rowsAndColsList[maxIndex1][maxIndex2].first; const int maxCardCount = cardCountList[maxIndex1][maxIndex2]; rowsAndColsList[maxIndex1][maxIndex2] = - QPair(maxRows + 1, (int)ceil((qreal)maxCardCount / (qreal)(maxRows + 1))); + QPair(maxRows + 1, (int)qCeil((qreal)maxCardCount / (qreal)(maxRows + 1))); } totalHeight = -spacing; diff --git a/cockatrice/src/dlg_connect.cpp b/cockatrice/src/dlg_connect.cpp index e63a7a87..508085f1 100644 --- a/cockatrice/src/dlg_connect.cpp +++ b/cockatrice/src/dlg_connect.cpp @@ -162,8 +162,7 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent) previousHostButton->setChecked(true); - connect(previousHosts, SIGNAL(currentIndexChanged(const QString &)), this, - SLOT(updateDisplayInfo(const QString &))); + connect(previousHosts, SIGNAL(currentTextChanged(const QString &)), this, SLOT(updateDisplayInfo(const QString &))); playernameEdit->setFocus(); } diff --git a/cockatrice/src/dlg_manage_sets.cpp b/cockatrice/src/dlg_manage_sets.cpp index 496431c1..81542c75 100644 --- a/cockatrice/src/dlg_manage_sets.cpp +++ b/cockatrice/src/dlg_manage_sets.cpp @@ -121,7 +121,12 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent) connect(disableSomeButton, SIGNAL(clicked()), this, SLOT(actDisableSome())); connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), this, SLOT(actToggleButtons(const QItemSelection &, const QItemSelection &))); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + connect(searchField, SIGNAL(textChanged(const QString &)), displayModel, + SLOT(setFilterRegularExpression(const QString &))); +#else connect(searchField, SIGNAL(textChanged(const QString &)), displayModel, SLOT(setFilterRegExp(const QString &))); +#endif connect(view->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(actDisableSortButtons(int))); connect(searchField, SIGNAL(textChanged(const QString &)), this, SLOT(actDisableResetButton(const QString &))); @@ -139,7 +144,6 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent) tr("How to use custom card art") + "")); QGridLayout *hintsGrid = new QGridLayout; - hintsGrid->setMargin(2); hintsGrid->addWidget(labNotes, 0, 0); hintsGroupBox = new QGroupBox(tr("Hints")); hintsGroupBox->setLayout(hintsGrid); diff --git a/cockatrice/src/dlg_settings.cpp b/cockatrice/src/dlg_settings.cpp index 894e5fba..c2015372 100644 --- a/cockatrice/src/dlg_settings.cpp +++ b/cockatrice/src/dlg_settings.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include @@ -44,18 +43,22 @@ GeneralSettingsPage::GeneralSettingsPage() { - SettingsCache &settings = SettingsCache::instance(); - QString setLanguage = settings.getLang(); - QStringList qmFiles = findQmFiles(); - for (int i = 0; i < qmFiles.size(); i++) { - QString langName = languageName(qmFiles[i]); - languageBox.addItem(langName, qmFiles[i]); - if ((qmFiles[i] == setLanguage) || - (setLanguage.isEmpty() && langName == QCoreApplication::translate("i18n", DEFAULT_LANG_NAME))) - languageBox.setCurrentIndex(i); + QStringList languageCodes = findQmFiles(); + for (const QString &code : languageCodes) { + QString langName = languageName(code); + languageBox.addItem(langName, code); + } + + QString setLanguage = QCoreApplication::translate("i18n", DEFAULT_LANG_NAME); + int index = languageBox.findText(setLanguage, Qt::MatchExactly); + if (index == -1) { + qWarning() << "could not find language" << setLanguage; + } else { + languageBox.setCurrentIndex(index); } // updates + SettingsCache &settings = SettingsCache::instance(); QList channels = settings.getUpdateReleaseChannels(); foreach (ReleaseChannel *chan, channels) { updateReleaseChannelBox.insertItem(chan->getIndex(), tr(chan->getName().toUtf8())); @@ -186,15 +189,20 @@ QStringList GeneralSettingsPage::findQmFiles() { QDir dir(translationPath); QStringList fileNames = dir.entryList(QStringList(translationPrefix + "_*.qm"), QDir::Files, QDir::Name); - fileNames.replaceInStrings(QRegExp(translationPrefix + "_(.*)\\.qm"), "\\1"); - fileNames.removeOne("en@source"); + fileNames.replaceInStrings(QRegularExpression(translationPrefix + "_(.*)\\.qm"), "\\1"); return fileNames; } -QString GeneralSettingsPage::languageName(const QString &qmFile) +QString GeneralSettingsPage::languageName(const QString &lang) { QTranslator qTranslator; - qTranslator.load(translationPrefix + "_" + qmFile + ".qm", translationPath); + + QString appNameHint = translationPrefix + "_" + lang; + bool appTranslationLoaded = qTranslator.load(appNameHint, translationPath); + if (!appTranslationLoaded) { + qDebug() << "Unable to load" << translationPrefix << "translation" << appNameHint << "at" << translationPath; + } + return qTranslator.translate("i18n", DEFAULT_LANG_NAME); } @@ -1235,11 +1243,7 @@ void ShortcutSettingsPage::retranslateUi() DlgSettings::DlgSettings(QWidget *parent) : QDialog(parent) { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)) - auto rec = qApp->primaryScreen()->availableGeometry(); -#else - auto rec = QApplication::desktop()->availableGeometry(); -#endif + auto rec = QGuiApplication::primaryScreen()->availableGeometry(); this->setMinimumSize(qMin(700, rec.width()), qMin(700, rec.height())); connect(&SettingsCache::instance(), SIGNAL(langChanged()), this, SLOT(updateLanguage())); diff --git a/cockatrice/src/dlg_settings.h b/cockatrice/src/dlg_settings.h index 36ea93ab..1bcbc1e3 100644 --- a/cockatrice/src/dlg_settings.h +++ b/cockatrice/src/dlg_settings.h @@ -49,7 +49,7 @@ private slots: private: QStringList findQmFiles(); - QString languageName(const QString &qmFile); + QString languageName(const QString &lang); QLineEdit *deckPathEdit; QLineEdit *replaysPathEdit; QLineEdit *picsPathEdit; diff --git a/cockatrice/src/filter_string.cpp b/cockatrice/src/filter_string.cpp index 63758371..e412ae5a 100644 --- a/cockatrice/src/filter_string.cpp +++ b/cockatrice/src/filter_string.cpp @@ -4,7 +4,6 @@ #include #include -#include #include peg::parser search(R"( diff --git a/cockatrice/src/gamescene.cpp b/cockatrice/src/gamescene.cpp index 815e35c5..b1be6661 100644 --- a/cockatrice/src/gamescene.cpp +++ b/cockatrice/src/gamescene.cpp @@ -13,7 +13,7 @@ #include #include #include -#include +#include GameScene::GameScene(PhasesToolbar *_phasesToolbar, QObject *parent) : QGraphicsScene(parent), phasesToolbar(_phasesToolbar), viewSize(QSize()), playerRotation(0) @@ -97,7 +97,7 @@ void GameScene::rearrange() const int playersCount = playersPlaying.size(); const int columns = playersCount < SettingsCache::instance().getMinPlayersForMultiColumnLayout() ? 1 : 2; - const int rows = ceil((qreal)playersCount / columns); + const int rows = qCeil((qreal)playersCount / columns); qreal sceneHeight = 0, sceneWidth = -playerAreaSpacing; QList columnWidth; diff --git a/cockatrice/src/gamesmodel.cpp b/cockatrice/src/gamesmodel.cpp index 092bf18b..6d8e9daf 100644 --- a/cockatrice/src/gamesmodel.cpp +++ b/cockatrice/src/gamesmodel.cpp @@ -93,11 +93,7 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const case CREATED: { switch (role) { case Qt::DisplayRole: { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) QDateTime then = QDateTime::fromSecsSinceEpoch(gameentry.start_time(), Qt::UTC); -#else - QDateTime then = QDateTime::fromTime_t(gameentry.start_time(), Qt::UTC); -#endif int secs = then.secsTo(QDateTime::currentDateTimeUtc()); return getGameCreatedString(secs); } diff --git a/cockatrice/src/handzone.cpp b/cockatrice/src/handzone.cpp index 91d2e89e..57c8b48b 100644 --- a/cockatrice/src/handzone.cpp +++ b/cockatrice/src/handzone.cpp @@ -24,8 +24,10 @@ void HandZone::updateBg() void HandZone::addCardImpl(CardItem *card, int x, int /*y*/) { - if (x == -1) + // if x is negative set it to add at end + if (x < 0 || x >= cards.size()) { x = cards.size(); + } cards.insert(x, card); if (!cards.getContentsKnown()) { diff --git a/cockatrice/src/localserver.cpp b/cockatrice/src/localserver.cpp index cf3b01d0..0a338a6a 100644 --- a/cockatrice/src/localserver.cpp +++ b/cockatrice/src/localserver.cpp @@ -12,8 +12,9 @@ LocalServer::LocalServer(QObject *parent) : Server(parent) LocalServer::~LocalServer() { // LocalServer is single threaded so it doesn't need locks on this - while (!clients.isEmpty()) - clients.first()->prepareDestroy(); + for (auto *client : clients) { + client->prepareDestroy(); + } prepareDestroy(); } diff --git a/cockatrice/src/localserver.h b/cockatrice/src/localserver.h index a48abdca..d3242548 100644 --- a/cockatrice/src/localserver.h +++ b/cockatrice/src/localserver.h @@ -27,6 +27,7 @@ protected: public: LocalServer_DatabaseInterface(LocalServer *_localServer); + ~LocalServer_DatabaseInterface() = default; AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler, const QString &user, const QString &password, diff --git a/cockatrice/src/main.cpp b/cockatrice/src/main.cpp index 69003a3d..7b22d248 100644 --- a/cockatrice/src/main.cpp +++ b/cockatrice/src/main.cpp @@ -67,11 +67,29 @@ void installNewTranslator() { QString lang = SettingsCache::instance().getLang(); - qtTranslator->load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + QString qtNameHint = "qt_" + lang; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QString qtTranslationPath = QLibraryInfo::path(QLibraryInfo::TranslationsPath); +#else + QString qtTranslationPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); +#endif + + bool qtTranslationLoaded = qtTranslator->load(qtNameHint, qtTranslationPath); + if (!qtTranslationLoaded) { + qDebug() << "Unable to load qt translation" << qtNameHint << "at" << qtTranslationPath; + } else { + qDebug() << "Loaded qt translation" << qtNameHint << "at" << qtTranslationPath; + } qApp->installTranslator(qtTranslator); - translator->load(translationPrefix + "_" + lang, translationPath); + + QString appNameHint = translationPrefix + "_" + lang; + bool appTranslationLoaded = qtTranslator->load(appNameHint, translationPath); + if (!appTranslationLoaded) { + qDebug() << "Unable to load" << translationPrefix << "translation" << appNameHint << "at" << translationPath; + } else { + qDebug() << "Loaded" << translationPrefix << "translation" << appNameHint << "at" << translationPath; + } qApp->installTranslator(translator); - qDebug() << "Language changed:" << lang; } QString const generateClientID() @@ -165,7 +183,9 @@ int main(int argc, char *argv[]) ui.show(); qDebug("main(): ui.show() finished"); +#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0)) app.setAttribute(Qt::AA_UseHighDpiPixmaps); +#endif app.exec(); qDebug("Event loop finished, terminating..."); diff --git a/cockatrice/src/pilezone.cpp b/cockatrice/src/pilezone.cpp index 271c713e..770cdf8d 100644 --- a/cockatrice/src/pilezone.cpp +++ b/cockatrice/src/pilezone.cpp @@ -44,6 +44,10 @@ void PileZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*optio void PileZone::addCardImpl(CardItem *card, int x, int /*y*/) { connect(card, SIGNAL(sigPixmapUpdated()), this, SLOT(callUpdate())); + // if x is negative set it to add at end + if (x < 0 || x >= cards.size()) { + x = cards.size(); + } cards.insert(x, card); card->setPos(0, 0); if (!contentsKnown()) { diff --git a/cockatrice/src/pixmapgenerator.cpp b/cockatrice/src/pixmapgenerator.cpp index 93d7add5..66d9283b 100644 --- a/cockatrice/src/pixmapgenerator.cpp +++ b/cockatrice/src/pixmapgenerator.cpp @@ -99,7 +99,7 @@ QMap CountryPixmapGenerator::pmCache; QPixmap UserLevelPixmapGenerator::generatePixmap(int height, UserLevelFlags userLevel, bool isBuddy, QString privLevel) { - QString key = QString::number(height * 10000) + ":" + (int)userLevel + ":" + (int)isBuddy + ":" + privLevel; + QString key = QString::number(height * 10000) + ":" + (short)userLevel + ":" + (short)isBuddy + ":" + privLevel; if (pmCache.contains(key)) return pmCache.value(key); diff --git a/cockatrice/src/player.cpp b/cockatrice/src/player.cpp index 123b0e54..03c22d81 100644 --- a/cockatrice/src/player.cpp +++ b/cockatrice/src/player.cpp @@ -66,6 +66,7 @@ #include #include +#include #include #include #include @@ -3066,7 +3067,11 @@ void Player::actSetPT() const auto oldpt = parsePT(card->getPT()); int ptIter = 0; for (const auto &item : ptList) { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (item.typeId() == QMetaType::Type::Int) { +#else if (item.type() == QVariant::Int) { +#endif int oldItem = ptIter < oldpt.size() ? oldpt.at(ptIter).toInt() : 0; newpt += '/' + QString::number(oldItem + item.toInt()); } else { diff --git a/cockatrice/src/playerlistwidget.cpp b/cockatrice/src/playerlistwidget.cpp index c4c706d9..4388679f 100644 --- a/cockatrice/src/playerlistwidget.cpp +++ b/cockatrice/src/playerlistwidget.cpp @@ -28,7 +28,11 @@ bool PlayerListItemDelegate::editorEvent(QEvent *event, if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) { QMouseEvent *const mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::RightButton) { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + static_cast(parent())->showContextMenu(mouseEvent->globalPosition().toPoint(), index); +#else static_cast(parent())->showContextMenu(mouseEvent->globalPos(), index); +#endif return true; } } diff --git a/cockatrice/src/releasechannel.cpp b/cockatrice/src/releasechannel.cpp index 0ce28839..97b22e95 100644 --- a/cockatrice/src/releasechannel.cpp +++ b/cockatrice/src/releasechannel.cpp @@ -23,10 +23,9 @@ int ReleaseChannel::sharedIndex = 0; -ReleaseChannel::ReleaseChannel() : response(nullptr), lastRelease(nullptr) +ReleaseChannel::ReleaseChannel() : netMan(new QNetworkAccessManager(this)), response(nullptr), lastRelease(nullptr) { index = sharedIndex++; - netMan = new QNetworkAccessManager(this); } ReleaseChannel::~ReleaseChannel() diff --git a/cockatrice/src/releasechannel.h b/cockatrice/src/releasechannel.h index 8ec4d04c..f9507b85 100644 --- a/cockatrice/src/releasechannel.h +++ b/cockatrice/src/releasechannel.h @@ -78,7 +78,7 @@ class ReleaseChannel : public QObject { Q_OBJECT public: - ReleaseChannel(); + explicit ReleaseChannel(); ~ReleaseChannel() override; protected: @@ -117,7 +117,7 @@ class StableReleaseChannel : public ReleaseChannel { Q_OBJECT public: - StableReleaseChannel() = default; + explicit StableReleaseChannel() = default; ~StableReleaseChannel() override = default; QString getManualDownloadUrl() const override; diff --git a/cockatrice/src/remoteclient.cpp b/cockatrice/src/remoteclient.cpp index 53037bfb..4ade3b08 100644 --- a/cockatrice/src/remoteclient.cpp +++ b/cockatrice/src/remoteclient.cpp @@ -41,8 +41,13 @@ RemoteClient::RemoteClient(QObject *parent) socket->setSocketOption(QAbstractSocket::LowDelayOption, 1); connect(socket, SIGNAL(connected()), this, SLOT(slotConnected())); connect(socket, SIGNAL(readyRead()), this, SLOT(readData())); + +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + connect(socket, &QTcpSocket::errorOccurred, this, &RemoteClient::slotSocketError); +#else connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this, SLOT(slotSocketError(QAbstractSocket::SocketError))); +#endif websocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this); connect(websocket, &QWebSocket::binaryMessageReceived, this, &RemoteClient::websocketMessageReceived); diff --git a/cockatrice/src/remotedecklist_treewidget.cpp b/cockatrice/src/remotedecklist_treewidget.cpp index 2df691a9..d681d0a0 100644 --- a/cockatrice/src/remotedecklist_treewidget.cpp +++ b/cockatrice/src/remotedecklist_treewidget.cpp @@ -221,7 +221,7 @@ void RemoteDeckList_TreeModel::addFileToTree(const ServerInfo_DeckStorage_TreeIt { const ServerInfo_DeckStorage_File &fileInfo = file.file(); QDateTime time; - time.setTime_t(fileInfo.creation_time()); + time.setSecsSinceEpoch(fileInfo.creation_time()); beginInsertRows(nodeToIndex(parent), parent->size(), parent->size()); parent->append(new FileNode(QString::fromStdString(file.name()), file.id(), time, parent)); diff --git a/cockatrice/src/remotereplaylist_treewidget.cpp b/cockatrice/src/remotereplaylist_treewidget.cpp index b81191a0..3ae2546b 100644 --- a/cockatrice/src/remotereplaylist_treewidget.cpp +++ b/cockatrice/src/remotereplaylist_treewidget.cpp @@ -111,7 +111,7 @@ QVariant RemoteReplayList_TreeModel::data(const QModelIndex &index, int role) co return playerList.join(", "); } case 4: - return QDateTime::fromTime_t(matchInfo.time_started()); + return QDateTime::fromSecsSinceEpoch(matchInfo.time_started()); case 5: return matchInfo.length(); default: diff --git a/cockatrice/src/replay_timeline_widget.cpp b/cockatrice/src/replay_timeline_widget.cpp index 55abcaf0..8a0d1d5b 100644 --- a/cockatrice/src/replay_timeline_widget.cpp +++ b/cockatrice/src/replay_timeline_widget.cpp @@ -62,7 +62,11 @@ void ReplayTimelineWidget::paintEvent(QPaintEvent * /* event */) void ReplayTimelineWidget::mousePressEvent(QMouseEvent *event) { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + int newTime = static_cast((qint64)maxTime * (qint64)event->position().x() / width()); +#else int newTime = static_cast((qint64)maxTime * (qint64)event->x() / width()); +#endif newTime -= newTime % 200; // Time should always be a multiple of 200 if (newTime < currentTime) { currentTime = 0; diff --git a/cockatrice/src/setsmodel.cpp b/cockatrice/src/setsmodel.cpp index bd18d7ad..b4a68417 100644 --- a/cockatrice/src/setsmodel.cpp +++ b/cockatrice/src/setsmodel.cpp @@ -1,5 +1,7 @@ #include "setsmodel.h" +#include + SetsModel::SetsModel(CardDatabase *_db, QObject *parent) : QAbstractTableModel(parent), sets(_db->getSetList()) { sets.sortByKey(); @@ -274,9 +276,15 @@ bool SetsDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex &source auto nameIndex = sourceModel()->index(sourceRow, SetsModel::LongNameCol, sourceParent); auto shortNameIndex = sourceModel()->index(sourceRow, SetsModel::ShortNameCol, sourceParent); - return (sourceModel()->data(typeIndex).toString().contains(filterRegExp()) || - sourceModel()->data(nameIndex).toString().contains(filterRegExp()) || - sourceModel()->data(shortNameIndex).toString().contains(filterRegExp())); +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + const auto filter = filterRegularExpression(); +#else + const auto filter = filterRegExp(); +#endif + + return (sourceModel()->data(typeIndex).toString().contains(filter) || + sourceModel()->data(nameIndex).toString().contains(filter) || + sourceModel()->data(shortNameIndex).toString().contains(filter)); } bool SetsDisplayModel::lessThan(const QModelIndex &left, const QModelIndex &right) const diff --git a/cockatrice/src/settingscache.cpp b/cockatrice/src/settingscache.cpp index 1f82ab60..5293c3c3 100644 --- a/cockatrice/src/settingscache.cpp +++ b/cockatrice/src/settingscache.cpp @@ -18,7 +18,7 @@ QString SettingsCache::getDataPath() if (isPortableBuild) return qApp->applicationDirPath() + "/data"; else - return QStandardPaths::writableLocation(QStandardPaths::DataLocation); + return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); } QString SettingsCache::getSettingsPath() diff --git a/cockatrice/src/soundengine.cpp b/cockatrice/src/soundengine.cpp index d581800e..fb821e69 100644 --- a/cockatrice/src/soundengine.cpp +++ b/cockatrice/src/soundengine.cpp @@ -2,21 +2,15 @@ #include "settingscache.h" -#include #include -#include -#include -#include -#include -#include +#include +#include #define DEFAULT_THEME_NAME "Default" #define TEST_SOUND_FILENAME "player_join" SoundEngine::SoundEngine(QObject *parent) : QObject(parent), player(0) { - inputBuffer = new QBuffer(this); - ensureThemeDirectoryExists(); connect(&SettingsCache::instance(), SIGNAL(soundThemeChanged()), this, SLOT(themeChangedSlot())); connect(&SettingsCache::instance(), SIGNAL(soundEnabledChanged()), this, SLOT(soundEnabledChanged())); @@ -31,8 +25,6 @@ SoundEngine::~SoundEngine() player->deleteLater(); player = 0; } - - inputBuffer->deleteLater(); } void SoundEngine::soundEnabledChanged() @@ -40,14 +32,11 @@ void SoundEngine::soundEnabledChanged() if (SettingsCache::instance().getSoundEnabled()) { qDebug("SoundEngine: enabling sound"); if (!player) { - QAudioFormat format; - format.setSampleRate(44100); - format.setChannelCount(1); - format.setSampleSize(16); - format.setCodec("audio/pcm"); - format.setByteOrder(QAudioFormat::LittleEndian); - format.setSampleType(QAudioFormat::SignedInt); - player = new QAudioOutput(format, this); + player = new QMediaPlayer; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + auto qAudioOutput = new QAudioOutput; + player->setAudioOutput(qAudioOutput); +#endif } } else { qDebug("SoundEngine: disabling sound"); @@ -61,25 +50,35 @@ void SoundEngine::soundEnabledChanged() void SoundEngine::playSound(QString fileName) { - if (!player) + if (!player) { return; + } // still playing the previous sound? - if (player->state() == QAudio::ActiveState) +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (player->playbackState() == QMediaPlayer::PlaybackState::PlayingState) { +#else + if (player->state() == QMediaPlayer::PlayingState) { +#endif return; + } - if (!audioData.contains(fileName)) + if (!audioData.contains(fileName)) { return; + } qDebug() << "playing" << fileName; - inputBuffer->close(); - inputBuffer->setData(audioData[fileName]); - inputBuffer->open(QIODevice::ReadOnly); - - player->setVolume(SettingsCache::instance().getMasterVolume() / 100.0); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + player->audioOutput()->setVolume(SettingsCache::instance().getMasterVolume()); player->stop(); - player->start(inputBuffer); + player->setSource(QUrl::fromLocalFile(audioData[fileName])); +#else + player->setVolume(SettingsCache::instance().getMasterVolume()); + player->stop(); + player->setMedia(QUrl::fromLocalFile(audioData[fileName])); +#endif + player->play(); } void SoundEngine::testSound() @@ -105,7 +104,7 @@ QStringMap &SoundEngine::getAvailableThemes() dir.setPath(SettingsCache::instance().getDataPath() + "/sounds"); - foreach (QString themeName, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) { + for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) { if (!availableThemes.contains(themeName)) availableThemes.insert(themeName, dir.absoluteFilePath(themeName)); } @@ -121,7 +120,7 @@ QStringMap &SoundEngine::getAvailableThemes() #endif ); - foreach (QString themeName, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) { + for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) { if (!availableThemes.contains(themeName)) availableThemes.insert(themeName, dir.absoluteFilePath(themeName)); } @@ -181,10 +180,7 @@ void SoundEngine::themeChangedSlot() continue; QFile file(dir.filePath(fileNames[i] + ".wav")); - file.open(QIODevice::ReadOnly); - // 44 = length of wav header - audioData.insert(fileNames[i], file.readAll().mid(44)); - file.close(); + audioData.insert(fileNames[i], file.fileName()); } soundEnabledChanged(); diff --git a/cockatrice/src/soundengine.h b/cockatrice/src/soundengine.h index 726c583f..a386cea8 100644 --- a/cockatrice/src/soundengine.h +++ b/cockatrice/src/soundengine.h @@ -1,8 +1,8 @@ #ifndef SOUNDENGINE_H #define SOUNDENGINE_H -#include #include +#include #include #include @@ -21,10 +21,9 @@ public: QStringMap &getAvailableThemes(); private: - QMap audioData; - QBuffer *inputBuffer; - QAudioOutput *player; QStringMap availableThemes; + QMap audioData; + QMediaPlayer *player; protected: void ensureThemeDirectoryExists(); diff --git a/cockatrice/src/spoilerbackgroundupdater.cpp b/cockatrice/src/spoilerbackgroundupdater.cpp index 7521b9ee..7fb55f16 100644 --- a/cockatrice/src/spoilerbackgroundupdater.cpp +++ b/cockatrice/src/spoilerbackgroundupdater.cpp @@ -114,7 +114,7 @@ void SpoilerBackgroundUpdater::actCheckIfSpoilerSeasonEnabled() emit spoilerCheckerDone(); } else { if (trayIcon) { - trayIcon->showMessage(tr("Spoilers download failed"), tr("Error") + " " + errorCode); + trayIcon->showMessage(tr("Spoilers download failed"), tr("Error") + " " + (short)errorCode); } qDebug() << "Spoiler download failed with reason" << errorCode; @@ -159,7 +159,7 @@ bool SpoilerBackgroundUpdater::saveDownloadedFile(QByteArray data) // Data written, so reload the card database qDebug() << "Spoiler Service Data Written"; - QtConcurrent::run(db, &CardDatabase::loadCardDatabases); + const auto reloadOk = QtConcurrent::run([] { db->loadCardDatabases(); }); // If the user has notifications enabled, let them know // when the database was last updated diff --git a/cockatrice/src/stackzone.cpp b/cockatrice/src/stackzone.cpp index 26f19d55..648ed7bc 100644 --- a/cockatrice/src/stackzone.cpp +++ b/cockatrice/src/stackzone.cpp @@ -26,8 +26,10 @@ void StackZone::updateBg() void StackZone::addCardImpl(CardItem *card, int x, int /*y*/) { - if (x == -1) + // if x is negative set it to add at end + if (x < 0 || x >= cards.size()) { x = cards.size(); + } cards.insert(x, card); if (!cards.getContentsKnown()) { diff --git a/cockatrice/src/tab.cpp b/cockatrice/src/tab.cpp index 3eaaaebc..06cf377c 100644 --- a/cockatrice/src/tab.cpp +++ b/cockatrice/src/tab.cpp @@ -4,7 +4,8 @@ #include #include -#include +#include + Tab::Tab(TabSupervisor *_tabSupervisor, QWidget *parent) : QMainWindow(parent), tabSupervisor(_tabSupervisor), contentsChanged(false), infoPopup(0) { @@ -20,7 +21,8 @@ void Tab::showCardInfoPopup(const QPoint &pos, const QString &cardName) infoPopup = new CardInfoWidget( cardName, 0, Qt::Widget | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint | Qt::WindowStaysOnTopHint); infoPopup->setAttribute(Qt::WA_TransparentForMouseEvents); - QRect screenRect = qApp->desktop()->screenGeometry(this); + + auto screenRect = qApp->primaryScreen()->geometry(); infoPopup->move(qMax(screenRect.left(), qMin(pos.x() - infoPopup->width() / 2, screenRect.left() + screenRect.width() - infoPopup->width())), qMax(screenRect.top(), qMin(pos.y() - infoPopup->height() / 2, diff --git a/cockatrice/src/tab_room.cpp b/cockatrice/src/tab_room.cpp index f7e2bbf9..51bfc3e5 100644 --- a/cockatrice/src/tab_room.cpp +++ b/cockatrice/src/tab_room.cpp @@ -52,7 +52,7 @@ TabRoom::TabRoom(TabSupervisor *_tabSupervisor, SIGNAL(openMessageDialog(const QString &, bool))); chatView = new ChatView(tabSupervisor, tabSupervisor, nullptr, true, this); - connect(chatView, SIGNAL(showMentionPopup(QString &)), this, SLOT(actShowMentionPopup(QString &))); + connect(chatView, SIGNAL(showMentionPopup(const QString &)), this, SLOT(actShowMentionPopup(const QString &))); connect(chatView, SIGNAL(messageClickedSignal()), this, SLOT(focusTab())); connect(chatView, SIGNAL(openMessageDialog(QString, bool)), this, SIGNAL(openMessageDialog(QString, bool))); connect(chatView, SIGNAL(showCardInfoPopup(QPoint, QString)), this, SLOT(showCardInfoPopup(QPoint, QString))); @@ -160,7 +160,7 @@ void TabRoom::focusTab() emit maximizeClient(); } -void TabRoom::actShowMentionPopup(QString &sender) +void TabRoom::actShowMentionPopup(const QString &sender) { this->actShowPopup(sender + tr(" mentioned you.")); } diff --git a/cockatrice/src/tab_room.h b/cockatrice/src/tab_room.h index d048f26e..d9e6d924 100644 --- a/cockatrice/src/tab_room.h +++ b/cockatrice/src/tab_room.h @@ -75,7 +75,7 @@ private slots: void actOpenChatSettings(); void addMentionTag(QString mentionTag); void focusTab(); - void actShowMentionPopup(QString &sender); + void actShowMentionPopup(const QString &sender); void actShowPopup(const QString &message); void actCompleterChanged(); diff --git a/cockatrice/src/tab_supervisor.cpp b/cockatrice/src/tab_supervisor.cpp index f5a199cc..e87a8592 100644 --- a/cockatrice/src/tab_supervisor.cpp +++ b/cockatrice/src/tab_supervisor.cpp @@ -58,7 +58,11 @@ QSize CloseButton::sizeHint() const return QSize(width, height); } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) +void CloseButton::enterEvent(QEnterEvent *event) +#else void CloseButton::enterEvent(QEvent *event) +#endif { update(); QAbstractButton::enterEvent(event); @@ -74,7 +78,7 @@ void CloseButton::paintEvent(QPaintEvent * /*event*/) { QPainter p(this); QStyleOption opt; - opt.init(this); + opt.initFrom(this); opt.state |= QStyle::State_AutoRaise; if (isEnabled() && underMouse() && !isChecked() && !isDown()) opt.state |= QStyle::State_Raised; diff --git a/cockatrice/src/tab_supervisor.h b/cockatrice/src/tab_supervisor.h index b6737557..7045e4f9 100644 --- a/cockatrice/src/tab_supervisor.h +++ b/cockatrice/src/tab_supervisor.h @@ -52,7 +52,11 @@ public: } protected: +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + void enterEvent(QEnterEvent *event); +#else void enterEvent(QEvent *event); +#endif void leaveEvent(QEvent *event); void paintEvent(QPaintEvent *event); }; diff --git a/cockatrice/src/tappedout_interface.cpp b/cockatrice/src/tappedout_interface.cpp index 95f58d39..0397c7f9 100644 --- a/cockatrice/src/tappedout_interface.cpp +++ b/cockatrice/src/tappedout_interface.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include TappedOutInterface::TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent) @@ -53,7 +54,7 @@ void TappedOutInterface::queryFinished(QNetworkReply *reply) int captures = rx2.captureCount(); for (int i = 1; i <= captures; i++) { - errorMessage += QString("\n") + rx2.cap(i).remove(QRegExp("<[^>]*>")).simplified(); + errorMessage += QString("\n") + rx2.cap(i).remove(QRegularExpression("<[^>]*>")).simplified(); } } diff --git a/cockatrice/src/tip_of_the_day.cpp b/cockatrice/src/tip_of_the_day.cpp index 876b6db3..94996e97 100644 --- a/cockatrice/src/tip_of_the_day.cpp +++ b/cockatrice/src/tip_of_the_day.cpp @@ -36,7 +36,9 @@ TipsOfTheDay::TipsOfTheDay(QString xmlPath, QObject *parent) : QAbstractListMode break; } - if (reader.name() == "tip") { + auto readerName = reader.name().toString(); + + if (readerName == "tip") { QString title, content, imagePath; QDate date; reader.readNext(); @@ -45,16 +47,18 @@ TipsOfTheDay::TipsOfTheDay(QString xmlPath, QObject *parent) : QAbstractListMode break; } - if (reader.name() == "title") { + readerName = reader.name().toString(); + + if (readerName == "title") { title = reader.readElementText(); - } else if (reader.name() == "text") { + } else if (readerName == "text") { content = reader.readElementText(); - } else if (reader.name() == "image") { + } else if (readerName == "image") { imagePath = "theme:tips/images/" + reader.readElementText(); - } else if (reader.name() == "date") { + } else if (readerName == "date") { date = QDate::fromString(reader.readElementText(), Qt::ISODate); } else { - // unkown element, do nothing + // unknown element, do nothing } } tipList->append(TipOfTheDay(title, content, imagePath, date)); diff --git a/cockatrice/src/userinfobox.cpp b/cockatrice/src/userinfobox.cpp index d9850e8d..369e08fb 100644 --- a/cockatrice/src/userinfobox.cpp +++ b/cockatrice/src/userinfobox.cpp @@ -137,7 +137,7 @@ QString UserInfoBox::getAgeString(int ageSeconds) if (ageSeconds == 0) return accountAgeString; - auto date = QDateTime::fromTime_t(QDateTime::currentSecsSinceEpoch() - ageSeconds).date(); + auto date = QDateTime::fromSecsSinceEpoch(QDateTime::currentSecsSinceEpoch() - ageSeconds).date(); if (!date.isValid()) return accountAgeString; diff --git a/cockatrice/src/userlist.cpp b/cockatrice/src/userlist.cpp index 80b62174..dc93a1f6 100644 --- a/cockatrice/src/userlist.cpp +++ b/cockatrice/src/userlist.cpp @@ -296,7 +296,11 @@ bool UserListItemDelegate::editorEvent(QEvent *event, if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) { QMouseEvent *const mouseEvent = static_cast(event); if (mouseEvent->button() == Qt::RightButton) { +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + static_cast(parent())->showContextMenu(mouseEvent->globalPosition().toPoint(), index); +#else static_cast(parent())->showContextMenu(mouseEvent->globalPos(), index); +#endif return true; } } diff --git a/cockatrice/src/window_main.cpp b/cockatrice/src/window_main.cpp index 4098f77b..b101aeb3 100644 --- a/cockatrice/src/window_main.cpp +++ b/cockatrice/src/window_main.cpp @@ -101,8 +101,8 @@ void MainWindow::processConnectionClosedEvent(const Event_ConnectionClosed &even case Event_ConnectionClosed::BANNED: { reasonStr = tr("Banned by moderator"); if (event.has_end_time()) - reasonStr.append("\n" + - tr("Expected end time: %1").arg(QDateTime::fromTime_t(event.end_time()).toString())); + reasonStr.append( + "\n" + tr("Expected end time: %1").arg(QDateTime::fromSecsSinceEpoch(event.end_time()).toString())); else reasonStr.append("\n" + tr("This ban lasts indefinitely.")); if (event.has_reason_str()) @@ -393,7 +393,7 @@ void MainWindow::loginError(Response::ResponseCode r, case Response::RespUserIsBanned: { QString bannedStr; if (endTime) - bannedStr = tr("You are banned until %1.").arg(QDateTime::fromTime_t(endTime).toString()); + bannedStr = tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString()); else bannedStr = tr("You are banned indefinitely."); if (!reasonStr.isEmpty()) @@ -530,7 +530,7 @@ void MainWindow::registerError(Response::ResponseCode r, QString reasonStr, quin case Response::RespUserIsBanned: { QString bannedStr; if (endTime) - bannedStr = tr("You are banned until %1.").arg(QDateTime::fromTime_t(endTime).toString()); + bannedStr = tr("You are banned until %1.").arg(QDateTime::fromSecsSinceEpoch(endTime).toString()); else bannedStr = tr("You are banned indefinitely."); if (!reasonStr.isEmpty()) @@ -865,13 +865,13 @@ void MainWindow::startupConfigCheck() if (SettingsCache::instance().getNotifyAboutNewVersion()) { alertForcedOracleRun(VERSION_STRING, true); } else { - QtConcurrent::run(db, &CardDatabase::loadCardDatabases); + const auto reloadOk0 = QtConcurrent::run([] { db->loadCardDatabases(); }); } SettingsCache::instance().setClientVersion(VERSION_STRING); } else { // previous config from this version found qDebug() << "Startup: found config with current version"; - QtConcurrent::run(db, &CardDatabase::loadCardDatabases); + const auto reloadOk1 = QtConcurrent::run([] { db->loadCardDatabases(); }); // Run the tips dialog only on subsequent startups. // On the first run after an install/update the startup is already crowded enough @@ -932,9 +932,9 @@ void MainWindow::createTrayIcon() void MainWindow::iconActivated(QSystemTrayIcon::ActivationReason reason) { if (reason == QSystemTrayIcon::DoubleClick) { - if (windowState() != Qt::WindowMinimized && windowState() != Qt::WindowMinimized + Qt::WindowMaximized) + if ((windowState() & Qt::WindowMinimized) == 0) { showMinimized(); - else { + } else { showNormal(); QApplication::setActiveWindow(this); } @@ -1058,7 +1058,7 @@ void MainWindow::cardDatabaseNewSetsFound(int numUnknownSets, QStringList unknow if (msgBox.clickedButton() == yesButton) { db->enableAllUnknownSets(); - QtConcurrent::run(db, &CardDatabase::loadCardDatabases); + const auto reloadOk1 = QtConcurrent::run([] { db->loadCardDatabases(); }); } else if (msgBox.clickedButton() == noButton) { db->markAllSetsAsKnown(); } else if (msgBox.clickedButton() == settingsButton) { @@ -1086,8 +1086,9 @@ void MainWindow::actCheckCardUpdates() } cardUpdateProcess = new QProcess(this); - connect(cardUpdateProcess, SIGNAL(error(QProcess::ProcessError)), this, - SLOT(cardUpdateError(QProcess::ProcessError))); + + connect(cardUpdateProcess, &QProcess::errorOccurred, this, &MainWindow::cardUpdateError); + connect(cardUpdateProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(cardUpdateFinished(int, QProcess::ExitStatus))); @@ -1148,7 +1149,7 @@ void MainWindow::exitCardDatabaseUpdate() cardUpdateProcess->deleteLater(); cardUpdateProcess = nullptr; - QtConcurrent::run(db, &CardDatabase::loadCardDatabases); + const auto reloadOk1 = QtConcurrent::run([] { db->loadCardDatabases(); }); } void MainWindow::cardUpdateError(QProcess::ProcessError err) @@ -1278,7 +1279,7 @@ void MainWindow::actAddCustomSet() QMessageBox::information( this, tr("Load sets/cards"), tr("The new sets/cards have been added successfully.\nCockatrice will now reload the card database.")); - QtConcurrent::run(db, &CardDatabase::loadCardDatabases); + const auto reloadOk1 = QtConcurrent::run([] { db->loadCardDatabases(); }); } else { QMessageBox::warning(this, tr("Load sets/cards"), tr("Sets/cards failed to import.")); } diff --git a/cockatrice/src/zoneviewzone.cpp b/cockatrice/src/zoneviewzone.cpp index 87d561d7..299ed9ef 100644 --- a/cockatrice/src/zoneviewzone.cpp +++ b/cockatrice/src/zoneviewzone.cpp @@ -14,7 +14,7 @@ #include #include #include -#include +#include ZoneViewZone::ZoneViewZone(Player *_p, CardZone *_origZone, @@ -103,17 +103,17 @@ void ZoneViewZone::reorganizeCards() for (int i = 0; i < cardCount; ++i) cards[i]->setId(i); - int cols = floor(sqrt((double)cardCount / 2)); + int cols = qFloor(qSqrt((double)cardCount / 2)); if (cols > 7) cols = 7; - int rows = ceil((double)cardCount / cols); + int rows = qCeil((double)cardCount / cols); if (rows < 1) rows = 1; if (minRows == 0) minRows = rows; else if (rows < minRows) { rows = minRows; - cols = ceil((double)cardCount / minRows); + cols = qCeil((double)cardCount / minRows); } if (cols < 2) cols = 2; @@ -193,6 +193,10 @@ void ZoneViewZone::setPileView(int _pileView) void ZoneViewZone::addCardImpl(CardItem *card, int x, int /*y*/) { + // if x is negative set it to add at end + if (x < 0 || x >= cards.size()) { + x = cards.size(); + } cards.insert(x, card); card->setParentItem(this); card->update(); diff --git a/common/CMakeLists.txt b/common/CMakeLists.txt index 5d2e6097..e8338c35 100644 --- a/common/CMakeLists.txt +++ b/common/CMakeLists.txt @@ -36,8 +36,8 @@ set(ORACLE_LIBS) INCLUDE_DIRECTORIES(pb) INCLUDE_DIRECTORIES(sfmt) INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR}) -include_directories(${Qt5Core_INCLUDE_DIRS}) +include_directories(${${COCKATRICE_QT_VERSION_NAME}Core_INCLUDE_DIRS}) INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) add_library(cockatrice_common ${common_SOURCES} ${common_MOC_SRCS}) -target_link_libraries(cockatrice_common cockatrice_protocol) +target_link_libraries(cockatrice_common PUBLIC cockatrice_protocol) diff --git a/common/decklist.cpp b/common/decklist.cpp index a1463d0c..09ceb2b7 100644 --- a/common/decklist.cpp +++ b/common/decklist.cpp @@ -292,7 +292,7 @@ bool AbstractDecklistCardNode::readElement(QXmlStreamReader *xml) { while (!xml->atEnd()) { xml->readNext(); - if (xml->isEndElement() && xml->name() == "card") + if (xml->isEndElement() && xml->name().toString() == "card") return false; } return true; @@ -435,7 +435,7 @@ bool DeckList::loadFromXml(QXmlStreamReader *xml) while (!xml->atEnd()) { xml->readNext(); if (xml->isStartElement()) { - if (xml->name() != "cockatrice_deck") + if (xml->name().toString() != "cockatrice_deck") return false; while (!xml->atEnd()) { xml->readNext(); @@ -602,7 +602,7 @@ bool DeckList::loadFromStream_Plain(QTextStream &in) int amount = 1; match = reMultiplier.match(cardName); if (match.hasMatch()) { - amount = match.capturedRef(1).toInt(); + amount = match.captured(1).toInt(); cardName = match.captured(2); } diff --git a/common/expression.cpp b/common/expression.cpp index 370a3864..cc3a393b 100644 --- a/common/expression.cpp +++ b/common/expression.cpp @@ -4,7 +4,7 @@ #include #include -#include +#include #include peg::parser math(R"( @@ -32,19 +32,17 @@ Expression::Expression(double initial) : value(initial) { if (default_functions == nullptr) { default_functions = new QMap>(); - default_functions->insert("sin", [](double a) { return sin(a); }); - default_functions->insert("cos", [](double a) { return cos(a); }); - default_functions->insert("tan", [](double a) { return tan(a); }); - default_functions->insert("sqrt", [](double a) { return sqrt(a); }); - default_functions->insert("log", [](double a) { return log(a); }); - default_functions->insert("log10", [](double a) { return log(a); }); - default_functions->insert("trunc", [](double a) { return trunc(a); }); - default_functions->insert("abs", [](double a) { return fabs(a); }); - - default_functions->insert("floor", [](double a) { return floor(a); }); - default_functions->insert("ceil", [](double a) { return ceil(a); }); - default_functions->insert("round", [](double a) { return round(a); }); - default_functions->insert("trunc", [](double a) { return trunc(a); }); + default_functions->insert("abs", [](double a) { return qFabs(a); }); + default_functions->insert("ceil", [](double a) { return qCeil(a); }); + default_functions->insert("cos", [](double a) { return qCos(a); }); + default_functions->insert("floor", [](double a) { return qFloor(a); }); + default_functions->insert("log", [](double a) { return qLn(a); }); + default_functions->insert("log10", [](double a) { return qLn(a); }); + default_functions->insert("round", [](double a) { return qRound(a); }); + default_functions->insert("sin", [](double a) { return qSin(a); }); + default_functions->insert("sqrt", [](double a) { return qSqrt(a); }); + default_functions->insert("tan", [](double a) { return qTan(a); }); + default_functions->insert("trunc", [](double a) { return std::trunc(a); }); } fns = QMap>(*default_functions); } @@ -80,7 +78,7 @@ double Expression::eval(const peg::Ast &ast) result /= arg; break; case '^': - result = pow(result, arg); + result = qPow(result, arg); break; default: result = 0; diff --git a/common/rng_sfmt.cpp b/common/rng_sfmt.cpp index 88c5be82..30d0ab63 100644 --- a/common/rng_sfmt.cpp +++ b/common/rng_sfmt.cpp @@ -14,7 +14,7 @@ RNG_SFMT::RNG_SFMT(QObject *parent) : RNG_Abstract(parent) { // initialize the random number generator with a 32bit integer seed (timestamp) - sfmt_init_gen_rand(&sfmt, QDateTime::currentDateTime().toTime_t()); + sfmt_init_gen_rand(&sfmt, QDateTime::currentDateTime().toSecsSinceEpoch()); } /** diff --git a/common/server.cpp b/common/server.cpp index 7a2aa3f8..5f0fe11e 100644 --- a/common/server.cpp +++ b/common/server.cpp @@ -118,7 +118,7 @@ AuthenticationResult Server::loginUser(Server_ProtocolHandler *session, Event_ConnectionClosed event; event.set_reason(Event_ConnectionClosed::LOGGEDINELSEWERE); event.set_reason_str("You have been logged out due to logging in at another location."); - event.set_end_time(QDateTime::currentDateTime().toTime_t()); + event.set_end_time(QDateTime::currentDateTime().toSecsSinceEpoch()); SessionEvent *se = users.value(name)->prepareSessionEvent(event); users.value(name)->sendProtocolItem(*se); @@ -230,6 +230,11 @@ void Server::addClient(Server_ProtocolHandler *client) void Server::removeClient(Server_ProtocolHandler *client) { + int clientIndex = clients.indexOf(client); + if (clientIndex == -1) { + qWarning() << "tried to remove non existing client"; + return; + } if (client->getConnectionType() == "tcp") tcpUserCount--; @@ -238,7 +243,7 @@ void Server::removeClient(Server_ProtocolHandler *client) webSocketUserCount--; QWriteLocker locker(&clientsLock); - clients.removeAt(clients.indexOf(client)); + clients.removeAt(clientIndex); ServerInfo_User *data = client->getUserInfo(); if (data) { Event_UserLeft event; diff --git a/common/server.h b/common/server.h index dc722042..16cbf408 100644 --- a/common/server.h +++ b/common/server.h @@ -57,8 +57,8 @@ private slots: public: mutable QReadWriteLock clientsLock, roomsLock; // locking order: roomsLock before clientsLock - Server(QObject *parent = nullptr); - ~Server() = default; + explicit Server(QObject *parent = nullptr); + virtual ~Server() = default; AuthenticationResult loginUser(Server_ProtocolHandler *session, QString &name, const QString &password, diff --git a/common/server_card.h b/common/server_card.h index e43997af..14f09fba 100644 --- a/common/server_card.h +++ b/common/server_card.h @@ -21,13 +21,13 @@ #define SERVER_CARD_H #include "pb/card_attributes.pb.h" +#include "pb/serverinfo_card.pb.h" #include "server_arrowtarget.h" #include #include class Server_CardZone; -class ServerInfo_Card; class Server_Card : public Server_ArrowTarget { @@ -52,7 +52,7 @@ private: public: Server_Card(QString _name, int _id, int _coord_x, int _coord_y, Server_CardZone *_zone = 0); - ~Server_Card(); + ~Server_Card() override; Server_CardZone *getZone() const { diff --git a/common/server_cardzone.cpp b/common/server_cardzone.cpp index 90b11695..f34e24e3 100644 --- a/common/server_cardzone.cpp +++ b/common/server_cardzone.cpp @@ -292,10 +292,10 @@ void Server_CardZone::insertCard(Server_Card *card, int x, int y) insertCardIntoCoordMap(card, x, y); } else { card->setCoords(0, 0); - if (x == -1) { - cards.append(card); - } else { + if (0 <= x && x < cards.length()) { cards.insert(x, card); + } else { + cards.append(card); } } card->setZone(this); diff --git a/common/server_database_interface.h b/common/server_database_interface.h index 4f404f7f..80578cc6 100644 --- a/common/server_database_interface.h +++ b/common/server_database_interface.h @@ -147,7 +147,12 @@ public: LogMessage_TargetType /* targetType */, const int /* targetId */, const QString & /* targetName */){}; - bool checkUserIsBanned(Server_ProtocolHandler *session, QString &banReason, int &banSecondsRemaining); + virtual bool checkUserIsBanned(Server_ProtocolHandler * /* session */, + QString & /* banReason */, + int & /* banSecondsRemaining */) + { + return false; + }; virtual int checkNumberOfUserAccounts(const QString & /* email */) { return 0; diff --git a/common/server_game.cpp b/common/server_game.cpp index 46c67f8e..631e3503 100644 --- a/common/server_game.cpp +++ b/common/server_game.cpp @@ -69,6 +69,7 @@ Server_Game::Server_Game(const ServerInfo_User &_creatorInfo, spectatorsNeedPassword(_spectatorsNeedPassword), spectatorsCanTalk(_spectatorsCanTalk), spectatorsSeeEverything(_spectatorsSeeEverything), inactivityCounter(0), startTimeOfThisGame(0), secondsElapsed(0), firstGameStarted(false), turnOrderReversed(false), startTime(QDateTime::currentDateTime()), + pingClock(nullptr), #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) gameMutex() #else @@ -97,7 +98,7 @@ Server_Game::~Server_Game() gameClosed = true; sendGameEventContainer(prepareGameEvent(Event_GameClosed(), -1)); - for (Server_Player *player : players.values()) { + for (auto *player : players.values()) { player->prepareDestroy(); } players.clear(); @@ -112,10 +113,22 @@ Server_Game::~Server_Game() replayList.append(currentReplay); storeGameInformation(); - for (int i = 0; i < replayList.size(); ++i) - delete replayList[i]; + for (auto *replay : replayList) { + delete replay; + } + replayList.clear(); + + room = nullptr; + currentReplay = nullptr; + creatorInfo = nullptr; + + if (pingClock) { + delete pingClock; + pingClock = nullptr; + } qDebug() << "Server_Game destructor: gameId=" << gameId; + deleteLater(); } void Server_Game::storeGameInformation() @@ -126,7 +139,7 @@ void Server_Game::storeGameInformation() ServerInfo_ReplayMatch *replayMatchInfo = replayEvent.mutable_match_info(); replayMatchInfo->set_game_id(gameInfo.game_id()); replayMatchInfo->set_room_name(room->getName().toStdString()); - replayMatchInfo->set_time_started(QDateTime::currentDateTime().addSecs(-secondsElapsed).toTime_t()); + replayMatchInfo->set_time_started(QDateTime::currentDateTime().addSecs(-secondsElapsed).toSecsSinceEpoch()); replayMatchInfo->set_length(secondsElapsed); replayMatchInfo->set_game_name(gameInfo.description()); @@ -769,6 +782,6 @@ void Server_Game::getInfo(ServerInfo_Game &result) const result.set_spectators_can_chat(spectatorsCanTalk); result.set_spectators_omniscient(spectatorsSeeEverything); result.set_spectators_count(getSpectatorCount()); - result.set_start_time(startTime.toTime_t()); + result.set_start_time(startTime.toSecsSinceEpoch()); } } diff --git a/common/server_player.cpp b/common/server_player.cpp index d2cd8f05..ee78a7fb 100644 --- a/common/server_player.cpp +++ b/common/server_player.cpp @@ -120,6 +120,7 @@ Server_Player::~Server_Player() = default; void Server_Player::prepareDestroy() { delete deck; + deck = nullptr; playerMutex.lock(); if (userInterface) { @@ -1234,7 +1235,6 @@ Server_Player::cmdAttachCard(const Command_AttachCard &cmd, ResponseContainer & return Response::RespContextError; } - // Get all arrows pointing to or originating from the card being attached and delete them. QMapIterator playerIterator(game->getPlayers()); while (playerIterator.hasNext()) { Server_Player *p = playerIterator.next().value(); diff --git a/common/server_protocolhandler.cpp b/common/server_protocolhandler.cpp index 6db54547..b5273b9a 100644 --- a/common/server_protocolhandler.cpp +++ b/common/server_protocolhandler.cpp @@ -25,8 +25,8 @@ #include #include +#include #include -#include Server_ProtocolHandler::Server_ProtocolHandler(Server *_server, Server_DatabaseInterface *_databaseInterface, @@ -44,6 +44,7 @@ Server_ProtocolHandler::~Server_ProtocolHandler() } // This function must only be called from the thread this object lives in. +// Except when the server is shutting down. // The thread must not hold any server locks when calling this (e.g. clientsLock, roomsLock). void Server_ProtocolHandler::prepareDestroy() { @@ -412,7 +413,7 @@ void Server_ProtocolHandler::pingClockTimeout() } } - if (((timeRunning - lastActionReceived) >= ceil(server->getIdleClientTimeout() * .9)) && + if (((timeRunning - lastActionReceived) >= qCeil(server->getIdleClientTimeout() * .9)) && (!idleClientWarningSent) && (server->getIdleClientTimeout() > 0)) { Event_NotifyUser event; event.set_type(Event_NotifyUser::IDLEWARNING); @@ -489,7 +490,7 @@ Response::ResponseCode Server_ProtocolHandler::cmdLogin(const Command_Login &cmd Response_Login *re = new Response_Login; re->set_denied_reason_str(reasonStr.toStdString()); if (banSecondsLeft != 0) - re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toTime_t()); + re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsLeft).toSecsSinceEpoch()); rc.setResponseExtension(re); return Response::RespUserIsBanned; } diff --git a/common/server_protocolhandler.h b/common/server_protocolhandler.h index 760ca273..b80e08c7 100644 --- a/common/server_protocolhandler.h +++ b/common/server_protocolhandler.h @@ -63,7 +63,6 @@ protected: private: QList messageSizeOverTime, messageCountOverTime, commandCountOverTime; int timeRunning, lastDataReceived, lastActionReceived; - QTimer *pingClock; virtual void transmitProtocolItem(const ServerMessage &item) = 0; diff --git a/common/serverinfo_user_container.cpp b/common/serverinfo_user_container.cpp index 1c261040..597ebd01 100644 --- a/common/serverinfo_user_container.cpp +++ b/common/serverinfo_user_container.cpp @@ -16,7 +16,7 @@ ServerInfo_User_Container::ServerInfo_User_Container(const ServerInfo_User_Conta if (other.userInfo) userInfo = new ServerInfo_User(*other.userInfo); else - userInfo = 0; + userInfo = nullptr; } ServerInfo_User_Container::~ServerInfo_User_Container() diff --git a/common/serverinfo_user_container.h b/common/serverinfo_user_container.h index 16135d65..3a648466 100644 --- a/common/serverinfo_user_container.h +++ b/common/serverinfo_user_container.h @@ -9,7 +9,7 @@ protected: ServerInfo_User *userInfo; public: - ServerInfo_User_Container(ServerInfo_User *_userInfo = 0); + ServerInfo_User_Container(ServerInfo_User *_userInfo = nullptr); ServerInfo_User_Container(const ServerInfo_User &_userInfo); ServerInfo_User_Container(const ServerInfo_User_Container &other); ServerInfo_User_Container &operator=(const ServerInfo_User_Container &other) = default; diff --git a/common/stringsizes.h b/common/stringsizes.h index 56fba626..d8015ccf 100644 --- a/common/stringsizes.h +++ b/common/stringsizes.h @@ -3,7 +3,6 @@ #define STRINGSIZES_H #include -#include // max size for short strings, like names and things that are generally a single phrase constexpr int MAX_NAME_LENGTH = 0xff; diff --git a/dbconverter/CMakeLists.txt b/dbconverter/CMakeLists.txt index 5e631b9a..b3696ae3 100644 --- a/dbconverter/CMakeLists.txt +++ b/dbconverter/CMakeLists.txt @@ -13,24 +13,25 @@ SET(dbconverter_SOURCES ${VERSION_STRING_CPP} ) -# Qt5 -find_package(Qt5 COMPONENTS Network Widgets REQUIRED) -set(dbconverter_QT_MODULES Qt5::Core Qt5::Network Qt5::Widgets) + SET(QT_DONT_USE_QTGUI TRUE) -QT5_WRAP_CPP(dbconverter_SOURCES - ../cockatrice/src/settingscache.h - ../cockatrice/src/settings/carddatabasesettings.h -) +IF(Qt6_FOUND) + Qt6_WRAP_CPP(dbconverter_SOURCES + ../cockatrice/src/settingscache.h + ../cockatrice/src/settings/carddatabasesettings.h + ) +ELSEIF(Qt5_FOUND) + Qt5_WRAP_CPP(dbconverter_SOURCES + ../cockatrice/src/settingscache.h + ../cockatrice/src/settings/carddatabasesettings.h + ) +ENDIF() # Build servatrice binary and link it ADD_EXECUTABLE(dbconverter MACOSX_BUNDLE ${dbconverter_SOURCES} ${dbconverter_MOC_SRCS}) -if(MSVC) - TARGET_LINK_LIBRARIES(dbconverter ${dbconverter_QT_MODULES} Qt5::WinMain) -else() - TARGET_LINK_LIBRARIES(dbconverter ${dbconverter_QT_MODULES}) -endif() +TARGET_LINK_LIBRARIES(dbconverter ${DB_CONVERTER_QT_MODULES}) # install rules if(UNIX) @@ -55,9 +56,8 @@ if(APPLE) # these needs to be relative to CMAKE_INSTALL_PREFIX set(plugin_dest_dir dbconverter.app/Contents/Plugins) set(qtconf_dest_dir dbconverter.app/Contents/Resources) - get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/.." ABSOLUTE) - # qt5 plugins: platforms, sqldrivers/mysql + # Qt plugins: platforms install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime FILES_MATCHING PATTERN "*.dSYM" EXCLUDE @@ -87,10 +87,12 @@ if(WIN32) install(DIRECTORY "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${CMAKE_BUILD_TYPE}/" DESTINATION ./ FILES_MATCHING PATTERN "*.dll") - # qt5 plugins: platforms, sqldrivers/mysql - install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime - FILES_MATCHING REGEX "(platforms/.*)\\.dll" - REGEX ".*d\\.dll" EXCLUDE) + # Qt plugins: platforms + install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime FILES_MATCHING + PATTERN "platforms/qdirect2d.dll" + PATTERN "platforms/qminimal.dll" + PATTERN "platforms/qoffscreen.dll" + PATTERN "platforms/qwindows.dll") install(CODE " file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"[Paths] diff --git a/oracle/CMakeLists.txt b/oracle/CMakeLists.txt index 3c201dec..c77d6ac8 100644 --- a/oracle/CMakeLists.txt +++ b/oracle/CMakeLists.txt @@ -2,12 +2,12 @@ # # provides the oracle binary -PROJECT(Oracle VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") +project(Oracle VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}") # paths set(DESKTOPDIR share/applications CACHE STRING "path to .desktop files") -SET(oracle_SOURCES +set(oracle_SOURCES src/main.cpp src/oraclewizard.cpp src/oracleimporter.cpp @@ -34,13 +34,13 @@ SET(oracle_SOURCES set(oracle_RESOURCES oracle.qrc) -IF(UPDATE_TRANSLATIONS) +if(UPDATE_TRANSLATIONS) FILE(GLOB_RECURSE translate_oracle_SRCS src/*.cpp src/*.h ../cockatrice/src/settingscache.cpp) SET(translate_SRCS ${translate_oracle_SRCS}) - SET(oracle_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/oracle_en@source.ts") -ELSE() + SET(oracle_TS "${CMAKE_CURRENT_SOURCE_DIR}/oracle_en@source.ts") +else() FILE(GLOB oracle_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts") -ENDIF(UPDATE_TRANSLATIONS) +endif(UPDATE_TRANSLATIONS) if(WIN32) set(oracle_SOURCES ${oracle_SOURCES} oracle.rc) @@ -50,38 +50,19 @@ if(APPLE) set(MACOSX_BUNDLE_ICON_FILE appicon.icns) set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources) set(oracle_SOURCES ${oracle_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns) -ENDIF(APPLE) +endif(APPLE) -# Qt5 -find_package(Qt5 COMPONENTS Concurrent Network Svg Widgets REQUIRED) -set(ORACLE_QT_MODULES Qt5::Concurrent Qt5::Network Qt5::Svg Qt5::Widgets) - -# Qt5LinguistTools -find_package(Qt5LinguistTools) -if(Qt5LinguistTools_FOUND) - list(APPEND ORACLE_LIBS Qt5::LinguistTools) - - if(NOT Qt5_LRELEASE_EXECUTABLE) - MESSAGE(WARNING "Qt's lrelease not found.") - endif() - - if(UPDATE_TRANSLATIONS) - if(NOT Qt5_LUPDATE_EXECUTABLE) - MESSAGE(WARNING "Qt's lupdate not found.") - endif() - QT5_CREATE_TRANSLATION(oracle_QM ${translate_SRCS} ${oracle_TS}) - else() - QT5_ADD_TRANSLATION(oracle_QM ${oracle_TS}) - endif() +if(Qt6_FOUND) + Qt6_ADD_RESOURCES(oracle_RESOURCES_RCC ${oracle_RESOURCES}) +elseif(Qt5_FOUND) + Qt5_ADD_RESOURCES(oracle_RESOURCES_RCC ${oracle_RESOURCES}) endif() -QT5_ADD_RESOURCES(oracle_RESOURCES_RCC ${oracle_RESOURCES}) - INCLUDE_DIRECTORIES(../cockatrice/src) # Libz is required to support zipped files FIND_PACKAGE(ZLIB) -IF(ZLIB_FOUND) +if(ZLIB_FOUND) INCLUDE_DIRECTORIES(${ZLIB_INCLUDE_DIRS}) ADD_DEFINITIONS("-DHAS_ZLIB") @@ -89,34 +70,60 @@ IF(ZLIB_FOUND) src/zip/unzip.cpp src/zip/zipglobal.cpp ) -ELSE() +else() MESSAGE(STATUS "Oracle: zlib not found; ZIP support disabled") -ENDIF() +endif() # LibLZMA is required to support xz files FIND_PACKAGE(LibLZMA) -IF(LIBLZMA_FOUND) +if(LIBLZMA_FOUND) INCLUDE_DIRECTORIES(${LIBLZMA_INCLUDE_DIRS}) ADD_DEFINITIONS("-DHAS_LZMA") set(oracle_SOURCES ${oracle_SOURCES} src/lzma/decompress.cpp ) -ELSE() +else() MESSAGE(STATUS "Oracle: LibLZMA not found; xz support disabled") -ENDIF() +endif() -# Build oracle binary and link it -ADD_EXECUTABLE(oracle WIN32 MACOSX_BUNDLE ${oracle_SOURCES} ${oracle_QM} ${oracle_RESOURCES_RCC} ${oracle_MOC_SRCS}) -TARGET_LINK_LIBRARIES(oracle ${ORACLE_QT_MODULES}) +set(ORACLE_MAC_QM_INSTALL_DIR "oracle.app/Contents/Resources/translations") +set(ORACLE_UNIX_QM_INSTALL_DIR "share/oracle/translations") +set(ORACLE_WIN32_QM_INSTALL_DIR "translations") -IF(ZLIB_FOUND) - TARGET_LINK_LIBRARIES(oracle ${ZLIB_LIBRARIES}) -ENDIF() +if(Qt6_FOUND) + # Qt6 Translations are linked after the executable is created in manual mode + qt6_add_executable(oracle WIN32 MACOSX_BUNDLE ${oracle_SOURCES} ${oracle_RESOURCES_RCC} ${oracle_MOC_SRCS} MANUAL_FINALIZATION) +elseif(Qt5_FOUND) + # Qt5 Translations need to be linked at executable creation time + if(Qt5LinguistTools_FOUND) + if(UPDATE_TRANSLATIONS) + qt5_create_translation(oracle_QM ${translate_SRCS} ${oracle_TS}) + else() + qt5_add_translation(oracle_QM ${oracle_TS}) + endif() + endif() + add_executable(oracle WIN32 MACOSX_BUNDLE ${oracle_SOURCES} ${oracle_QM} ${oracle_RESOURCES_RCC} ${oracle_MOC_SRCS}) + if(UNIX) + if(APPLE) + install(FILES ${oracle_QM} DESTINATION ${ORACLE_MAC_QM_INSTALL_DIR}) + else() + install(FILES ${oracle_QM} DESTINATION ${ORACLE_UNIX_QM_INSTALL_DIR}) + endif() + elseif(WIN32) + install(FILES ${oracle_QM} DESTINATION ${ORACLE_WIN32_QM_INSTALL_DIR}) + endif() +endif() -IF(LIBLZMA_FOUND) - TARGET_LINK_LIBRARIES(oracle ${LIBLZMA_LIBRARIES}) -ENDIF() +TARGET_LINK_LIBRARIES(oracle PUBLIC ${ORACLE_QT_MODULES}) + +if(ZLIB_FOUND) + TARGET_LINK_LIBRARIES(oracle PUBLIC ${ZLIB_LIBRARIES}) +endif() + +if(LIBLZMA_FOUND) + TARGET_LINK_LIBRARIES(oracle PUBLIC ${LIBLZMA_LIBRARIES}) +endif() if(UNIX) if(APPLE) @@ -129,17 +136,14 @@ if(UNIX) set_target_properties(oracle PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/Info.plist) INSTALL(TARGETS oracle BUNDLE DESTINATION ./) - INSTALL(FILES ${oracle_QM} DESTINATION ./oracle.app/Contents/Resources/translations) else() # Assume linux INSTALL(TARGETS oracle RUNTIME DESTINATION bin/) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/oracle.png DESTINATION ${ICONDIR}/hicolor/48x48/apps) INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/oracle.svg DESTINATION ${ICONDIR}/hicolor/scalable/apps) - INSTALL(FILES ${oracle_QM} DESTINATION share/oracle/translations) endif() elseif(WIN32) INSTALL(TARGETS oracle RUNTIME DESTINATION ./) - INSTALL(FILES ${oracle_QM} DESTINATION ./translations) endif() IF (NOT WIN32 AND NOT APPLE) @@ -150,9 +154,8 @@ if(APPLE) # these needs to be relative to CMAKE_INSTALL_PREFIX set(plugin_dest_dir oracle.app/Contents/Plugins) set(qtconf_dest_dir oracle.app/Contents/Resources) - get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/.." ABSOLUTE) - # qt5 plugins: iconengines, platforms + # Qt plugins: iconengines, platforms, styles, tls (Qt6) install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime FILES_MATCHING PATTERN "*.dSYM" EXCLUDE @@ -160,6 +163,7 @@ if(APPLE) PATTERN "iconengines/*.dylib" PATTERN "platforms/*.dylib" PATTERN "styles/*.dylib" + PATTERN "tls/*.dylib" ) install(CODE " @@ -177,7 +181,7 @@ Translations = Resources/translations\") " COMPONENT Runtime) endif() -IF(WIN32) +if(WIN32) # these needs to be relative to CMAKE_INSTALL_PREFIX set(plugin_dest_dir Plugins) set(qtconf_dest_dir .) @@ -185,10 +189,20 @@ IF(WIN32) install(DIRECTORY "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${CMAKE_BUILD_TYPE}/" DESTINATION ./ FILES_MATCHING PATTERN "*.dll") - # qt5 plugins: iconengines, platforms - - install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime - FILES_MATCHING REGEX "(iconengines|platforms|styles)/.*[^d]\\.dll") + # Qt plugins: iconengines, platforms, styles, tls (Qt6) + install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime FILES_MATCHING + PATTERN "iconengines/qsvgicon.dll" + PATTERN "platforms/qdirect2d.dll" + PATTERN "platforms/qminimal.dll" + PATTERN "platforms/qoffscreen.dll" + PATTERN "platforms/qwindows.dll" + PATTERN "styles/qcertonlybackend.dll" + PATTERN "styles/qopensslbackend.dll" + PATTERN "styles/qschannelbackend.dll" + PATTERN "styles/qwindowsvistastyle.dll" + PATTERN "tls/qcertonlybackend.dll" + PATTERN "tls/qopensslbackend.dll" + PATTERN "tls/qschannelbackend.dll") install(CODE " file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"[Paths] @@ -204,3 +218,26 @@ Translations = Resources/translations\") fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/Oracle.exe\" \"\${QTPLUGINS}\" \"${libSearchDirs}\") " COMPONENT Runtime) endif() + +if(Qt6LinguistTools_FOUND) + #Qt6 Translations happen after the executable is built up + if(UPDATE_TRANSLATIONS) + qt6_add_translations(oracle TS_FILES ${oracle_TS} SOURCES ${translate_SRCS} QM_FILES_OUTPUT_VARIABLE oracle_QM) + else() + qt6_add_translations(oracle TS_FILES ${oracle_TS} QM_FILES_OUTPUT_VARIABLE oracle_QM) + endif() + + if(UNIX) + if(APPLE) + install(FILES ${oracle_QM} DESTINATION ${ORACLE_MAC_QM_INSTALL_DIR}) + else() + install(FILES ${oracle_QM} DESTINATION ${ORACLE_UNIX_QM_INSTALL_DIR}) + endif() + elseif(WIN32) + install(FILES ${oracle_QM} DESTINATION ${ORACLE_WIN32_QM_INSTALL_DIR}) + endif() +endif() + +if(Qt6_FOUND) + qt6_finalize_target(oracle) +endif() diff --git a/oracle/translations/oracle_en@source.ts b/oracle/oracle_en@source.ts similarity index 100% rename from oracle/translations/oracle_en@source.ts rename to oracle/oracle_en@source.ts diff --git a/oracle/src/main.cpp b/oracle/src/main.cpp index 6cae0b6d..934286a2 100644 --- a/oracle/src/main.cpp +++ b/oracle/src/main.cpp @@ -22,9 +22,28 @@ void installNewTranslator() { QString lang = SettingsCache::instance().getLang(); - qtTranslator->load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath)); + QString qtNameHint = "qt_" + lang; +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QString qtTranslationPath = QLibraryInfo::path(QLibraryInfo::TranslationsPath); +#else + QString qtTranslationPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath); +#endif + + bool qtTranslationLoaded = qtTranslator->load(qtNameHint, qtTranslationPath); + if (!qtTranslationLoaded) { + qDebug() << "Unable to load qt translation" << qtNameHint << "at" << qtTranslationPath; + } else { + qDebug() << "Loaded qt translation" << qtNameHint << "at" << qtTranslationPath; + } qApp->installTranslator(qtTranslator); - translator->load(translationPrefix + "_" + lang, translationPath); + + QString appNameHint = translationPrefix + "_" + lang; + bool appTranslationLoaded = qtTranslator->load(appNameHint, translationPath); + if (!appTranslationLoaded) { + qDebug() << "Unable to load" << translationPrefix << "translation" << appNameHint << "at" << translationPath; + } else { + qDebug() << "Loaded" << translationPrefix << "translation" << appNameHint << "at" << translationPath; + } qApp->installTranslator(translator); } @@ -62,10 +81,8 @@ int main(int argc, char *argv[]) QIcon icon("theme:appicon.svg"); wizard.setWindowIcon(icon); -#if QT_VERSION >= QT_VERSION_CHECK(5, 7, 0) // set name of the app desktop file; used by wayland to load the window icon QGuiApplication::setDesktopFileName("oracle"); -#endif wizard.show(); diff --git a/oracle/src/oracleimporter.cpp b/oracle/src/oracleimporter.cpp index 785f5470..9ee88baa 100644 --- a/oracle/src/oracleimporter.cpp +++ b/oracle/src/oracleimporter.cpp @@ -116,7 +116,7 @@ CardInfoPtr OracleImporter::addCard(QString name, QStringList symbols = manacost.split("}"); QString formattedCardCost; for (QString symbol : symbols) { - if (symbol.contains(QRegExp("[0-9WUBGRP]/[0-9WUBGRP]"))) { + if (symbol.contains(QRegularExpression("[0-9WUBGRP]/[0-9WUBGRP]"))) { symbol.append("}"); } else { symbol.remove(QChar('{')); diff --git a/oracle/src/oraclewizard.cpp b/oracle/src/oraclewizard.cpp index 957546fd..6a480b73 100644 --- a/oracle/src/oraclewizard.cpp +++ b/oracle/src/oraclewizard.cpp @@ -143,16 +143,19 @@ IntroPage::IntroPage(QWidget *parent) : OracleWizardPage(parent) languageLabel = new QLabel(this); versionLabel = new QLabel(this); languageBox = new QComboBox(this); - QString setLanguage = SettingsCache::instance().getLang(); - QStringList qmFiles = findQmFiles(); - for (int i = 0; i < qmFiles.size(); i++) { - QString langName = languageName(qmFiles[i]); - languageBox->addItem(langName, qmFiles[i]); - if ((qmFiles[i] == setLanguage) || - (setLanguage.isEmpty() && langName == QCoreApplication::translate("i18n", DEFAULT_LANG_NAME))) { - languageBox->setCurrentIndex(i); - } + QStringList languageCodes = findQmFiles(); + for (const QString &code : languageCodes) { + QString langName = languageName(code); + languageBox->addItem(langName, code); + } + + QString setLanguage = QCoreApplication::translate("i18n", DEFAULT_LANG_NAME); + int index = languageBox->findText(setLanguage, Qt::MatchExactly); + if (index == -1) { + qWarning() << "could not find language" << setLanguage; + } else { + languageBox->setCurrentIndex(index); } connect(languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int))); @@ -170,15 +173,20 @@ QStringList IntroPage::findQmFiles() { QDir dir(translationPath); QStringList fileNames = dir.entryList(QStringList(translationPrefix + "_*.qm"), QDir::Files, QDir::Name); - fileNames.replaceInStrings(QRegExp(translationPrefix + "_(.*)\\.qm"), "\\1"); - fileNames.removeOne("en@source"); + fileNames.replaceInStrings(QRegularExpression(translationPrefix + "_(.*)\\.qm"), "\\1"); return fileNames; } -QString IntroPage::languageName(const QString &qmFile) +QString IntroPage::languageName(const QString &lang) { QTranslator qTranslator; - qTranslator.load(translationPrefix + "_" + qmFile + ".qm", translationPath); + + QString appNameHint = translationPrefix + "_" + lang; + bool appTranslationLoaded = qTranslator.load(appNameHint, translationPath); + if (!appTranslationLoaded) { + qDebug() << "Unable to load" << translationPrefix << "translation" << appNameHint << "at" << translationPath; + } + return qTranslator.translate("i18n", DEFAULT_LANG_NAME); } @@ -454,8 +462,10 @@ void LoadSetsPage::readSetsFromByteArray(QByteArray data) zipDownloadFailed(tr("Xz extraction failed.")); return; } + const auto &outBufferData = outBuffer->data(); - future = QtConcurrent::run(wizard()->importer, &OracleImporter::readSetsFromByteArray, outBuffer->data()); + future = QtConcurrent::run( + [this, &outBufferData] { return wizard()->importer->readSetsFromByteArray(outBufferData); }); watcher.setFuture(future); return; #else @@ -495,8 +505,10 @@ void LoadSetsPage::readSetsFromByteArray(QByteArray data) uz.closeArchive(); return; } + const auto &outBufferData = outBuffer->data(); - future = QtConcurrent::run(wizard()->importer, &OracleImporter::readSetsFromByteArray, outBuffer->data()); + future = QtConcurrent::run( + [this, &outBufferData] { return wizard()->importer->readSetsFromByteArray(outBufferData); }); watcher.setFuture(future); return; #else @@ -510,7 +522,7 @@ void LoadSetsPage::readSetsFromByteArray(QByteArray data) #endif } // Start the computation. - future = QtConcurrent::run(wizard()->importer, &OracleImporter::readSetsFromByteArray, data); + future = QtConcurrent::run([this, &data] { return wizard()->importer->readSetsFromByteArray(data); }); watcher.setFuture(future); } diff --git a/oracle/src/oraclewizard.h b/oracle/src/oraclewizard.h index 362c19de..f660be32 100644 --- a/oracle/src/oraclewizard.h +++ b/oracle/src/oraclewizard.h @@ -82,7 +82,7 @@ public: private: QStringList findQmFiles(); - QString languageName(const QString &qmFile); + QString languageName(const QString &lang); private: QLabel *label, *languageLabel, *versionLabel; @@ -189,4 +189,4 @@ protected: QString getFileType() override; }; -#endif \ No newline at end of file +#endif diff --git a/oracle/src/qt-json/json.cpp b/oracle/src/qt-json/json.cpp index a5dd69c2..418f9c6b 100644 --- a/oracle/src/qt-json/json.cpp +++ b/oracle/src/qt-json/json.cpp @@ -31,36 +31,35 @@ */ #include "json.h" + +#include #include namespace QtJson { - static QString sanitizeString(QString str) { - str.replace(QLatin1String("\\"), QLatin1String("\\\\")); - str.replace(QLatin1String("\""), QLatin1String("\\\"")); - str.replace(QLatin1String("\b"), QLatin1String("\\b")); - str.replace(QLatin1String("\f"), QLatin1String("\\f")); - str.replace(QLatin1String("\n"), QLatin1String("\\n")); - str.replace(QLatin1String("\r"), QLatin1String("\\r")); - str.replace(QLatin1String("\t"), QLatin1String("\\t")); - return QString(QLatin1String("\"%1\"")).arg(str); + str.replace(QLatin1String("\\"), QLatin1String("\\\\")); + str.replace(QLatin1String("\""), QLatin1String("\\\"")); + str.replace(QLatin1String("\b"), QLatin1String("\\b")); + str.replace(QLatin1String("\f"), QLatin1String("\\f")); + str.replace(QLatin1String("\n"), QLatin1String("\\n")); + str.replace(QLatin1String("\r"), QLatin1String("\\r")); + str.replace(QLatin1String("\t"), QLatin1String("\\t")); + return QString(QLatin1String("\"%1\"")).arg(str); } static QByteArray join(const QList &list, const QByteArray &sep) { - QByteArray res; - Q_FOREACH(const QByteArray &i, list) - { - if(!res.isEmpty()) - { - res += sep; - } - res += i; + QByteArray res; + Q_FOREACH (const QByteArray &i, list) { + if (!res.isEmpty()) { + res += sep; } - return res; + res += i; + } + return res; } /** @@ -68,8 +67,8 @@ static QByteArray join(const QList &list, const QByteArray &sep) */ QVariant Json::parse(const QString &json) { - bool success = true; - return Json::parse(json, success); + bool success = true; + return Json::parse(json, success); } /** @@ -77,149 +76,160 @@ QVariant Json::parse(const QString &json) */ QVariant Json::parse(const QString &json, bool &success) { - success = true; + success = true; - //Return an empty QVariant if the JSON data is either null or empty - if(!json.isNull() || !json.isEmpty()) - { - QString data = json; - //We'll start from index 0 - int index = 0; + // Return an empty QVariant if the JSON data is either null or empty + if (!json.isNull() || !json.isEmpty()) { + QString data = json; + // We'll start from index 0 + int index = 0; - //Parse the first value - QVariant value = Json::parseValue(data, index, success); + // Parse the first value + QVariant value = Json::parseValue(data, index, success); - //Return the parsed value - return value; - } - else - { - //Return the empty QVariant - return QVariant(); - } + // Return the parsed value + return value; + } else { + // Return the empty QVariant + return QVariant(); + } } QByteArray Json::serialize(const QVariant &data) { - bool success = true; - return Json::serialize(data, success); + bool success = true; + return Json::serialize(data, success); } QByteArray Json::serialize(const QVariant &data, bool &success) { - QByteArray str; - success = true; + QByteArray str; + success = true; - if(!data.isValid()) // invalid or null? - { - str = "null"; + if (!data.isValid()) // invalid or null? + { + str = "null"; + } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + else if ((data.typeId() == QMetaType::Type::QVariantList) || + (data.typeId() == QMetaType::Type::QStringList)) // variant is a list? +#else + else if ((data.type() == QVariant::List) || (data.type() == QVariant::StringList)) // variant is a list? +#endif + { + QList values; + const QVariantList list = data.toList(); + Q_FOREACH (const QVariant &v, list) { + QByteArray serializedValue = serialize(v); + if (serializedValue.isNull()) { + success = false; + break; + } + values << serializedValue; } - else if((data.type() == QVariant::List) || (data.type() == QVariant::StringList)) // variant is a list? - { - QList values; - const QVariantList list = data.toList(); - Q_FOREACH(const QVariant& v, list) - { - QByteArray serializedValue = serialize(v); - if(serializedValue.isNull()) - { - success = false; - break; - } - values << serializedValue; - } - str = "[ " + join( values, ", " ) + " ]"; - } - else if(data.type() == QVariant::Hash) // variant is a hash? - { - const QVariantHash vhash = data.toHash(); - QHashIterator it( vhash ); - str = "{ "; - QList pairs; + str = "[ " + join(values, ", ") + " ]"; + } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + else if ((data.typeId() == QMetaType::Type::QVariantHash)) // variant is a list? +#else + else if (data.type() == QVariant::Hash) // variant is a hash? +#endif + { + const QVariantHash vhash = data.toHash(); + QHashIterator it(vhash); + str = "{ "; + QList pairs; - while(it.hasNext()) - { - it.next(); - QByteArray serializedValue = serialize(it.value()); + while (it.hasNext()) { + it.next(); + QByteArray serializedValue = serialize(it.value()); - if(serializedValue.isNull()) - { - success = false; - break; - } - - pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue; + if (serializedValue.isNull()) { + success = false; + break; } - str += join(pairs, ", "); - str += " }"; + pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue; } - else if(data.type() == QVariant::Map) // variant is a map? - { - const QVariantMap vmap = data.toMap(); - QMapIterator it( vmap ); - str = "{ "; - QList pairs; - while(it.hasNext()) - { - it.next(); - QByteArray serializedValue = serialize(it.value()); - if(serializedValue.isNull()) - { - success = false; - break; - } - pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue; - } - str += join(pairs, ", "); - str += " }"; - } - else if((data.type() == QVariant::String) || (data.type() == QVariant::ByteArray)) // a string or a byte array? - { - str = sanitizeString(data.toString()).toUtf8(); - } - else if(data.type() == QVariant::Double) // double? - { - str = QByteArray::number(data.toDouble(), 'g', 20); - if(!str.contains(".") && ! str.contains("e")) - { - str += ".0"; - } - } - else if (data.type() == QVariant::Bool) // boolean value? - { - str = data.toBool() ? "true" : "false"; - } - else if (data.type() == QVariant::ULongLong) // large unsigned number? - { - str = QByteArray::number(data.value()); - } - else if ( data.canConvert() ) // any signed number? - { - str = QByteArray::number(data.value()); - } - else if (data.canConvert()) - { - str = QString::number(data.value()).toUtf8(); - } - else if (data.canConvert()) // can value be converted to string? - { - // this will catch QDate, QDateTime, QUrl, ... - str = sanitizeString(data.toString()).toUtf8(); - } - else - { + + str += join(pairs, ", "); + str += " }"; + } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + else if ((data.typeId() == QMetaType::Type::QVariantMap)) // variant is a list? +#else + else if (data.type() == QVariant::Map) // variant is a map? +#endif + { + const QVariantMap vmap = data.toMap(); + QMapIterator it(vmap); + str = "{ "; + QList pairs; + while (it.hasNext()) { + it.next(); + QByteArray serializedValue = serialize(it.value()); + if (serializedValue.isNull()) { success = false; + break; + } + pairs << sanitizeString(it.key()).toUtf8() + " : " + serializedValue; } - if (success) - { - return str; - } - else - { - return QByteArray(); + str += join(pairs, ", "); + str += " }"; + } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + else if ((data.typeId() == QMetaType::Type::QString) || + (data.typeId() == QMetaType::Type::QByteArray)) // variant is a list? +#else + else if ((data.type() == QVariant::String) || (data.type() == QVariant::ByteArray)) // a string or a byte array? +#endif + { + str = sanitizeString(data.toString()).toUtf8(); + } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + else if (data.typeId() == QMetaType::Type::Double) +#else + else if (data.type() == QVariant::Double) // double? +#endif + { + str = QByteArray::number(data.toDouble(), 'g', 20); + if (!str.contains(".") && !str.contains("e")) { + str += ".0"; } + } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + else if (data.typeId() == QMetaType::Type::Bool) +#else + else if (data.type() == QVariant::Bool) // boolean value? +#endif + { + str = data.toBool() ? "true" : "false"; + } +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + else if (data.typeId() == QMetaType::Type::ULongLong) +#else + else if (data.type() == QVariant::ULongLong) // large unsigned number? +#endif + { + str = QByteArray::number(data.value()); + } else if (data.canConvert()) // any signed number? + { + str = QByteArray::number(data.value()); + } else if (data.canConvert()) { + str = QString::number(data.value()).toUtf8(); + } else if (data.canConvert()) // can value be converted to string? + { + // this will catch QDate, QDateTime, QUrl, ... + str = sanitizeString(data.toString()).toUtf8(); + } else { + success = false; + } + if (success) { + return str; + } else { + return QByteArray(); + } } /** @@ -227,34 +237,33 @@ QByteArray Json::serialize(const QVariant &data, bool &success) */ QVariant Json::parseValue(const QString &json, int &index, bool &success) { - //Determine what kind of data we should parse by - //checking out the upcoming token - switch(Json::lookAhead(json, index)) - { - case JsonTokenString: - return Json::parseString(json, index, success); - case JsonTokenNumber: - return Json::parseNumber(json, index); - case JsonTokenCurlyOpen: - return Json::parseObject(json, index, success); - case JsonTokenSquaredOpen: - return Json::parseArray(json, index, success); - case JsonTokenTrue: - Json::nextToken(json, index); - return QVariant(true); - case JsonTokenFalse: - Json::nextToken(json, index); - return QVariant(false); - case JsonTokenNull: - Json::nextToken(json, index); - return QVariant(); - case JsonTokenNone: - break; - } + // Determine what kind of data we should parse by + // checking out the upcoming token + switch (Json::lookAhead(json, index)) { + case JsonTokenString: + return Json::parseString(json, index, success); + case JsonTokenNumber: + return Json::parseNumber(json, index); + case JsonTokenCurlyOpen: + return Json::parseObject(json, index, success); + case JsonTokenSquaredOpen: + return Json::parseArray(json, index, success); + case JsonTokenTrue: + Json::nextToken(json, index); + return QVariant(true); + case JsonTokenFalse: + Json::nextToken(json, index); + return QVariant(false); + case JsonTokenNull: + Json::nextToken(json, index); + return QVariant(); + case JsonTokenNone: + break; + } - //If there were no tokens, flag the failure and return an empty QVariant - success = false; - return QVariant(); + // If there were no tokens, flag the failure and return an empty QVariant + success = false; + return QVariant(); } /** @@ -262,69 +271,58 @@ QVariant Json::parseValue(const QString &json, int &index, bool &success) */ QVariant Json::parseObject(const QString &json, int &index, bool &success) { - QVariantMap map; - int token; + QVariantMap map; + int token; - //Get rid of the whitespace and increment index - Json::nextToken(json, index); + // Get rid of the whitespace and increment index + Json::nextToken(json, index); - //Loop through all of the key/value pairs of the object - bool done = false; - while(!done) - { - //Get the upcoming token - token = Json::lookAhead(json, index); + // Loop through all of the key/value pairs of the object + bool done = false; + while (!done) { + // Get the upcoming token + token = Json::lookAhead(json, index); - if(token == JsonTokenNone) - { - success = false; - return QVariantMap(); - } - else if(token == JsonTokenComma) - { - Json::nextToken(json, index); - } - else if(token == JsonTokenCurlyClose) - { - Json::nextToken(json, index); - return map; - } - else - { - //Parse the key/value pair's name - QString name = Json::parseString(json, index, success).toString(); + if (token == JsonTokenNone) { + success = false; + return QVariantMap(); + } else if (token == JsonTokenComma) { + Json::nextToken(json, index); + } else if (token == JsonTokenCurlyClose) { + Json::nextToken(json, index); + return map; + } else { + // Parse the key/value pair's name + QString name = Json::parseString(json, index, success).toString(); - if(!success) - { - return QVariantMap(); - } + if (!success) { + return QVariantMap(); + } - //Get the next token - token = Json::nextToken(json, index); + // Get the next token + token = Json::nextToken(json, index); - //If the next token is not a colon, flag the failure - //return an empty QVariant - if(token != JsonTokenColon) - { - success = false; - return QVariant(QVariantMap()); - } + // If the next token is not a colon, flag the failure + // return an empty QVariant + if (token != JsonTokenColon) { + success = false; + return QVariant(QVariantMap()); + } - //Parse the key/value pair's value - QVariant value = Json::parseValue(json, index, success); + // Parse the key/value pair's value + QVariant value = Json::parseValue(json, index, success); - if(!success) - { - return QVariantMap(); - } + if (!success) { + return QVariantMap(); + } - //Assign the value to the key in the map - map[name] = value; - } + // Assign the value to the key in the map + map[name] = value; } + } - //Return the map successfully - return QVariant(map); + // Return the map successfully + return QVariant(map); } /** @@ -332,43 +330,34 @@ QVariant Json::parseObject(const QString &json, int &index, bool &success) */ QVariant Json::parseArray(const QString &json, int &index, bool &success) { - QVariantList list; + QVariantList list; - Json::nextToken(json, index); + Json::nextToken(json, index); - bool done = false; - while(!done) - { - int token = Json::lookAhead(json, index); + bool done = false; + while (!done) { + int token = Json::lookAhead(json, index); - if(token == JsonTokenNone) - { - success = false; - return QVariantList(); - } - else if(token == JsonTokenComma) - { - Json::nextToken(json, index); - } - else if(token == JsonTokenSquaredClose) - { - Json::nextToken(json, index); - break; - } - else - { - QVariant value = Json::parseValue(json, index, success); + if (token == JsonTokenNone) { + success = false; + return QVariantList(); + } else if (token == JsonTokenComma) { + Json::nextToken(json, index); + } else if (token == JsonTokenSquaredClose) { + Json::nextToken(json, index); + break; + } else { + QVariant value = Json::parseValue(json, index, success); - if(!success) - { - return QVariantList(); - } + if (!success) { + return QVariantList(); + } - list.push_back(value); - } + list.push_back(value); } + } - return QVariant(list); + return QVariant(list); } /** @@ -376,102 +365,73 @@ QVariant Json::parseArray(const QString &json, int &index, bool &success) */ QVariant Json::parseString(const QString &json, int &index, bool &success) { - QString s; - QChar c; + QString s; + QChar c; - Json::eatWhitespace(json, index); + Json::eatWhitespace(json, index); + + c = json[index++]; + + bool complete = false; + while (!complete) { + if (index == json.size()) { + break; + } c = json[index++]; - bool complete = false; - while(!complete) - { - if(index == json.size()) - { - break; - } - - c = json[index++]; - - if(c == '\"') - { - complete = true; - break; - } - else if(c == '\\') - { - if(index == json.size()) - { - break; - } - - c = json[index++]; - - if(c == '\"') - { - s.append('\"'); - } - else if(c == '\\') - { - s.append('\\'); - } - else if(c == '/') - { - s.append('/'); - } - else if(c == 'b') - { - s.append('\b'); - } - else if(c == 'f') - { - s.append('\f'); - } - else if(c == 'n') - { - s.append('\n'); - } - else if(c == 'r') - { - s.append('\r'); - } - else if(c == 't') - { - s.append('\t'); - } - else if(c == 'u') - { - int remainingLength = json.size() - index; - - if(remainingLength >= 4) - { - QString unicodeStr = json.mid(index, 4); - - int symbol = unicodeStr.toInt(0, 16); - - s.append(QChar(symbol)); - - index += 4; - } - else - { - break; - } - } - } - else - { - s.append(c); + if (c == '\"') { + complete = true; + break; + } else if (c == '\\') { + if (index == json.size()) { + break; + } + + c = json[index++]; + + if (c == '\"') { + s.append('\"'); + } else if (c == '\\') { + s.append('\\'); + } else if (c == '/') { + s.append('/'); + } else if (c == 'b') { + s.append('\b'); + } else if (c == 'f') { + s.append('\f'); + } else if (c == 'n') { + s.append('\n'); + } else if (c == 'r') { + s.append('\r'); + } else if (c == 't') { + s.append('\t'); + } else if (c == 'u') { + int remainingLength = json.size() - index; + + if (remainingLength >= 4) { + QString unicodeStr = json.mid(index, 4); + + int symbol = unicodeStr.toInt(0, 16); + + s.append(QChar(symbol)); + + index += 4; + } else { + break; } + } + } else { + s.append(c); } + } - if(!complete) - { - success = false; - return QVariant(); - } + if (!complete) { + success = false; + return QVariant(); + } - return QVariant(s); + return QVariant(s); } /** @@ -479,23 +439,23 @@ QVariant Json::parseString(const QString &json, int &index, bool &success) */ QVariant Json::parseNumber(const QString &json, int &index) { - Json::eatWhitespace(json, index); + Json::eatWhitespace(json, index); - int lastIndex = Json::lastIndexOfNumber(json, index); - int charLength = (lastIndex - index) + 1; - QString numberStr; + int lastIndex = Json::lastIndexOfNumber(json, index); + int charLength = (lastIndex - index) + 1; + QString numberStr; - numberStr = json.mid(index, charLength); + numberStr = json.mid(index, charLength); - index = lastIndex + 1; + index = lastIndex + 1; - if (numberStr.contains('.')) { - return QVariant(numberStr.toDouble(NULL)); - } else if (numberStr.startsWith('-')) { - return QVariant(numberStr.toLongLong(NULL)); - } else { - return QVariant(numberStr.toULongLong(NULL)); - } + if (numberStr.contains('.')) { + return QVariant(numberStr.toDouble(NULL)); + } else if (numberStr.startsWith('-')) { + return QVariant(numberStr.toLongLong(NULL)); + } else { + return QVariant(numberStr.toULongLong(NULL)); + } } /** @@ -503,18 +463,16 @@ QVariant Json::parseNumber(const QString &json, int &index) */ int Json::lastIndexOfNumber(const QString &json, int index) { - static const QString numericCharacters("0123456789+-.eE"); - int lastIndex; + static const QString numericCharacters("0123456789+-.eE"); + int lastIndex; - for(lastIndex = index; lastIndex < json.size(); lastIndex++) - { - if(numericCharacters.indexOf(json[lastIndex]) == -1) - { - break; - } + for (lastIndex = index; lastIndex < json.size(); lastIndex++) { + if (numericCharacters.indexOf(json[lastIndex]) == -1) { + break; } + } - return lastIndex -1; + return lastIndex - 1; } /** @@ -522,14 +480,12 @@ int Json::lastIndexOfNumber(const QString &json, int index) */ void Json::eatWhitespace(const QString &json, int &index) { - static const QString whitespaceChars(" \t\n\r"); - for(; index < json.size(); index++) - { - if(whitespaceChars.indexOf(json[index]) == -1) - { - break; - } + static const QString whitespaceChars(" \t\n\r"); + for (; index < json.size(); index++) { + if (whitespaceChars.indexOf(json[index]) == -1) { + break; } + } } /** @@ -537,8 +493,8 @@ void Json::eatWhitespace(const QString &json, int &index) */ int Json::lookAhead(const QString &json, int index) { - int saveIndex = index; - return Json::nextToken(json, saveIndex); + int saveIndex = index; + return Json::nextToken(json, saveIndex); } /** @@ -546,69 +502,73 @@ int Json::lookAhead(const QString &json, int index) */ int Json::nextToken(const QString &json, int &index) { - Json::eatWhitespace(json, index); - - if(index == json.size()) - { - return JsonTokenNone; - } - - QChar c = json[index]; - index++; - switch(c.toLatin1()) - { - case '{': return JsonTokenCurlyOpen; - case '}': return JsonTokenCurlyClose; - case '[': return JsonTokenSquaredOpen; - case ']': return JsonTokenSquaredClose; - case ',': return JsonTokenComma; - case '"': return JsonTokenString; - case '0': case '1': case '2': case '3': case '4': - case '5': case '6': case '7': case '8': case '9': - case '-': return JsonTokenNumber; - case ':': return JsonTokenColon; - } - - index--; - - int remainingLength = json.size() - index; - - //True - if(remainingLength >= 4) - { - if (json[index] == 't' && json[index + 1] == 'r' && - json[index + 2] == 'u' && json[index + 3] == 'e') - { - index += 4; - return JsonTokenTrue; - } - } - - //False - if (remainingLength >= 5) - { - if (json[index] == 'f' && json[index + 1] == 'a' && - json[index + 2] == 'l' && json[index + 3] == 's' && - json[index + 4] == 'e') - { - index += 5; - return JsonTokenFalse; - } - } - - //Null - if (remainingLength >= 4) - { - if (json[index] == 'n' && json[index + 1] == 'u' && - json[index + 2] == 'l' && json[index + 3] == 'l') - { - index += 4; - return JsonTokenNull; - } - } + Json::eatWhitespace(json, index); + if (index == json.size()) { return JsonTokenNone; + } + + QChar c = json[index]; + index++; + switch (c.toLatin1()) { + case '{': + return JsonTokenCurlyOpen; + case '}': + return JsonTokenCurlyClose; + case '[': + return JsonTokenSquaredOpen; + case ']': + return JsonTokenSquaredClose; + case ',': + return JsonTokenComma; + case '"': + return JsonTokenString; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + case '-': + return JsonTokenNumber; + case ':': + return JsonTokenColon; + } + + index--; + + int remainingLength = json.size() - index; + + // True + if (remainingLength >= 4) { + if (json[index] == 't' && json[index + 1] == 'r' && json[index + 2] == 'u' && json[index + 3] == 'e') { + index += 4; + return JsonTokenTrue; + } + } + + // False + if (remainingLength >= 5) { + if (json[index] == 'f' && json[index + 1] == 'a' && json[index + 2] == 'l' && json[index + 3] == 's' && + json[index + 4] == 'e') { + index += 5; + return JsonTokenFalse; + } + } + + // Null + if (remainingLength >= 4) { + if (json[index] == 'n' && json[index + 1] == 'u' && json[index + 2] == 'l' && json[index + 3] == 'l') { + index += 4; + return JsonTokenNull; + } + } + + return JsonTokenNone; } - -} //end namespace +} // namespace QtJson diff --git a/oracle/src/zip/unzip.h b/oracle/src/zip/unzip.h old mode 100755 new mode 100644 index 7171c8b8..ab57fdc3 --- a/oracle/src/zip/unzip.h +++ b/oracle/src/zip/unzip.h @@ -33,14 +33,12 @@ #include #include #include - #include class QDir; class QFile; class QIODevice; class QString; -class QStringList; OSDAB_BEGIN_NAMESPACE(Zip) @@ -49,100 +47,105 @@ class UnzipPrivate; class OSDAB_ZIP_EXPORT UnZip { public: - enum ErrorCode - { - Ok, - ZlibInit, - ZlibError, - OpenFailed, - PartiallyCorrupted, - Corrupted, - WrongPassword, - NoOpenArchive, - FileNotFound, - ReadFailed, - WriteFailed, - SeekFailed, - CreateDirFailed, - InvalidDevice, - InvalidArchive, - HeaderConsistencyError, + enum ErrorCode + { + Ok, + ZlibInit, + ZlibError, + OpenFailed, + PartiallyCorrupted, + Corrupted, + WrongPassword, + NoOpenArchive, + FileNotFound, + ReadFailed, + WriteFailed, + SeekFailed, + CreateDirFailed, + InvalidDevice, + InvalidArchive, + HeaderConsistencyError, - Skip, SkipAll // internal use only - }; + Skip, + SkipAll // internal use only + }; - enum ExtractionOption + enum ExtractionOption { ExtractPaths = 0x0001, SkipPaths = 0x0002, VerifyOnly = 0x0004, NoSilentDirectoryCreation = 0x0008 - }; - Q_DECLARE_FLAGS(ExtractionOptions, ExtractionOption) + }; + Q_DECLARE_FLAGS(ExtractionOptions, ExtractionOption) - enum CompressionMethod - { - NoCompression, Deflated, UnknownCompression - }; + enum CompressionMethod + { + NoCompression, + Deflated, + UnknownCompression + }; - enum FileType - { - File, Directory - }; + enum FileType + { + File, + Directory + }; - struct ZipEntry - { - ZipEntry(); + struct ZipEntry + { + ZipEntry(); - QString filename; - QString comment; + QString filename; + QString comment; - quint32 compressedSize; - quint32 uncompressedSize; - quint32 crc32; + quint32 compressedSize; + quint32 uncompressedSize; + quint32 crc32; - QDateTime lastModified; + QDateTime lastModified; - CompressionMethod compression; - FileType type; + CompressionMethod compression; + FileType type; - bool encrypted; - }; + bool encrypted; + }; - UnZip(); - virtual ~UnZip(); + UnZip(); + virtual ~UnZip(); - bool isOpen() const; + bool isOpen() const; - ErrorCode openArchive(const QString& filename); - ErrorCode openArchive(QIODevice* device); - void closeArchive(); + ErrorCode openArchive(const QString &filename); + ErrorCode openArchive(QIODevice *device); + void closeArchive(); - QString archiveComment() const; + QString archiveComment() const; - QString formatError(UnZip::ErrorCode c) const; + QString formatError(UnZip::ErrorCode c) const; - bool contains(const QString& file) const; + bool contains(const QString &file) const; - QStringList fileList() const; - QList entryList() const; + QStringList fileList() const; + QList entryList() const; ErrorCode verifyArchive(); - ErrorCode extractAll(const QString& dirname, ExtractionOptions options = ExtractPaths); - ErrorCode extractAll(const QDir& dir, ExtractionOptions options = ExtractPaths); + ErrorCode extractAll(const QString &dirname, ExtractionOptions options = ExtractPaths); + ErrorCode extractAll(const QDir &dir, ExtractionOptions options = ExtractPaths); - ErrorCode extractFile(const QString& filename, const QString& dirname, ExtractionOptions options = ExtractPaths); - ErrorCode extractFile(const QString& filename, const QDir& dir, ExtractionOptions options = ExtractPaths); - ErrorCode extractFile(const QString& filename, QIODevice* device, ExtractionOptions options = ExtractPaths); + ErrorCode extractFile(const QString &filename, const QString &dirname, ExtractionOptions options = ExtractPaths); + ErrorCode extractFile(const QString &filename, const QDir &dir, ExtractionOptions options = ExtractPaths); + ErrorCode extractFile(const QString &filename, QIODevice *device, ExtractionOptions options = ExtractPaths); - ErrorCode extractFiles(const QStringList& filenames, const QString& dirname, ExtractionOptions options = ExtractPaths); - ErrorCode extractFiles(const QStringList& filenames, const QDir& dir, ExtractionOptions options = ExtractPaths); + ErrorCode + extractFiles(const QStringList &filenames, const QString &dirname, ExtractionOptions options = ExtractPaths); + ErrorCode extractFiles(const QStringList &filenames, const QDir &dir, ExtractionOptions options = ExtractPaths); - void setPassword(const QString& pwd); + void setPassword(const QString &pwd); private: - UnzipPrivate* d; + UnzipPrivate *d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(UnZip::ExtractionOptions) diff --git a/oracle/src/zip/zipglobal.cpp b/oracle/src/zip/zipglobal.cpp old mode 100755 new mode 100644 index aed1ee0e..4a855ed8 --- a/oracle/src/zip/zipglobal.cpp +++ b/oracle/src/zip/zipglobal.cpp @@ -27,7 +27,7 @@ #include "zipglobal.h" -#if defined(Q_OS_WIN) || defined(Q_OS_WINCE) || defined(Q_OS_LINUX) || defined (Q_OS_MACX) +#if defined(Q_OS_WIN) || defined(Q_OS_WINCE) || defined(Q_OS_LINUX) || defined(Q_OS_MACX) #define OSDAB_ZIP_HAS_UTC #include #else @@ -55,9 +55,9 @@ int OSDAB_ZIP_MANGLE(currentUtcOffset)() #if defined Q_OS_WIN struct tm _tm_struct; - struct tm* tm_struct = &_tm_struct; + struct tm *tm_struct = &_tm_struct; #else - struct tm* tm_struct = 0; + struct tm *tm_struct = 0; #endif #if !defined(QT_NO_THREAD) && defined(_POSIX_THREAD_SAFE_FUNCTIONS) @@ -92,14 +92,14 @@ int OSDAB_ZIP_MANGLE(currentUtcOffset)() const time_t local_time_t = mktime(tm_struct); - const int utcOffset = - qRound(difftime(global_time_t, local_time_t)); + const int utcOffset = -qRound(difftime(global_time_t, local_time_t)); return tm_struct->tm_isdst > 0 ? utcOffset + 3600 : utcOffset; #endif // No UTC return 0; } -QDateTime OSDAB_ZIP_MANGLE(fromFileTimestamp)(const QDateTime& dateTime) +QDateTime OSDAB_ZIP_MANGLE(fromFileTimestamp)(const QDateTime &dateTime) { #if !defined OSDAB_ZIP_NO_UTC && defined OSDAB_ZIP_HAS_UTC const int utc = OSDAB_ZIP_MANGLE(currentUtcOffset)(); @@ -109,14 +109,14 @@ QDateTime OSDAB_ZIP_MANGLE(fromFileTimestamp)(const QDateTime& dateTime) #endif // OSDAB_ZIP_NO_UTC } -bool OSDAB_ZIP_MANGLE(setFileTimestamp)(const QString& fileName, const QDateTime& dateTime) +bool OSDAB_ZIP_MANGLE(setFileTimestamp)(const QString &fileName, const QDateTime &dateTime) { if (fileName.isEmpty()) return true; #ifdef Q_OS_WIN - HANDLE hFile = CreateFileW(fileName.toStdWString().c_str(), - GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); + HANDLE hFile = + CreateFileW(fileName.toStdWString().c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0); if (hFile == INVALID_HANDLE_VALUE) { return false; } @@ -143,7 +143,7 @@ bool OSDAB_ZIP_MANGLE(setFileTimestamp)(const QString& fileName, const QDateTime #elif defined(Q_OS_LINUX) || defined(Q_OS_MACX) struct utimbuf t_buffer; - t_buffer.actime = t_buffer.modtime = dateTime.toTime_t(); + t_buffer.actime = t_buffer.modtime = dateTime.toSecsSinceEpoch(); return utime(fileName.toLocal8Bit().constData(), &t_buffer) == 0; #endif diff --git a/servatrice/CMakeLists.txt b/servatrice/CMakeLists.txt index 56995867..99ce2f8c 100644 --- a/servatrice/CMakeLists.txt +++ b/servatrice/CMakeLists.txt @@ -41,11 +41,12 @@ if(APPLE) set(servatrice_SOURCES ${servatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns) ENDIF(APPLE) -# Qt5 -find_package(Qt5 COMPONENTS Network Sql WebSockets REQUIRED) -set(SERVATRICE_QT_MODULES Qt5::Core Qt5::Network Qt5::Sql Qt5::WebSockets) +IF(Qt6_FOUND) + Qt6_ADD_RESOURCES(servatrice_RESOURCES_RCC ${servatrice_RESOURCES}) +ELSEIF(Qt5_FOUND) + Qt5_ADD_RESOURCES(servatrice_RESOURCES_RCC ${servatrice_RESOURCES}) +ENDIF() -QT5_ADD_RESOURCES(servatrice_RESOURCES_RCC ${servatrice_RESOURCES}) SET(QT_DONT_USE_QTGUI TRUE) # Mysql connector @@ -59,15 +60,15 @@ elseif(WIN32) SET(MYSQLCLIENT_DEFAULT_PATHS "C:\\Program Files\\MySQL\\MySQL Server 5.7\\lib" "C:\\Program Files (x86)\\MySQL\\MySQL Server 5.7\\lib") endif() -find_library(MYSQLCLIENT_LIBRARIES NAMES mysqlclient PATHS ${MYSQLCLIENT_DEFAULT_PATHS} PATH_SUFFIXES mysql mariadb) -if(${MYSQLCLIENT_LIBRARIES} MATCHES "NOTFOUND") +find_library(MYSQL_CLIENT_LIBRARIES NAMES mysqlclient PATHS ${MYSQLCLIENT_DEFAULT_PATHS} PATH_SUFFIXES mysql mariadb) +if(${MYSQL_CLIENT_LIBRARIES} MATCHES "NOTFOUND") set(MYSQLCLIENT_FOUND FALSE CACHE INTERNAL "") - MESSAGE(STATUS "Mysql connector NOT FOUND: servatrice won't be able to connect to a mysql server") - unset(MYSQLCLIENT_LIBRARIES) + MESSAGE(STATUS "MySQL connector NOT FOUND: Servatrice won't be able to connect to a MySQL server") + unset(MYSQL_CLIENT_LIBRARIES) else() set(MYSQLCLIENT_FOUND TRUE CACHE INTERNAL "") - get_filename_component(MYSQLCLIENT_LIBRARY_DIR ${MYSQLCLIENT_LIBRARIES} PATH) - MESSAGE(STATUS "Mysql connector found at: ${MYSQLCLIENT_LIBRARY_DIR}") + get_filename_component(MYSQLCLIENT_LIBRARY_DIR ${MYSQL_CLIENT_LIBRARIES} PATH) + MESSAGE(STATUS "Found MySQL connector at: ${MYSQL_CLIENT_LIBRARIES}") endif() # Declare path variables @@ -83,9 +84,7 @@ INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR}) # Build servatrice binary and link it ADD_EXECUTABLE(servatrice MACOSX_BUNDLE ${servatrice_SOURCES} ${servatrice_RESOURCES_RCC} ${servatrice_MOC_SRCS}) -if(MSVC) - TARGET_LINK_LIBRARIES(servatrice cockatrice_common Threads::Threads ${SERVATRICE_QT_MODULES} Qt5::WinMain) -elseif(CMAKE_HOST_SYSTEM MATCHES "FreeBSD") +if(CMAKE_HOST_SYSTEM MATCHES "FreeBSD") TARGET_LINK_LIBRARIES(servatrice cockatrice_common Threads::Threads ${SERVATRICE_QT_MODULES} ${LIBEXECINFO_LIBRARY}) else() TARGET_LINK_LIBRARIES(servatrice cockatrice_common Threads::Threads ${SERVATRICE_QT_MODULES}) @@ -124,15 +123,15 @@ if(APPLE) # these needs to be relative to CMAKE_INSTALL_PREFIX set(plugin_dest_dir servatrice.app/Contents/Plugins) set(qtconf_dest_dir servatrice.app/Contents/Resources) - get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/.." ABSOLUTE) - # qt5 plugins: platforms, sqldrivers/mysql + # Qt plugins: platforms, sqldrivers/mysql, tls (Qt6) install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime FILES_MATCHING PATTERN "*.dSYM" EXCLUDE PATTERN "*_debug.dylib" EXCLUDE PATTERN "platforms/*.dylib" PATTERN "sqldrivers/libqsqlmysql*.dylib" + PATTERN "tls/*.dylib" ) install(CODE " @@ -157,10 +156,18 @@ if(WIN32) install(DIRECTORY "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${CMAKE_BUILD_TYPE}/" DESTINATION ./ FILES_MATCHING PATTERN "*.dll") - # qt5 plugins: platforms, sqldrivers/mysql - install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime - FILES_MATCHING REGEX "(platforms/.*|sqldrivers/qsqlmysql)\\.dll" - REGEX ".*d\\.dll" EXCLUDE) + # Qt plugins: platforms, sqldrivers, tls (Qt6) + install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime FILES_MATCHING + PATTERN "platforms/qdirect2d.dll" + PATTERN "platforms/qminimal.dll" + PATTERN "platforms/qoffscreen.dll" + PATTERN "platforms/qwindows.dll" + PATTERN "tls/qcertonlybackend.dll" + PATTERN "tls/qopensslbackend.dll" + PATTERN "tls/qschannelbackend.dll" + PATTERN "sqldrivers/qsqlite.dll" + PATTERN "sqldrivers/qsqlodbc.dll" + PATTERN "sqldrivers/qsqlpsql.dll") install(CODE " file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"[Paths] diff --git a/servatrice/src/main.cpp b/servatrice/src/main.cpp index de34755a..63e85fa1 100644 --- a/servatrice/src/main.cpp +++ b/servatrice/src/main.cpp @@ -34,7 +34,6 @@ #include #include #include -#include #include RNG_Abstract *rng; @@ -70,17 +69,17 @@ void testRNG() } for (int i = 0; i <= maxMax - min; ++i) { std::cerr << (min + i); - for (int j = 0; j < numbers.size(); ++j) { - if (i < numbers[j].size()) - std::cerr << "\t" << numbers[j][i]; + for (auto &number : numbers) { + if (i < number.size()) + std::cerr << "\t" << number[i]; else std::cerr << "\t"; } std::cerr << std::endl; } std::cerr << std::endl << "Chi^2 ="; - for (int j = 0; j < chisq.size(); ++j) - std::cerr << "\t" << QString::number(chisq[j], 'f', 3).toStdString(); + for (double j : chisq) + std::cerr << "\t" << QString::number(j, 'f', 3).toStdString(); std::cerr << std::endl << "k ="; for (int j = 0; j < chisq.size(); ++j) std::cerr << "\t" << (j - min + minMax); @@ -112,9 +111,9 @@ void myMessageOutput2(QtMsgType /*type*/, const QMessageLogContext &, const QStr int main(int argc, char *argv[]) { QCoreApplication app(argc, argv); - app.setOrganizationName("Cockatrice"); - app.setApplicationName("Servatrice"); - app.setApplicationVersion(VERSION_STRING); + QCoreApplication::setOrganizationName("Cockatrice"); + QCoreApplication::setApplicationName("Servatrice"); + QCoreApplication::setApplicationVersion(VERSION_STRING); QCommandLineParser parser; parser.addHelpOption(); @@ -183,7 +182,7 @@ int main(int argc, char *argv[]) smtpClient = new SmtpClient(); - Servatrice *server = new Servatrice(); + auto *server = new Servatrice(); QObject::connect(server, SIGNAL(destroyed()), &app, SLOT(quit()), Qt::QueuedConnection); int retval = 0; if (server->initServer()) { @@ -192,7 +191,7 @@ int main(int argc, char *argv[]) qInstallMessageHandler(myMessageOutput); - retval = app.exec(); + retval = QCoreApplication::exec(); std::cerr << "Server quit." << std::endl; std::cerr << "-------------------------" << std::endl; @@ -210,5 +209,6 @@ int main(int argc, char *argv[]) // Delete all global objects allocated by libprotobuf. google::protobuf::ShutdownProtobufLibrary(); + QCoreApplication::quit(); return retval; } diff --git a/servatrice/src/servatrice.cpp b/servatrice/src/servatrice.cpp index 48b43848..4e16ff24 100644 --- a/servatrice/src/servatrice.cpp +++ b/servatrice/src/servatrice.cpp @@ -76,6 +76,7 @@ Servatrice_GameServer::~Servatrice_GameServer() QThread *poolThread = connectionPools[i]->thread(); connectionPools[i]->deleteLater(); // pool destructor calls thread()->quit() poolThread->wait(); + poolThread->deleteLater(); } } @@ -84,6 +85,7 @@ void Servatrice_GameServer::incomingConnection(qintptr socketDescriptor) Servatrice_ConnectionPool *pool = findLeastUsedConnectionPool(); auto ssi = new TcpServerSocketInterface(server, pool->getDatabaseInterface()); + connect(ssi, SIGNAL(incTxBytes), this, SLOT(incTxBytes)); ssi->moveToThread(pool->thread()); pool->addClient(); connect(ssi, SIGNAL(destroyed()), pool, SLOT(removeClient())); @@ -144,6 +146,7 @@ Servatrice_WebsocketGameServer::~Servatrice_WebsocketGameServer() QThread *poolThread = connectionPools[i]->thread(); connectionPools[i]->deleteLater(); // pool destructor calls thread()->quit() poolThread->wait(); + poolThread->deleteLater(); } } @@ -152,6 +155,7 @@ void Servatrice_WebsocketGameServer::onNewConnection() Servatrice_ConnectionPool *pool = findLeastUsedConnectionPool(); auto ssi = new WebsocketServerSocketInterface(server, pool->getDatabaseInterface()); + connect(ssi, SIGNAL(incTxBytes), this, SLOT(incTxBytes)); /* * Due to a Qt limitation, websockets can't be moved to another thread. * This will hopefully change in Qt6 if QtWebSocket will be integrated in QtNetwork @@ -195,7 +199,7 @@ void Servatrice_IslServer::incomingConnection(qintptr socketDescriptor) Servatrice::Servatrice(QObject *parent) : Server(parent), authenticationMethod(AuthenticationNone), uptime(0), txBytes(0), rxBytes(0), - shutdownTimer(nullptr), isFirstShutdownMessage(true) + shutdownTimer(nullptr) { qRegisterMetaType("QSqlDatabase"); } @@ -204,21 +208,16 @@ Servatrice::~Servatrice() { gameServer->close(); - // clients live in other threads, we need to lock them - clientsLock.lockForRead(); + // we are destroying the clients outside their thread! for (auto *client : clients) { - QMetaObject::invokeMethod(client, "prepareDestroy", Qt::QueuedConnection); - } - clientsLock.unlock(); - - // client destruction is asynchronous, wait for all clients to be gone - for (;;) { - QThread::usleep(10); - QReadLocker locker(&clientsLock); - if (clients.isEmpty()) - break; + client->prepareDestroy(); } + if (shutdownTimer) { + shutdownTimer->deleteLater(); + } + + servatriceDatabaseInterface->deleteLater(); prepareDestroy(); } @@ -559,7 +558,7 @@ void Servatrice::updateLoginMessage() } } -void Servatrice::setRequiredFeatures(const QString featureList) +void Servatrice::setRequiredFeatures(const QString &featureList) { FeatureSet features; serverRequiredFeatureList.clear(); @@ -570,8 +569,9 @@ void Servatrice::setRequiredFeatures(const QString featureList) QStringList listReqFeatures = featureList.split(",", QString::SkipEmptyParts); #endif if (!listReqFeatures.isEmpty()) - foreach (QString reqFeature, listReqFeatures) + for (const QString &reqFeature : listReqFeatures) { features.enableRequiredFeature(serverRequiredFeatureList, reqFeature); + } qDebug() << "Set required client features to:" << serverRequiredFeatureList; } @@ -715,8 +715,9 @@ void Servatrice::shutdownTimeout() clientsLock.unlock(); delete se; - if (!shutdownMinutes) + if (!shutdownMinutes) { deleteLater(); + } } shutdownMinutes--; } diff --git a/servatrice/src/servatrice.h b/servatrice/src/servatrice.h index 8456bf7d..d2141056 100644 --- a/servatrice/src/servatrice.h +++ b/servatrice/src/servatrice.h @@ -96,9 +96,9 @@ private: public: Servatrice_IslServer(Servatrice *_server, const QSslCertificate &_cert, - const QSslKey &_privateKey, + QSslKey _privateKey, QObject *parent = nullptr) - : QTcpServer(parent), server(_server), cert(_cert), privateKey(_privateKey) + : QTcpServer(parent), server(_server), cert(_cert), privateKey(std::move(_privateKey)) { } @@ -143,7 +143,7 @@ private slots: void shutdownTimeout(); protected: - void doSendIslMessage(const IslMessage &msg, int serverId) override; + void doSendIslMessage(const IslMessage &msg, int islServerId) override; private: enum DatabaseType @@ -160,7 +160,6 @@ private: mutable QMutex loginMessageMutex; QString loginMessage; QString dbPrefix; - QString requiredFeatures; QMap serverRequiredFeatureList; QString officialWarnings; Servatrice_DatabaseInterface *servatriceDatabaseInterface; @@ -173,7 +172,6 @@ private: int shutdownMinutes; int nextShutdownMessageMinutes; QTimer *shutdownTimer; - bool isFirstShutdownMessage; mutable QMutex serverListMutex; QList serverList; @@ -203,7 +201,7 @@ private: public slots: void scheduleShutdown(const QString &reason, int minutes); void updateLoginMessage(); - void setRequiredFeatures(QString featureList); + void setRequiredFeatures(const QString &featureList); public: explicit Servatrice(QObject *parent = nullptr); @@ -213,10 +211,6 @@ public: { return serverRequiredFeatureList; } - QString getOfficialWarningsList() const - { - return officialWarnings; - } QString getServerName() const; QString getLoginMessage() const override { @@ -282,9 +276,9 @@ public: void incRxBytes(quint64 num); void addDatabaseInterface(QThread *thread, Servatrice_DatabaseInterface *databaseInterface); - bool islConnectionExists(int serverId) const; - void addIslInterface(int serverId, IslInterface *interface); - void removeIslInterface(int serverId); + bool islConnectionExists(int islServerId) const; + void addIslInterface(int islServerId, IslInterface *interface); + void removeIslInterface(int islServerId); QReadWriteLock islLock; QList getServerList() const; diff --git a/servatrice/src/servatrice_connection_pool.h b/servatrice/src/servatrice_connection_pool.h index 2814089e..7479122c 100644 --- a/servatrice/src/servatrice_connection_pool.h +++ b/servatrice/src/servatrice_connection_pool.h @@ -17,8 +17,8 @@ private: int clientCount; public: - Servatrice_ConnectionPool(Servatrice_DatabaseInterface *_databaseInterface); - ~Servatrice_ConnectionPool(); + explicit Servatrice_ConnectionPool(Servatrice_DatabaseInterface *_databaseInterface); + ~Servatrice_ConnectionPool() override; Servatrice_DatabaseInterface *getDatabaseInterface() const { diff --git a/servatrice/src/servatrice_database_interface.cpp b/servatrice/src/servatrice_database_interface.cpp index 4e261da8..1c691e9b 100644 --- a/servatrice/src/servatrice_database_interface.cpp +++ b/servatrice/src/servatrice_database_interface.cpp @@ -113,12 +113,13 @@ bool Servatrice_DatabaseInterface::checkSql() QSqlQuery *Servatrice_DatabaseInterface::prepareQuery(const QString &queryText) { - if (preparedStatements.contains(queryText)) + if (preparedStatements.contains(queryText)) { return preparedStatements.value(queryText); + } QString prefixedQueryText = queryText; prefixedQueryText.replace("{prefix}", server->getDbPrefix()); - QSqlQuery *query = new QSqlQuery(sqlDatabase); + auto *query = new QSqlQuery(sqlDatabase); query->prepare(prefixedQueryText); preparedStatements.insert(queryText, query); diff --git a/servatrice/src/servatrice_database_interface.h b/servatrice/src/servatrice_database_interface.h index c867b807..f4bbf5df 100644 --- a/servatrice/src/servatrice_database_interface.h +++ b/servatrice/src/servatrice_database_interface.h @@ -36,14 +36,14 @@ protected: const QString &clientId, QString &reasonStr, int &banSecondsLeft, - bool passwordNeedsHash); + bool passwordNeedsHash) override; public slots: void initDatabase(const QSqlDatabase &_sqlDatabase); public: - Servatrice_DatabaseInterface(int _instanceId, Servatrice *_server); - ~Servatrice_DatabaseInterface(); + explicit Servatrice_DatabaseInterface(int _instanceId, Servatrice *_server); + ~Servatrice_DatabaseInterface() override; bool initDatabase(const QString &type, const QString &hostName, const QString &databaseName, @@ -58,66 +58,66 @@ public: return sqlDatabase; } - bool activeUserExists(const QString &user); - bool userExists(const QString &user); - QString getUserSalt(const QString &user); + bool activeUserExists(const QString &user) override; + bool userExists(const QString &user) override; + QString getUserSalt(const QString &user) override; int getUserIdInDB(const QString &name); - QMap getBuddyList(const QString &name); - QMap getIgnoreList(const QString &name); - bool isInBuddyList(const QString &whoseList, const QString &who); - bool isInIgnoreList(const QString &whoseList, const QString &who); - ServerInfo_User getUserData(const QString &name, bool withId = false); + QMap getBuddyList(const QString &name) override; + QMap getIgnoreList(const QString &name) override; + bool isInBuddyList(const QString &whoseList, const QString &who) override; + bool isInIgnoreList(const QString &whoseList, const QString &who) override; + ServerInfo_User getUserData(const QString &name, bool withId = false) override; void storeGameInformation(const QString &roomName, const QStringList &roomGameTypes, const ServerInfo_Game &gameInfo, const QSet &allPlayersEver, const QSet &allSpectatorsEver, - const QList &replayList); - DeckList *getDeckFromDatabase(int deckId, int userId); + const QList &replayList) override; + DeckList *getDeckFromDatabase(int deckId, int userId) override; - int getNextGameId(); - int getNextReplayId(); - int getActiveUserCount(QString connectionType = QString()); + int getNextGameId() override; + int getNextReplayId() override; + int getActiveUserCount(QString connectionType = QString()) override; qint64 startSession(const QString &userName, const QString &address, const QString &clientId, - const QString &connectionType); - void endSession(qint64 sessionId); - void clearSessionTables(); - void lockSessionTables(); - void unlockSessionTables(); - bool userSessionExists(const QString &userName); - bool usernameIsValid(const QString &user, QString &error); + const QString &connectionType) override; + void endSession(qint64 sessionId) override; + void clearSessionTables() override; + void lockSessionTables() override; + void unlockSessionTables() override; + bool userSessionExists(const QString &userName) override; + bool usernameIsValid(const QString &user, QString &error) override; bool checkUserIsBanned(const QString &ipAddress, const QString &userName, const QString &clientId, QString &banReason, - int &banSecondsRemaining); - int checkNumberOfUserAccounts(const QString &email); + int &banSecondsRemaining) override; + int checkNumberOfUserAccounts(const QString &email) override; bool registerUser(const QString &userName, const QString &realName, const QString &password, bool passwordNeedsHash, const QString &emailAddress, const QString &country, - bool active = false); - bool activateUser(const QString &userName, const QString &token); - void updateUsersClientID(const QString &userName, const QString &userClientID); - void updateUsersLastLoginData(const QString &userName, const QString &clientVersion); + bool active = false) override; + bool activateUser(const QString &userName, const QString &token) override; + void updateUsersClientID(const QString &userName, const QString &userClientID) override; + void updateUsersLastLoginData(const QString &userName, const QString &clientVersion) override; void logMessage(const int senderId, const QString &senderName, const QString &senderIp, const QString &logMessage, LogMessage_TargetType targetType, const int targetId, - const QString &targetName); - bool changeUserPassword(const QString &user, const QString &password, bool passwordNeedsHash); + const QString &targetName) override; + bool changeUserPassword(const QString &user, const QString &password, bool passwordNeedsHash) override; bool changeUserPassword(const QString &user, const QString &oldPassword, bool oldPasswordNeedsHash, const QString &newPassword, - bool newPasswordNeedsHash); + bool newPasswordNeedsHash) override; QList getUserBanHistory(const QString userName); bool addWarning(const QString userName, const QString adminName, const QString warningReason, const QString clientID); @@ -133,7 +133,7 @@ public: int &range, int &maxresults); bool addForgotPassword(const QString &user); - bool removeForgotPassword(const QString &user); + bool removeForgotPassword(const QString &user) override; bool doesForgotPasswordExist(const QString &user); bool updateUserToken(const QString &token, const QString &user); bool validateTableColumnStringData(const QString &table, diff --git a/servatrice/src/server_logger.cpp b/servatrice/src/server_logger.cpp index 31553cad..4453757b 100644 --- a/servatrice/src/server_logger.cpp +++ b/servatrice/src/server_logger.cpp @@ -45,7 +45,7 @@ void ServerLogger::startLog(const QString &logFileName) connect(this, SIGNAL(sigFlushBuffer()), this, SLOT(flushBuffer()), Qt::QueuedConnection); } -void ServerLogger::logMessage(QString message, void *caller) +void ServerLogger::logMessage(const QString &message, void *caller) { if (!logFile) return; diff --git a/servatrice/src/server_logger.h b/servatrice/src/server_logger.h index 0e11d23f..0ad092b6 100644 --- a/servatrice/src/server_logger.h +++ b/servatrice/src/server_logger.h @@ -18,7 +18,7 @@ public: ~ServerLogger(); public slots: void startLog(const QString &logFileName); - void logMessage(QString message, void *caller = 0); + void logMessage(const QString &message, void *caller = 0); void rotateLogs(); private slots: void flushBuffer(); diff --git a/servatrice/src/serversocketinterface.cpp b/servatrice/src/serversocketinterface.cpp index ce1770fb..ee6fa6c8 100644 --- a/servatrice/src/serversocketinterface.cpp +++ b/servatrice/src/serversocketinterface.cpp @@ -74,7 +74,6 @@ #include #include #include -#include #include #include @@ -388,7 +387,7 @@ bool AbstractServerSocketInterface::deckListHelper(int folderId, ServerInfo_Deck newItem->set_name(query->value(1).toString().toStdString()); ServerInfo_DeckStorage_File *newFile = newItem->mutable_file(); - newFile->set_creation_time(query->value(2).toDateTime().toTime_t()); + newFile->set_creation_time(query->value(2).toDateTime().toSecsSinceEpoch()); } return true; @@ -551,7 +550,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckUpload(const Comman ServerInfo_DeckStorage_TreeItem *fileInfo = re->mutable_new_file(); fileInfo->set_id(query->lastInsertId().toInt()); fileInfo->set_name(deckName.toStdString()); - fileInfo->mutable_file()->set_creation_time(QDateTime::currentDateTime().toTime_t()); + fileInfo->mutable_file()->set_creation_time(QDateTime::currentDateTime().toSecsSinceEpoch()); rc.setResponseExtension(re); } else if (cmd.has_deck_id()) { QSqlQuery *query = @@ -570,7 +569,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdDeckUpload(const Comman ServerInfo_DeckStorage_TreeItem *fileInfo = re->mutable_new_file(); fileInfo->set_id(cmd.deck_id()); fileInfo->set_name(deckName.toStdString()); - fileInfo->mutable_file()->set_creation_time(QDateTime::currentDateTime().toTime_t()); + fileInfo->mutable_file()->set_creation_time(QDateTime::currentDateTime().toSecsSinceEpoch()); rc.setResponseExtension(re); } else return Response::RespInvalidData; @@ -619,8 +618,8 @@ Response::ResponseCode AbstractServerSocketInterface::cmdReplayList(const Comman const int gameId = query1->value(0).toInt(); matchInfo->set_game_id(gameId); matchInfo->set_room_name(query1->value(2).toString().toStdString()); - const int timeStarted = query1->value(3).toDateTime().toTime_t(); - const int timeFinished = query1->value(4).toDateTime().toTime_t(); + const int timeStarted = query1->value(3).toDateTime().toSecsSinceEpoch(); + const int timeFinished = query1->value(4).toDateTime().toSecsSinceEpoch(); matchInfo->set_time_started(timeStarted); matchInfo->set_length(timeFinished - timeStarted); matchInfo->set_game_name(query1->value(5).toString().toStdString()); @@ -977,7 +976,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdBanFromServer(const Com if (cmd.has_visible_reason()) event.set_reason_str(visibleReason.toStdString()); if (minutes) - event.set_end_time(QDateTime::currentDateTime().addSecs(60 * minutes).toTime_t()); + event.set_end_time(QDateTime::currentDateTime().addSecs(60 * minutes).toSecsSinceEpoch()); for (int i = 0; i < userList.size(); ++i) { SessionEvent *se = userList[i]->prepareSessionEvent(event); userList[i]->sendProtocolItem(*se); @@ -1148,7 +1147,7 @@ Response::ResponseCode AbstractServerSocketInterface::cmdRegisterAccount(const C Response_Register *re = new Response_Register; re->set_denied_reason_str(banReason.toStdString()); if (banSecondsRemaining != 0) - re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsRemaining).toTime_t()); + re->set_denied_end_time(QDateTime::currentDateTime().addSecs(banSecondsRemaining).toSecsSinceEpoch()); rc.setResponseExtension(re); return Response::RespUserIsBanned; } @@ -1649,7 +1648,7 @@ bool AbstractServerSocketInterface::removeAdminFlagFromUser(const QString &userN Event_ConnectionClosed event; event.set_reason(Event_ConnectionClosed::DEMOTED); event.set_reason_str("Your moderator and/or judge status has been revoked."); - event.set_end_time(QDateTime::currentDateTime().toTime_t()); + event.set_end_time(QDateTime::currentDateTime().toSecsSinceEpoch()); SessionEvent *se = user->prepareSessionEvent(event); user->sendProtocolItem(*se); @@ -1765,7 +1764,7 @@ void TcpServerSocketInterface::flushOutputQueue() locker.relock(); } locker.unlock(); - servatrice->incTxBytes(totalBytes); + emit incTxBytes(totalBytes); // see above wrt mutex flushSocket(); } @@ -1859,7 +1858,7 @@ bool TcpServerSocketInterface::initTcpSession() WebsocketServerSocketInterface::WebsocketServerSocketInterface(Servatrice *_server, Servatrice_DatabaseInterface *_databaseInterface, QObject *parent) - : AbstractServerSocketInterface(_server, _databaseInterface, parent) + : AbstractServerSocketInterface(_server, _databaseInterface, parent), socket(nullptr) { } @@ -1885,17 +1884,12 @@ void WebsocketServerSocketInterface::initConnection(void *_socket) address = socket->peerAddress(); QByteArray websocketIPHeader = settingsCache->value("server/web_socket_ip_header", "").toByteArray(); - if (websocketIPHeader.length() > 0) { -#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0)) - if (socket->request().hasRawHeader(websocketIPHeader)) { - QString header(socket->request().rawHeader(websocketIPHeader)); - QHostAddress parsed(header); - if (!parsed.isNull()) - address = parsed; + if (websocketIPHeader.length() > 0 && socket->request().hasRawHeader(websocketIPHeader)) { + QString header(socket->request().rawHeader(websocketIPHeader)); + QHostAddress parsed(header); + if (!parsed.isNull()) { + address = parsed; } -#else - logger->logMessage(QString("Reading the websocket IP header is unsupported on this version of QT.")); -#endif } connect(socket, SIGNAL(binaryMessageReceived(const QByteArray &)), this, @@ -1905,7 +1899,7 @@ void WebsocketServerSocketInterface::initConnection(void *_socket) connect(socket, SIGNAL(disconnected()), this, SLOT(catchSocketDisconnected())); // Add this object to the server's list of connections before it can receive socket events. - // Otherwise, in case a of a socket error, it could be removed from the list before it is added. + // Otherwise, in case of a socket error, it could be removed from the list before it is added. server->addClient(this); logger->logMessage( @@ -1949,7 +1943,7 @@ void WebsocketServerSocketInterface::flushOutputQueue() if (outputQueue.isEmpty()) return; - int totalBytes = 0; + qint64 totalBytes = 0; while (!outputQueue.isEmpty()) { ServerMessage item = outputQueue.takeFirst(); locker.unlock(); @@ -1969,7 +1963,7 @@ void WebsocketServerSocketInterface::flushOutputQueue() locker.relock(); } locker.unlock(); - servatrice->incTxBytes(totalBytes); + emit incTxBytes(totalBytes); // see above wrt mutex flushSocket(); } diff --git a/servatrice/src/serversocketinterface.h b/servatrice/src/serversocketinterface.h index 55d452ea..b2ee2e27 100644 --- a/servatrice/src/serversocketinterface.h +++ b/servatrice/src/serversocketinterface.h @@ -63,6 +63,7 @@ protected slots: virtual void flushOutputQueue() = 0; signals: void outputQueueChanged(); + void incTxBytes(qint64 amount); protected: void logDebugMessage(const QString &message); diff --git a/servatrice/src/settingscache.cpp b/servatrice/src/settingscache.cpp index 8c33cdba..e606cc2c 100644 --- a/servatrice/src/settingscache.cpp +++ b/servatrice/src/settingscache.cpp @@ -45,6 +45,6 @@ QString SettingsCache::guessConfigurationPath() return guessFileName; #endif - guessFileName = QStandardPaths::writableLocation(QStandardPaths::DataLocation) + "/" + fileName; + guessFileName = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/" + fileName; return guessFileName; } diff --git a/servatrice/src/smtp/qxtmail_p.h b/servatrice/src/smtp/qxtmail_p.h index a9a9dc90..96d22c0d 100644 --- a/servatrice/src/smtp/qxtmail_p.h +++ b/servatrice/src/smtp/qxtmail_p.h @@ -26,9 +26,12 @@ #define QXTMAIL_P_H #include +#include #define QXT_MUST_QP(x) (x < char(32) || x > char(126) || x == '=' || x == '?') -QByteArray qxt_fold_mime_header(const QString& key, const QString& value, QTextCodec* latin1, - const QByteArray& prefix = QByteArray()); +QByteArray qxt_fold_mime_header(const QString &key, + const QString &value, + QTextCodec *latin1, + const QByteArray &prefix = QByteArray()); #endif // QXTMAIL_P_H diff --git a/servatrice/src/smtp/qxtmailmessage.cpp b/servatrice/src/smtp/qxtmailmessage.cpp index 45452aed..a1c5f440 100644 --- a/servatrice/src/smtp/qxtmailmessage.cpp +++ b/servatrice/src/smtp/qxtmailmessage.cpp @@ -379,6 +379,8 @@ QByteArray QxtMailMessage::rfc2822() const line = line + ' ' + word; word = ""; } + if (line.isEmpty()) + continue; if (line[0] == '.') rv += "."; rv += line + "\r\n"; diff --git a/servatrice/src/smtp/qxtsmtp.cpp b/servatrice/src/smtp/qxtsmtp.cpp index f9afd8c5..7f46234e 100644 --- a/servatrice/src/smtp/qxtsmtp.cpp +++ b/servatrice/src/smtp/qxtsmtp.cpp @@ -23,39 +23,44 @@ ** ****************************************************************************/ - /*! * \class QxtSmtp * \inmodule QxtNetwork * \brief The QxtSmtp class implements the SMTP protocol for sending email */ - - #include "qxtsmtp.h" -#include "qxtsmtp_p.h" + #include "qxthmac.h" -#include -#include +#include "qxtsmtp_p.h" + #include #include +#include +#include QxtSmtpPrivate::QxtSmtpPrivate() : QObject(0) { // empty ctor } -QxtSmtp::QxtSmtp(QObject* parent) : QObject(parent) +QxtSmtp::QxtSmtp(QObject *parent) : QObject(parent) { QXT_INIT_PRIVATE(QxtSmtp); qxt_d().state = QxtSmtpPrivate::Disconnected; qxt_d().nextID = 0; qxt_d().socket = new QSslSocket(this); QObject::connect(socket(), SIGNAL(encrypted()), this, SIGNAL(encrypted())); - //QObject::connect(socket(), SIGNAL(encrypted()), &qxt_d(), SLOT(ehlo())); + // QObject::connect(socket(), SIGNAL(encrypted()), &qxt_d(), SLOT(ehlo())); QObject::connect(socket(), SIGNAL(connected()), this, SIGNAL(connected())); QObject::connect(socket(), SIGNAL(disconnected()), this, SIGNAL(disconnected())); - QObject::connect(socket(), SIGNAL(error(QAbstractSocket::SocketError)), &qxt_d(), SLOT(socketError(QAbstractSocket::SocketError))); +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + QObject::connect(socket(), SIGNAL(errorOccurred(QAbstractSocket::SocketError)), &qxt_d(), + SLOT(socketError(QAbstractSocket::SocketError))); +#else + QObject::connect(socket(), SIGNAL(error(QAbstractSocket::SocketError)), &qxt_d(), + SLOT(socketError(QAbstractSocket::SocketError))); +#endif QObject::connect(this, SIGNAL(authenticated()), &qxt_d(), SLOT(sendNext())); QObject::connect(socket(), SIGNAL(readyRead()), &qxt_d(), SLOT(socketRead())); } @@ -65,7 +70,7 @@ QByteArray QxtSmtp::username() const return qxt_d().username; } -void QxtSmtp::setUsername(const QByteArray& username) +void QxtSmtp::setUsername(const QByteArray &username) { qxt_d().username = username; } @@ -75,12 +80,12 @@ QByteArray QxtSmtp::password() const return qxt_d().password; } -void QxtSmtp::setPassword(const QByteArray& password) +void QxtSmtp::setPassword(const QByteArray &password) { qxt_d().password = password; } -int QxtSmtp::send(const QxtMailMessage& message) +int QxtSmtp::send(const QxtMailMessage &message) { int messageID = ++qxt_d().nextID; qxt_d().pending.append(qMakePair(messageID, message)); @@ -94,19 +99,19 @@ int QxtSmtp::pendingMessages() const return qxt_d().pending.count(); } -QTcpSocket* QxtSmtp::socket() const +QTcpSocket *QxtSmtp::socket() const { return qxt_d().socket; } -void QxtSmtp::connectToHost(const QString& hostName, quint16 port) +void QxtSmtp::connectToHost(const QString &hostName, quint16 port) { qxt_d().useSecure = false; qxt_d().state = QxtSmtpPrivate::StartState; socket()->connectToHost(hostName, port); } -void QxtSmtp::connectToHost(const QHostAddress& address, quint16 port) +void QxtSmtp::connectToHost(const QHostAddress &address, quint16 port) { connectToHost(address.toString(), port); } @@ -126,157 +131,141 @@ void QxtSmtp::setStartTlsDisabled(bool disable) qxt_d().disableStartTLS = disable; } -QSslSocket* QxtSmtp::sslSocket() const +QSslSocket *QxtSmtp::sslSocket() const { return qxt_d().socket; } -void QxtSmtp::connectToSecureHost(const QString& hostName, quint16 port) +void QxtSmtp::connectToSecureHost(const QString &hostName, quint16 port) { qxt_d().useSecure = true; qxt_d().state = QxtSmtpPrivate::StartState; sslSocket()->connectToHostEncrypted(hostName, port); } -void QxtSmtp::connectToSecureHost(const QHostAddress& address, quint16 port) +void QxtSmtp::connectToSecureHost(const QHostAddress &address, quint16 port) { connectToSecureHost(address.toString(), port); } -bool QxtSmtp::hasExtension(const QString& extension) +bool QxtSmtp::hasExtension(const QString &extension) { return qxt_d().extensions.contains(extension); } -QString QxtSmtp::extensionData(const QString& extension) +QString QxtSmtp::extensionData(const QString &extension) { return qxt_d().extensions[extension]; } void QxtSmtpPrivate::socketError(QAbstractSocket::SocketError err) { - if (err == QAbstractSocket::SslHandshakeFailedError) - { + if (err == QAbstractSocket::SslHandshakeFailedError) { emit qxt_p().encryptionFailed(); - emit qxt_p().encryptionFailed( socket->errorString().toLatin1() ); - } - else if (state == StartState) - { + emit qxt_p().encryptionFailed(socket->errorString().toLatin1()); + } else if (state == StartState) { emit qxt_p().connectionFailed(); - emit qxt_p().connectionFailed( socket->errorString().toLatin1() ); + emit qxt_p().connectionFailed(socket->errorString().toLatin1()); } } void QxtSmtpPrivate::socketRead() { buffer += socket->readAll(); - while (true) - { + while (true) { int pos = buffer.indexOf("\r\n"); - if (pos < 0) return; + if (pos < 0) + return; QByteArray line = buffer.left(pos); buffer = buffer.mid(pos + 2); QByteArray code = line.left(3); - switch (state) - { - case StartState: - if (code[0] != '2') - { - socket->disconnectFromHost(); - } - else - { - ehlo(); - } - break; - case HeloSent: - case EhloSent: - case EhloGreetReceived: - parseEhlo(code, (line[3] != ' '), line.mid(4)); - break; - case StartTLSSent: - if (code == "220") - { - socket->startClientEncryption(); - ehlo(); - } - else - { - authenticate(); - } - break; - case AuthRequestSent: - case AuthUsernameSent: - if (authType == AuthPlain) authPlain(); - else if (authType == AuthLogin) authLogin(); - else authCramMD5(line.mid(4)); - break; - case AuthSent: - if (code[0] == '2') - { - state = Authenticated; - emit qxt_p().authenticated(); - } - else - { - state = Disconnected; - emit qxt_p().authenticationFailed(); - emit qxt_p().authenticationFailed( line ); - emit socket->disconnectFromHost(); - } - break; - case MailToSent: - case RcptAckPending: - if (code[0] != '2') { - emit qxt_p().mailFailed( pending.first().first, code.toInt() ); - emit qxt_p().mailFailed(pending.first().first, code.toInt(), line); - // pending.removeFirst(); - // DO NOT remove it, the body sent state needs this message to assigned the next mail failed message that will - // the sendNext - // a reset will be sent to clear things out + switch (state) { + case StartState: + if (code[0] != '2') { + socket->disconnectFromHost(); + } else { + ehlo(); + } + break; + case HeloSent: + case EhloSent: + case EhloGreetReceived: + parseEhlo(code, (line[3] != ' '), line.mid(4)); + break; + case StartTLSSent: + if (code == "220") { + socket->startClientEncryption(); + ehlo(); + } else { + authenticate(); + } + break; + case AuthRequestSent: + case AuthUsernameSent: + if (authType == AuthPlain) + authPlain(); + else if (authType == AuthLogin) + authLogin(); + else + authCramMD5(line.mid(4)); + break; + case AuthSent: + if (code[0] == '2') { + state = Authenticated; + emit qxt_p().authenticated(); + } else { + state = Disconnected; + emit qxt_p().authenticationFailed(); + emit qxt_p().authenticationFailed(line); + emit socket->disconnectFromHost(); + } + break; + case MailToSent: + case RcptAckPending: + if (code[0] != '2') { + emit qxt_p().mailFailed(pending.first().first, code.toInt()); + emit qxt_p().mailFailed(pending.first().first, code.toInt(), line); + // pending.removeFirst(); + // DO NOT remove it, the body sent state needs this message to assigned the next mail failed message + // that will the sendNext a reset will be sent to clear things out + sendNext(); + state = BodySent; + } else + sendNextRcpt(code, line); + break; + case SendingBody: + sendBody(code, line); + break; + case BodySent: + if (pending.count()) { + // if you removeFirst in RcpActpending/MailToSent on an error, and the queue is now empty, + // you will get into this state and then crash because no check is done. CHeck added but shouldnt + // be necessary since I commented out the removeFirst + if (code[0] != '2') { + emit qxt_p().mailFailed(pending.first().first, code.toInt()); + emit qxt_p().mailFailed(pending.first().first, code.toInt(), line); + } else + emit qxt_p().mailSent(pending.first().first); + pending.removeFirst(); + } sendNext(); - state = BodySent; - } - else - sendNextRcpt(code, line); - break; - case SendingBody: - sendBody(code, line); - break; - case BodySent: - if ( pending.count() ) - { - // if you removeFirst in RcpActpending/MailToSent on an error, and the queue is now empty, - // you will get into this state and then crash because no check is done. CHeck added but shouldnt - // be necessary since I commented out the removeFirst - if (code[0] != '2') - { - emit qxt_p().mailFailed(pending.first().first, code.toInt() ); - emit qxt_p().mailFailed(pending.first().first, code.toInt(), line); - } - else - emit qxt_p().mailSent(pending.first().first); - pending.removeFirst(); - } - sendNext(); - break; - case Resetting: - if (code[0] != '2') { - emit qxt_p().connectionFailed(); - emit qxt_p().connectionFailed( line ); - } - else { - state = Waiting; - sendNext(); - } - break; - case Disconnected: - case EhloExtensionsReceived: - case EhloDone: - case Authenticated: - case Waiting: - // only to make compiler happy - break; + break; + case Resetting: + if (code[0] != '2') { + emit qxt_p().connectionFailed(); + emit qxt_p().connectionFailed(line); + } else { + state = Waiting; + sendNext(); + } + break; + case Disconnected: + case EhloExtensionsReceived: + case EhloDone: + case Authenticated: + case Waiting: + // only to make compiler happy + break; } } } @@ -284,8 +273,7 @@ void QxtSmtpPrivate::socketRead() void QxtSmtpPrivate::ehlo() { QByteArray address = "127.0.0.1"; - foreach(const QHostAddress& addr, QNetworkInterface::allAddresses()) - { + foreach (const QHostAddress &addr, QNetworkInterface::allAddresses()) { if (addr == QHostAddress::LocalHost || addr == QHostAddress::LocalHostIPv6) continue; address = addr.toString().toLatin1(); @@ -296,53 +284,40 @@ void QxtSmtpPrivate::ehlo() state = EhloSent; } -void QxtSmtpPrivate::parseEhlo(const QByteArray& code, bool cont, const QString& line) +void QxtSmtpPrivate::parseEhlo(const QByteArray &code, bool cont, const QString &line) { - if (code != "250") - { + if (code != "250") { // error! - if (state != HeloSent) - { + if (state != HeloSent) { // maybe let's try HELO socket->write("helo\r\n"); state = HeloSent; - } - else - { + } else { // nope socket->write("QUIT\r\n"); socket->flush(); socket->disconnectFromHost(); } return; - } - else if (state != EhloGreetReceived) - { - if (!cont) - { + } else if (state != EhloGreetReceived) { + if (!cont) { // greeting only, no extensions state = EhloDone; - } - else - { + } else { // greeting followed by extensions state = EhloGreetReceived; return; } - } - else - { + } else { extensions[line.section(' ', 0, 0).toUpper()] = line.section(' ', 1); if (!cont) state = EhloDone; } - if (state != EhloDone) return; - if (extensions.contains("STARTTLS") && !disableStartTLS) - { + if (state != EhloDone) + return; + if (extensions.contains("STARTTLS") && !disableStartTLS) { startTLS(); - } - else - { + } else { authenticate(); } } @@ -355,48 +330,35 @@ void QxtSmtpPrivate::startTLS() void QxtSmtpPrivate::authenticate() { - if (!extensions.contains("AUTH") || username.isEmpty() || password.isEmpty()) - { + if (!extensions.contains("AUTH") || username.isEmpty() || password.isEmpty()) { state = Authenticated; emit qxt_p().authenticated(); - } - else - { + } else { #if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) QStringList auth = extensions["AUTH"].toUpper().split(' ', Qt::SkipEmptyParts); #else QStringList auth = extensions["AUTH"].toUpper().split(' ', QString::SkipEmptyParts); #endif - if (auth.contains("CRAM-MD5")) - { + if (auth.contains("CRAM-MD5")) { authCramMD5(); - } - else if (auth.contains("PLAIN")) - { + } else if (auth.contains("PLAIN")) { authPlain(); - } - else if (auth.contains("LOGIN")) - { + } else if (auth.contains("LOGIN")) { authLogin(); - } - else - { + } else { state = Authenticated; emit qxt_p().authenticated(); } } } -void QxtSmtpPrivate::authCramMD5(const QByteArray& challenge) +void QxtSmtpPrivate::authCramMD5(const QByteArray &challenge) { - if (state != AuthRequestSent) - { + if (state != AuthRequestSent) { socket->write("auth cram-md5\r\n"); authType = AuthCramMD5; state = AuthRequestSent; - } - else - { + } else { QxtHmac hmac(QCryptographicHash::Md5); hmac.setKey(password); hmac.addData(QByteArray::fromBase64(challenge)); @@ -408,14 +370,11 @@ void QxtSmtpPrivate::authCramMD5(const QByteArray& challenge) void QxtSmtpPrivate::authPlain() { - if (state != AuthRequestSent) - { + if (state != AuthRequestSent) { socket->write("auth plain\r\n"); authType = AuthPlain; state = AuthRequestSent; - } - else - { + } else { QByteArray auth; auth += '\0'; auth += username; @@ -428,60 +387,44 @@ void QxtSmtpPrivate::authPlain() void QxtSmtpPrivate::authLogin() { - if (state != AuthRequestSent && state != AuthUsernameSent) - { + if (state != AuthRequestSent && state != AuthUsernameSent) { socket->write("auth login\r\n"); authType = AuthLogin; state = AuthRequestSent; - } - else if (state == AuthRequestSent) - { + } else if (state == AuthRequestSent) { socket->write(username.toBase64() + "\r\n"); state = AuthUsernameSent; - } - else - { + } else { socket->write(password.toBase64() + "\r\n"); state = AuthSent; } } -static QByteArray qxt_extract_address(const QString& address) +static QByteArray qxt_extract_address(const QString &address) { int parenDepth = 0; int addrStart = -1; bool inQuote = false; int ct = address.length(); - for (int i = 0; i < ct; i++) - { + for (int i = 0; i < ct; i++) { QChar ch = address[i]; - if (inQuote) - { + if (inQuote) { if (ch == '"') inQuote = false; - } - else if (addrStart != -1) - { + } else if (addrStart != -1) { if (ch == '>') return address.mid(addrStart, (i - addrStart)).toLatin1(); - } - else if (ch == '(') - { + } else if (ch == '(') { parenDepth++; - } - else if (ch == ')') - { + } else if (ch == ')') { parenDepth--; - if (parenDepth < 0) parenDepth = 0; - } - else if (ch == '"') - { + if (parenDepth < 0) + parenDepth = 0; + } else if (ch == '"') { if (parenDepth == 0) inQuote = true; - } - else if (ch == '<') - { + } else if (ch == '<') { if (!inQuote && parenDepth == 0) addrStart = i + 1; } @@ -491,35 +434,31 @@ static QByteArray qxt_extract_address(const QString& address) void QxtSmtpPrivate::sendNext() { - if (state == Disconnected) - { + if (state == Disconnected) { // leave the mail in the queue if not ready to send return; } - if (pending.isEmpty()) - { + if (pending.isEmpty()) { // if there are no additional mails to send, finish up state = Waiting; emit qxt_p().finished(); return; } - if(state != Waiting) { + if (state != Waiting) { state = Resetting; socket->write("rset\r\n"); return; } - const QxtMailMessage& msg = pending.first().second; + const QxtMailMessage &msg = pending.first().second; rcptNumber = rcptAck = mailAck = 0; - recipients = msg.recipients(QxtMailMessage::To) + - msg.recipients(QxtMailMessage::Cc) + - msg.recipients(QxtMailMessage::Bcc); - if (recipients.count() == 0) - { + recipients = + msg.recipients(QxtMailMessage::To) + msg.recipients(QxtMailMessage::Cc) + msg.recipients(QxtMailMessage::Bcc); + if (recipients.count() == 0) { // can't send an e-mail with no recipients - emit qxt_p().mailFailed(pending.first().first, QxtSmtp::NoRecipients ); - emit qxt_p().mailFailed(pending.first().first, QxtSmtp::NoRecipients, QByteArray( "e-mail has no recipients" ) ); + emit qxt_p().mailFailed(pending.first().first, QxtSmtp::NoRecipients); + emit qxt_p().mailFailed(pending.first().first, QxtSmtp::NoRecipients, QByteArray("e-mail has no recipients")); pending.removeFirst(); sendNext(); return; @@ -528,87 +467,67 @@ void QxtSmtpPrivate::sendNext() // interprets any string starting with an uppercase R as a request // to renegotiate the SSL connection. socket->write("mail from:<" + qxt_extract_address(msg.sender()) + ">\r\n"); - if (extensions.contains("PIPELINING")) // almost all do nowadays + if (extensions.contains("PIPELINING")) // almost all do nowadays { - foreach(const QString& rcpt, recipients) - { + foreach (const QString &rcpt, recipients) { socket->write("rcpt to:<" + qxt_extract_address(rcpt) + ">\r\n"); } state = RcptAckPending; - } - else - { + } else { state = MailToSent; } } -void QxtSmtpPrivate::sendNextRcpt(const QByteArray& code, const QByteArray&line) +void QxtSmtpPrivate::sendNextRcpt(const QByteArray &code, const QByteArray &line) { int messageID = pending.first().first; - const QxtMailMessage& msg = pending.first().second; + const QxtMailMessage &msg = pending.first().second; - if (code[0] != '2') - { + if (code[0] != '2') { // on failure, emit a warning signal - if (!mailAck) - { + if (!mailAck) { emit qxt_p().senderRejected(messageID, msg.sender()); - emit qxt_p().senderRejected(messageID, msg.sender(), line ); - } - else - { + emit qxt_p().senderRejected(messageID, msg.sender(), line); + } else { emit qxt_p().recipientRejected(messageID, msg.sender()); emit qxt_p().recipientRejected(messageID, msg.sender(), line); } - } - else if (!mailAck) - { + } else if (!mailAck) { mailAck = true; - } - else - { + } else { rcptAck++; } - if (rcptNumber == recipients.count()) - { + if (rcptNumber == recipients.count()) { // all recipients have been sent - if (rcptAck == 0) - { + if (rcptAck == 0) { // no recipients were considered valid - emit qxt_p().mailFailed(messageID, code.toInt() ); + emit qxt_p().mailFailed(messageID, code.toInt()); emit qxt_p().mailFailed(messageID, code.toInt(), line); pending.removeFirst(); sendNext(); - } - else - { + } else { // at least one recipient was acknowledged, send mail body socket->write("data\r\n"); state = SendingBody; } - } - else if (state != RcptAckPending) - { + } else if (state != RcptAckPending) { // send the next recipient unless we're only waiting on acks socket->write("rcpt to:<" + qxt_extract_address(recipients[rcptNumber]) + ">\r\n"); rcptNumber++; - } - else - { + } else { // If we're only waiting on acks, just count them rcptNumber++; } } -void QxtSmtpPrivate::sendBody(const QByteArray& code, const QByteArray & line) +void QxtSmtpPrivate::sendBody(const QByteArray &code, const QByteArray &line) { int messageID = pending.first().first; - const QxtMailMessage& msg = pending.first().second; + const QxtMailMessage &msg = pending.first().second; - if (code[0] != '3') - { - emit qxt_p().mailFailed(messageID, code.toInt() ); + if (code[0] != '3') { + emit qxt_p().mailFailed(messageID, code.toInt()); emit qxt_p().mailFailed(messageID, code.toInt(), line); pending.removeFirst(); sendNext(); diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 9ca0bfeb..bce3afeb 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -44,10 +44,6 @@ if(NOT GTEST_FOUND) add_dependencies(password_hash_test gtest) endif() -find_package(Qt5 COMPONENTS Widgets REQUIRED) -set(TEST_QT_MODULES Qt5::Widgets) - - include_directories(${GTEST_INCLUDE_DIRS}) target_link_libraries(dummy_test Threads::Threads ${GTEST_BOTH_LIBRARIES}) target_link_libraries(expression_test cockatrice_common Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}) diff --git a/tests/carddatabase/CMakeLists.txt b/tests/carddatabase/CMakeLists.txt index 6aac4ebd..ee9605fa 100644 --- a/tests/carddatabase/CMakeLists.txt +++ b/tests/carddatabase/CMakeLists.txt @@ -1,11 +1,18 @@ ADD_DEFINITIONS("-DCARDDB_DATADIR=\"${CMAKE_CURRENT_SOURCE_DIR}/data/\"") -find_package(Qt5 COMPONENTS Concurrent Network Widgets Svg REQUIRED) +SET(TEST_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Concurrent ${COCKATRICE_QT_VERSION_NAME}::Network ${COCKATRICE_QT_VERSION_NAME}::Widgets ${COCKATRICE_QT_VERSION_NAME}::Svg) -QT5_WRAP_CPP(MOCKS_SOURCES - ../../cockatrice/src/settingscache.h - ../../cockatrice/src/settings/carddatabasesettings.h -) +IF(Qt6_FOUND) + QT6_WRAP_CPP(MOCKS_SOURCES + ../../cockatrice/src/settingscache.h + ../../cockatrice/src/settings/carddatabasesettings.h + ) +ELSEIF(Qt5_FOUND) + QT5_WRAP_CPP(MOCKS_SOURCES + ../../cockatrice/src/settingscache.h + ../../cockatrice/src/settings/carddatabasesettings.h + ) +ENDIF() add_executable(carddatabase_test carddatabase_test.cpp @@ -37,8 +44,6 @@ if(NOT GTEST_FOUND) add_dependencies(filter_string_test gtest) endif() -set(TEST_QT_MODULES Qt5::Concurrent Qt5::Network Qt5::Widgets Qt5::Svg) - target_link_libraries(carddatabase_test Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}) target_link_libraries(filter_string_test Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}) diff --git a/tests/carddatabase/filter_string_test.cpp b/tests/carddatabase/filter_string_test.cpp index f76f27b6..07824087 100644 --- a/tests/carddatabase/filter_string_test.cpp +++ b/tests/carddatabase/filter_string_test.cpp @@ -2,7 +2,6 @@ #include "mocks.h" #include "gtest/gtest.h" -#include CardDatabase *db; diff --git a/tests/expression_test.cpp b/tests/expression_test.cpp index 30569a19..51c4039a 100644 --- a/tests/expression_test.cpp +++ b/tests/expression_test.cpp @@ -1,7 +1,7 @@ #include "../common/expression.h" #include "gtest/gtest.h" -#include +#include #define TEST_EXPR(name, a, b) \ TEST(ExpressionTest, name) \ @@ -18,7 +18,7 @@ TEST_EXPR(Multiply, "2*2", 4) TEST_EXPR(Whitespace, "3 * 3", 9) TEST_EXPR(Powers, "2^8", 256) TEST_EXPR(OrderOfOperations, "2+2*2", 6) -TEST_EXPR(Fn, "2*cos(1)", 2 * cos(1)) +TEST_EXPR(Fn, "2*cos(1)", 2 * qCos(1)) TEST_EXPR(Variable, "x / 2", 4) TEST_EXPR(Negative, "-2 * 2", -4) TEST_EXPR(UnknownFnReturnsZero, "blah(22)", 0) diff --git a/tests/loading_from_clipboard/CMakeLists.txt b/tests/loading_from_clipboard/CMakeLists.txt index c778fb7b..efb36a08 100644 --- a/tests/loading_from_clipboard/CMakeLists.txt +++ b/tests/loading_from_clipboard/CMakeLists.txt @@ -9,8 +9,7 @@ if(NOT GTEST_FOUND) add_dependencies(loading_from_clipboard_test gtest) endif() -find_package(Qt5 COMPONENTS Concurrent Network Widgets REQUIRED) -set(TEST_QT_MODULES Qt5::Concurrent Qt5::Network Qt5::Widgets) +SET(TEST_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Concurrent ${COCKATRICE_QT_VERSION_NAME}::Network ${COCKATRICE_QT_VERSION_NAME}::Widgets) target_link_libraries(loading_from_clipboard_test cockatrice_common Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}) add_test(NAME loading_from_clipboard_test COMMAND loading_from_clipboard_test) diff --git a/vcpkg b/vcpkg index a863c848..b98afc9f 160000 --- a/vcpkg +++ b/vcpkg @@ -1 +1 @@ -Subproject commit a863c84812089836a3c0f2f215ab3e2579fc8acf +Subproject commit b98afc9f1192becb2f447cee485ce36ba111f9f6 diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 00000000..7d2c1a48 --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,11 @@ +{ + "name": "cockatrice", + "version-string": "1.0.0", + "dependencies": [ + "gtest", + "liblzma", + "protobuf", + "pthreads", + "zlib" + ] +} \ No newline at end of file diff --git a/vcpkg.txt b/vcpkg.txt deleted file mode 100644 index 359f420d..00000000 --- a/vcpkg.txt +++ /dev/null @@ -1,4 +0,0 @@ -protobuf -liblzma -zlib -gtest \ No newline at end of file