Support Qt6, Min Qt5.8, Fix Win32, Fix Servatrice

Add lock around deleting arrows for commanding cards

Add support for Qt6 w/ Backwards Qt5

Handle Qt5/6 cross compilation better

Last cleanups

caps matter

Fix serv

Prevent crash on 6.3.0 Linux & bump to 5.8 min

Prevent out of bounds indexing

Delete shutdown timer if it exists

Fixup ticket comments, remove unneeded guards

Try to add support for missing OSes

Update .ci/release_template.md

Update PR based on comments

Update XML name after done and remove Hirsute

Address local game crash

Address comments from PR (again)
Tests don't work on mac, will see if a problem on other OSes

make soundengine more consistent across qt versions

disable tests on distros that are covered by others

Fix Oracle Crash due to bad memory access

Update Oracle to use new Qt6 way of adding translations

Add support for Qt5/Qt6 compiling of Cockatrice

Remove unneeded calls to QtMath/cmath/math.h

Update how we handle bitwise comparisons for enums with Tray Icon

Change header guards to not duplicate function

Leave comment & Fix Path for GHA Qt

Update common/server.h

Update cockatrice/src/window_main.cpp

Rollback change on cmake module path for NSIS

check docker image requirements

add size limit to ccache

put variables in quotes

properly set build type on mac

avoid names used in cmake

fix up cmake module path

cmake 3.10 does not recognize prepend

Support Tests in FindQtRuntime

set ccache size on non debug builds as well

immediately return when removing non existing client

handle incTxBytes with a signal instead

don't set common link libraries in cockatrice/CMakeLists.txt

add comments

set macos qt version to 6

Try upgrading XCode versions to latest they can be supported on

Ensure Qt gets linked

add tmate so i can see what's going on

Qt6 points two directories further down than Qt5 with regard to the top lib path, so we need to account for this

Establish Plugins directory for Qt6

Establish TLS plugins for Qt6 services

Minor change for release channel network manager

Let windows build in parallel cores

Wrong symbols

Qt6 patch up for signal

add missing qt6 package on deb builds

boolean expressions are hard

negative indexes should go to the end

Intentionally fail cache

move size checks to individual zone types

Hardcode libs needed for building on Windows, as the regex was annoying

Update wording

use the --parallel option in all builds

clean up the .ci scripts some more

tweak fedora build

add os parameter to compile.sh

I don't really like this but it seems the easiest way
I'd prefer if these types of quirks would live in the main configuration
file, the yml

fixup yml

readd appended cache key to vcpkg step

fix windows 32 quirk

the json hash is already added to the key as well

remove os parameter and clean up ci files

set name_build.sh to output relative paths

set backwards compatible version of xcode and qt on mac

set QTDIR for mac builds on qt5

has no effect for qt6

export BUILD_DIR to name_build.sh

merge mac build steps

merge homebrew steps, set package suffix

link qt5

remove brew link

set qtdir to qt5 only

compile.sh vars need to be empty not 0

fix sets manager search bar on qt 5.12/15

fix oracle subprocess errors being ignored on qt 5

clean up translation loading

move en@source translation file so it will not get included in packages
NOTE: this needs to be done at transifex as well!

Use generator platform over osname

Short circuit if not Win defined
This commit is contained in:
ZeldaZach 2022-03-27 19:59:37 -04:00 committed by ZeldaZach
parent accd5e4df7
commit b02adccf87
114 changed files with 1925 additions and 1603 deletions

View file

@ -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/*

14
.ci/Fedora36/Dockerfile Normal file
View file

@ -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

View file

@ -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/*

View file

@ -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 [<package type>] runs make package, optionally force the type
# --suffix <suffix> renames package with this suffix, requires arg
# --server compiles servatrice
# --test runs tests
# --debug or --release or <arg> 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 [<size>] uses ccache and shows stats, optionally provide size
# --dir <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: <buildtype>/--debug/--release --format --install --package <package type> --suffix <suffix> --server --test --ccache --dir <dir>)
# --parallel <core count> 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 <package type> --suffix <suffix> --server --test --ccache <ccache_size> --dir <dir> --parallel <core_count>)
# 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

View file

@ -10,7 +10,8 @@
# --interactive immediately starts the image interactively for debugging
# --set-cache <location> sets the location to cache the image or for ccache
# requires: docker
# uses env: NAME CACHE BUILD GET SAVE INTERACTIVE (correspond to args: <name> --set-cache <cache> --build --get --save --interactive)
# uses env: NAME CACHE BUILD GET SAVE INTERACTIVE
# (correspond to args: <name> --set-cache <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,25 +75,26 @@ fi
if ! [[ $CACHE ]]; then
echo "cache dir is not set!" >&2
else
if ! [[ -d $CACHE ]]; then
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
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
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
fi
# Get the docker image from previously stored save
@ -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)")

35
.ci/download_openssl.sh Normal file
View file

@ -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"

View file

@ -66,4 +66,4 @@ EOM
echo "Something went wrong in our formatting checks: clangify returned $err" >&2
echo ""
;;
esac
esac

View file

@ -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"

View file

@ -8,18 +8,20 @@ git push -d origin --REPLACE-WITH-BETA-LIST--
include different targets -->
<pre>
<b>Pre-compiled binaries we serve:</b>
- <kbd>Windows 7/8/10 (32-bit)</kbd></i>
- <kbd>Windows 7/8/10 (64-bit)</kbd></i>
- <kbd>macOS 10.14</kbd> ("Mojave")</i>
- <kbd>macOS 10.15</kbd> ("Catalina")</i>
- <kbd>macOS 11.0</kbd> ("Big Sur")</i>
- <kbd>Ubuntu 18.04</kbd> ("Bionic Beaver")</i>
- <kbd>Ubuntu 20.04</kbd> ("Focal Fossa")</i>
- <kbd>Ubuntu 20.10</kbd> ("Groovy Gorilla")</i>
- <kbd>Ubuntu 21.04</kbd> ("Hirsute Hippo")</i>
- <kbd>Debian 10</kbd> ("Buster")</i>
- <kbd>Fedora 33</kbd></i>
- <kbd>Fedora 34</kbd></i>
- <kbd>Windows 7/8/10/11 (32-bit)</kbd>
- <kbd>Windows 7/8/10/11 (64-bit)</kbd>
- <kbd>macOS 10.14</kbd> ("Mojave")
- <kbd>macOS 10.15</kbd> ("Catalina")
- <kbd>macOS 11.0</kbd> ("Big Sur")
- <kbd>Ubuntu 18.04</kbd> ("Bionic Beaver")
- <kbd>Ubuntu 20.04</kbd> ("Focal Fossa")
- <kbd>Ubuntu 21.10</kbd> ("Impish Indri")
- <kbd>Ubuntu 22.04</kbd> ("Jammy Jellyfish")
- <kbd>Debian 10</kbd> ("Buster")
- <kbd>Debian 11</kbd> ("Bullseye")
- <kbd>Fedora 34</kbd>
- <kbd>Fedora 35</kbd>
- <kbd>Fedora 36</kbd>
<kbd>We are also packaged in Arch Linux's official community repository, courtesy of @FFY00</kbd></i>
<kbd>General linux support is available via a flatpak package (Flathub)</kbd></i>
</pre>

View file

@ -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

2
.gitignore vendored
View file

@ -6,7 +6,7 @@ mysql.cnf
.DS_Store
.idea/
*.aps
cmake-build-debug/
cmake-build-debug*
preferences
compile_commands.json
.vs/

View file

@ -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 <zahalpern+github@gmail.com>")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_NAME})
set(CPACK_PACKAGE_CONTACT "Zach Halpern <zach@cockatrice.us>")
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,16 +229,34 @@ 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")
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)
set(CPACK_GENERATOR NSIS ${CPACK_GENERATOR})
@ -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()

View file

@ -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

118
cmake/FindQtRuntime.cmake Normal file
View file

@ -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}")

View file

@ -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
# 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
)
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"
"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
)
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"
"C:/OpenSSL/"
"C:/OpenSSL-Win32/"
)
unset(_programfiles)
endif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
endif()
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}")

View file

@ -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()

View file

@ -48,6 +48,7 @@ AbstractClient::AbstractClient(QObject *parent)
qRegisterMetaType<QList<ServerInfo_User>>("QList<ServerInfo_User>");
qRegisterMetaType<Event_ReplayAdded>("Event_ReplayAdded");
qRegisterMetaType<QList<QString>>("missingFeatures");
qRegisterMetaType<PendingCommand *>("pendingCommand");
FeatureSet features;
features.initalizeFeatureList(clientFeatures);

View file

@ -16,7 +16,7 @@
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <cmath>
#include <QtMath>
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);

View file

@ -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<bool>(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();
}

View file

@ -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<bool>(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();
}

View file

@ -6,13 +6,9 @@
#include "main.h"
#include <QApplication>
#include <utility>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
#include <QScreen>
#else
#include <QDesktopWidget>
#endif
#include <QVBoxLayout>
#include <utility>
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<int>(pixmapHeight / aspectRatio);
pic->setFixedWidth(pixmapWidth);
pic->setFixedHeight(pixmapHeight);

View file

@ -2,6 +2,7 @@
#define CARDITEM_H
#include "abstractcarditem.h"
#include "server_card.h"
class CardDatabase;
class CardDragItem;

View file

@ -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: {

View file

@ -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);

View file

@ -6,6 +6,7 @@
#include <QDebug>
#include <QFile>
#include <QRegularExpression>
#include <QStringList>
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";
}

View file

@ -9,8 +9,8 @@
#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QMouseEvent>
#include <QtMath>
#include <algorithm>
#include <math.h>
DeckViewCardDragItem::DeckViewCardDragItem(DeckViewCard *_item,
const QPointF &_hotSpot,
@ -238,11 +238,9 @@ int DeckViewCardContainer::getCardTypeTextWidth() const
QFontMetrics fm(f);
int maxCardTypeWidth = 0;
QMapIterator<QString, DeckViewCard *> 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<int, int>(maxRows + 1, (int)ceil((qreal)maxCardCount / (qreal)(maxRows + 1)));
QPair<int, int>(maxRows + 1, (int)qCeil((qreal)maxCardCount / (qreal)(maxRows + 1)));
}
totalHeight = -spacing;

View file

@ -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();
}

View file

@ -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") + "</a>"));
QGridLayout *hintsGrid = new QGridLayout;
hintsGrid->setMargin(2);
hintsGrid->addWidget(labNotes, 0, 0);
hintsGroupBox = new QGroupBox(tr("Hints"));
hintsGroupBox->setLayout(hintsGrid);

View file

@ -17,7 +17,6 @@
#include <QComboBox>
#include <QDebug>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QGridLayout>
@ -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<ReleaseChannel *> 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()));

View file

@ -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;

View file

@ -4,7 +4,6 @@
#include <QByteArray>
#include <QString>
#include <cmath>
#include <functional>
peg::parser search(R"(

View file

@ -13,7 +13,7 @@
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QSet>
#include <math.h>
#include <QtMath>
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<int> columnWidth;

View file

@ -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);
}

View file

@ -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()) {

View file

@ -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();
}

View file

@ -27,6 +27,7 @@ protected:
public:
LocalServer_DatabaseInterface(LocalServer *_localServer);
~LocalServer_DatabaseInterface() = default;
AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler,
const QString &user,
const QString &password,

View file

@ -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...");

View file

@ -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()) {

View file

@ -99,7 +99,7 @@ QMap<QString, QPixmap> 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);

View file

@ -66,6 +66,7 @@
#include <QDebug>
#include <QMenu>
#include <QMetaType>
#include <QPainter>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
@ -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 {

View file

@ -28,7 +28,11 @@ bool PlayerListItemDelegate::editorEvent(QEvent *event,
if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) {
QMouseEvent *const mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->button() == Qt::RightButton) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
static_cast<PlayerListWidget *>(parent())->showContextMenu(mouseEvent->globalPosition().toPoint(), index);
#else
static_cast<PlayerListWidget *>(parent())->showContextMenu(mouseEvent->globalPos(), index);
#endif
return true;
}
}

View file

@ -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()

View file

@ -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;

View file

@ -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);

View file

@ -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));

View file

@ -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:

View file

@ -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<int>((qint64)maxTime * (qint64)event->position().x() / width());
#else
int newTime = static_cast<int>((qint64)maxTime * (qint64)event->x() / width());
#endif
newTime -= newTime % 200; // Time should always be a multiple of 200
if (newTime < currentTime) {
currentTime = 0;

View file

@ -1,5 +1,7 @@
#include "setsmodel.h"
#include <QSortFilterProxyModel>
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

View file

@ -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()

View file

@ -2,21 +2,15 @@
#include "settingscache.h"
#include <QApplication>
#include <QAudioOutput>
#include <QBuffer>
#include <QDebug>
#include <QFileInfo>
#include <QLibraryInfo>
#include <QStandardPaths>
#include <QDir>
#include <QMediaPlayer>
#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();

View file

@ -1,8 +1,8 @@
#ifndef SOUNDENGINE_H
#define SOUNDENGINE_H
#include <QDir>
#include <QMap>
#include <QMediaPlayer>
#include <QObject>
#include <QString>
@ -21,10 +21,9 @@ public:
QStringMap &getAvailableThemes();
private:
QMap<QString, QByteArray> audioData;
QBuffer *inputBuffer;
QAudioOutput *player;
QStringMap availableThemes;
QMap<QString, QString> audioData;
QMediaPlayer *player;
protected:
void ensureThemeDirectoryExists();

View file

@ -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

View file

@ -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()) {

View file

@ -4,7 +4,8 @@
#include <QApplication>
#include <QDebug>
#include <QDesktopWidget>
#include <QScreen>
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,

View file

@ -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."));
}

View file

@ -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();

View file

@ -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;

View file

@ -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);
};

View file

@ -8,6 +8,7 @@
#include <QNetworkReply>
#include <QNetworkRequest>
#include <QRegExp>
#include <QRegularExpression>
#include <QUrlQuery>
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();
}
}

View file

@ -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));

View file

@ -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;

View file

@ -296,7 +296,11 @@ bool UserListItemDelegate::editorEvent(QEvent *event,
if ((event->type() == QEvent::MouseButtonPress) && index.isValid()) {
QMouseEvent *const mouseEvent = static_cast<QMouseEvent *>(event);
if (mouseEvent->button() == Qt::RightButton) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
static_cast<UserList *>(parent())->showContextMenu(mouseEvent->globalPosition().toPoint(), index);
#else
static_cast<UserList *>(parent())->showContextMenu(mouseEvent->globalPos(), index);
#endif
return true;
}
}

View file

@ -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."));
}

View file

@ -14,7 +14,7 @@
#include <QDebug>
#include <QGraphicsSceneWheelEvent>
#include <QPainter>
#include <math.h>
#include <QtMath>
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();

View file

@ -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)

View file

@ -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);
}

View file

@ -4,7 +4,7 @@
#include <QByteArray>
#include <QString>
#include <cmath>
#include <QtMath>
#include <functional>
peg::parser math(R"(
@ -32,19 +32,17 @@ Expression::Expression(double initial) : value(initial)
{
if (default_functions == nullptr) {
default_functions = new QMap<QString, std::function<double(double)>>();
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<QString, std::function<double(double)>>(*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;

View file

@ -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());
}
/**

View file

@ -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;

View file

@ -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,

View file

@ -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 <QMap>
#include <QString>
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
{

View file

@ -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);

View file

@ -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;

View file

@ -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());
}
}

View file

@ -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<int, Server_Player *> playerIterator(game->getPlayers());
while (playerIterator.hasNext()) {
Server_Player *p = playerIterator.next().value();

View file

@ -25,8 +25,8 @@
#include <QDateTime>
#include <QDebug>
#include <QtMath>
#include <google/protobuf/descriptor.h>
#include <math.h>
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;
}

View file

@ -63,7 +63,6 @@ protected:
private:
QList<int> messageSizeOverTime, messageCountOverTime, commandCountOverTime;
int timeRunning, lastDataReceived, lastActionReceived;
QTimer *pingClock;
virtual void transmitProtocolItem(const ServerMessage &item) = 0;

View file

@ -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()

View file

@ -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;

View file

@ -3,7 +3,6 @@
#define STRINGSIZES_H
#include <QString>
#include <QtMath>
// max size for short strings, like names and things that are generally a single phrase
constexpr int MAX_NAME_LENGTH = 0xff;

View file

@ -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
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]

View file

@ -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()

View file

@ -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();

View file

@ -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('{'));

View file

@ -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);
}

View file

@ -82,7 +82,7 @@ public:
private:
QStringList findQmFiles();
QString languageName(const QString &qmFile);
QString languageName(const QString &lang);
private:
QLabel *label, *languageLabel, *versionLabel;

View file

@ -31,12 +31,13 @@
*/
#include "json.h"
#include <QMetaType>
#include <iostream>
namespace QtJson
{
static QString sanitizeString(QString str)
{
str.replace(QLatin1String("\\"), QLatin1String("\\\\"));
@ -52,10 +53,8 @@ static QString sanitizeString(QString str)
static QByteArray join(const QList<QByteArray> &list, const QByteArray &sep)
{
QByteArray res;
Q_FOREACH(const QByteArray &i, list)
{
if(!res.isEmpty())
{
Q_FOREACH (const QByteArray &i, list) {
if (!res.isEmpty()) {
res += sep;
}
res += i;
@ -79,22 +78,19 @@ QVariant Json::parse(const QString &json, bool &success)
{
success = true;
//Return an empty QVariant if the JSON data is either null or empty
if(!json.isNull() || !json.isEmpty())
{
// 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
// We'll start from index 0
int index = 0;
//Parse the first value
// Parse the first value
QVariant value = Json::parseValue(data, index, success);
//Return the parsed value
// Return the parsed value
return value;
}
else
{
//Return the empty QVariant
} else {
// Return the empty QVariant
return QVariant();
}
}
@ -110,41 +106,46 @@ QByteArray Json::serialize(const QVariant &data, bool &success)
QByteArray str;
success = true;
if(!data.isValid()) // invalid or null?
if (!data.isValid()) // invalid or null?
{
str = "null";
}
else if((data.type() == QVariant::List) || (data.type() == QVariant::StringList)) // variant is a list?
#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<QByteArray> values;
const QVariantList list = data.toList();
Q_FOREACH(const QVariant& v, list)
{
Q_FOREACH (const QVariant &v, list) {
QByteArray serializedValue = serialize(v);
if(serializedValue.isNull())
{
if (serializedValue.isNull()) {
success = false;
break;
}
values << serializedValue;
}
str = "[ " + join( values, ", " ) + " ]";
str = "[ " + join(values, ", ") + " ]";
}
else if(data.type() == QVariant::Hash) // variant is a hash?
#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<QString, QVariant> it( vhash );
QHashIterator<QString, QVariant> it(vhash);
str = "{ ";
QList<QByteArray> pairs;
while(it.hasNext())
{
while (it.hasNext()) {
it.next();
QByteArray serializedValue = serialize(it.value());
if(serializedValue.isNull())
{
if (serializedValue.isNull()) {
success = false;
break;
}
@ -155,18 +156,20 @@ QByteArray Json::serialize(const QVariant &data, bool &success)
str += join(pairs, ", ");
str += " }";
}
else if(data.type() == QVariant::Map) // variant is a map?
#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<QString, QVariant> it( vmap );
QMapIterator<QString, QVariant> it(vmap);
str = "{ ";
QList<QByteArray> pairs;
while(it.hasNext())
{
while (it.hasNext()) {
it.next();
QByteArray serializedValue = serialize(it.value());
if(serializedValue.isNull())
{
if (serializedValue.isNull()) {
success = false;
break;
}
@ -175,49 +178,56 @@ QByteArray Json::serialize(const QVariant &data, bool &success)
str += join(pairs, ", ");
str += " }";
}
else if((data.type() == QVariant::String) || (data.type() == QVariant::ByteArray)) // a string or a byte array?
#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();
}
else if(data.type() == QVariant::Double) // double?
#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"))
{
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<qulonglong>());
}
else if ( data.canConvert<qlonglong>() ) // any signed number?
} else if (data.canConvert<qlonglong>()) // any signed number?
{
str = QByteArray::number(data.value<qlonglong>());
}
else if (data.canConvert<long>())
{
} else if (data.canConvert<long>()) {
str = QString::number(data.value<long>()).toUtf8();
}
else if (data.canConvert<QString>()) // can value be converted to string?
} else if (data.canConvert<QString>()) // can value be converted to string?
{
// this will catch QDate, QDateTime, QUrl, ...
str = sanitizeString(data.toString()).toUtf8();
}
else
{
} else {
success = false;
}
if (success)
{
if (success) {
return str;
}
else
{
} else {
return QByteArray();
}
}
@ -227,10 +237,9 @@ 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))
{
// 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:
@ -252,7 +261,7 @@ QVariant Json::parseValue(const QString &json, int &index, bool &success)
break;
}
//If there were no tokens, flag the failure and return an empty QVariant
// If there were no tokens, flag the failure and return an empty QVariant
success = false;
return QVariant();
}
@ -265,65 +274,54 @@ QVariant Json::parseObject(const QString &json, int &index, bool &success)
QVariantMap map;
int token;
//Get rid of the whitespace and increment index
// Get rid of the whitespace and increment index
Json::nextToken(json, index);
//Loop through all of the key/value pairs of the object
// Loop through all of the key/value pairs of the object
bool done = false;
while(!done)
{
//Get the upcoming token
while (!done) {
// Get the upcoming token
token = Json::lookAhead(json, index);
if(token == JsonTokenNone)
{
if (token == JsonTokenNone) {
success = false;
return QVariantMap();
}
else if(token == JsonTokenComma)
{
} else if (token == JsonTokenComma) {
Json::nextToken(json, index);
}
else if(token == JsonTokenCurlyClose)
{
} else if (token == JsonTokenCurlyClose) {
Json::nextToken(json, index);
return map;
}
else
{
//Parse the key/value pair's name
} else {
// Parse the key/value pair's name
QString name = Json::parseString(json, index, success).toString();
if(!success)
{
if (!success) {
return QVariantMap();
}
//Get the next token
// 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)
{
// 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
// Parse the key/value pair's value
QVariant value = Json::parseValue(json, index, success);
if(!success)
{
if (!success) {
return QVariantMap();
}
//Assign the value to the key in the map
// Assign the value to the key in the map
map[name] = value;
}
}
//Return the map successfully
// Return the map successfully
return QVariant(map);
}
@ -337,30 +335,21 @@ QVariant Json::parseArray(const QString &json, int &index, bool &success)
Json::nextToken(json, index);
bool done = false;
while(!done)
{
while (!done) {
int token = Json::lookAhead(json, index);
if(token == JsonTokenNone)
{
if (token == JsonTokenNone) {
success = false;
return QVariantList();
}
else if(token == JsonTokenComma)
{
} else if (token == JsonTokenComma) {
Json::nextToken(json, index);
}
else if(token == JsonTokenSquaredClose)
{
} else if (token == JsonTokenSquaredClose) {
Json::nextToken(json, index);
break;
}
else
{
} else {
QVariant value = Json::parseValue(json, index, success);
if(!success)
{
if (!success) {
return QVariantList();
}
@ -384,67 +373,43 @@ QVariant Json::parseString(const QString &json, int &index, bool &success)
c = json[index++];
bool complete = false;
while(!complete)
{
if(index == json.size())
{
while (!complete) {
if (index == json.size()) {
break;
}
c = json[index++];
if(c == '\"')
{
if (c == '\"') {
complete = true;
break;
}
else if(c == '\\')
{
if(index == json.size())
{
} else if (c == '\\') {
if (index == json.size()) {
break;
}
c = json[index++];
if(c == '\"')
{
if (c == '\"') {
s.append('\"');
}
else if(c == '\\')
{
} else if (c == '\\') {
s.append('\\');
}
else if(c == '/')
{
} else if (c == '/') {
s.append('/');
}
else if(c == 'b')
{
} else if (c == 'b') {
s.append('\b');
}
else if(c == 'f')
{
} else if (c == 'f') {
s.append('\f');
}
else if(c == 'n')
{
} else if (c == 'n') {
s.append('\n');
}
else if(c == 'r')
{
} else if (c == 'r') {
s.append('\r');
}
else if(c == 't')
{
} else if (c == 't') {
s.append('\t');
}
else if(c == 'u')
{
} else if (c == 'u') {
int remainingLength = json.size() - index;
if(remainingLength >= 4)
{
if (remainingLength >= 4) {
QString unicodeStr = json.mid(index, 4);
int symbol = unicodeStr.toInt(0, 16);
@ -452,21 +417,16 @@ QVariant Json::parseString(const QString &json, int &index, bool &success)
s.append(QChar(symbol));
index += 4;
}
else
{
} else {
break;
}
}
}
else
{
} else {
s.append(c);
}
}
if(!complete)
{
if (!complete) {
success = false;
return QVariant();
}
@ -506,15 +466,13 @@ int Json::lastIndexOfNumber(const QString &json, int index)
static const QString numericCharacters("0123456789+-.eE");
int lastIndex;
for(lastIndex = index; lastIndex < json.size(); lastIndex++)
{
if(numericCharacters.indexOf(json[lastIndex]) == -1)
{
for (lastIndex = index; lastIndex < json.size(); lastIndex++) {
if (numericCharacters.indexOf(json[lastIndex]) == -1) {
break;
}
}
return lastIndex -1;
return lastIndex - 1;
}
/**
@ -523,10 +481,8 @@ 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)
{
for (; index < json.size(); index++) {
if (whitespaceChars.indexOf(json[index]) == -1) {
break;
}
}
@ -548,60 +504,65 @@ int Json::nextToken(const QString &json, int &index)
{
Json::eatWhitespace(json, index);
if(index == json.size())
{
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;
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')
{
// 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')
{
// 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')
{
// Null
if (remainingLength >= 4) {
if (json[index] == 'n' && json[index + 1] == 'u' && json[index + 2] == 'l' && json[index + 3] == 'l') {
index += 4;
return JsonTokenNull;
}
@ -610,5 +571,4 @@ int Json::nextToken(const QString &json, int &index)
return JsonTokenNone;
}
} //end namespace
} // namespace QtJson

37
oracle/src/zip/unzip.h Executable file → Normal file
View file

@ -33,14 +33,12 @@
#include <QtCore/QDateTime>
#include <QtCore/QMap>
#include <QtCore/QtGlobal>
#include <zlib.h>
class QDir;
class QFile;
class QIODevice;
class QString;
class QStringList;
OSDAB_BEGIN_NAMESPACE(Zip)
@ -68,7 +66,8 @@ public:
InvalidArchive,
HeaderConsistencyError,
Skip, SkipAll // internal use only
Skip,
SkipAll // internal use only
};
enum ExtractionOption
@ -82,12 +81,15 @@ public:
enum CompressionMethod
{
NoCompression, Deflated, UnknownCompression
NoCompression,
Deflated,
UnknownCompression
};
enum FileType
{
File, Directory
File,
Directory
};
struct ZipEntry
@ -114,35 +116,36 @@ public:
bool isOpen() const;
ErrorCode openArchive(const QString& filename);
ErrorCode openArchive(QIODevice* device);
ErrorCode openArchive(const QString &filename);
ErrorCode openArchive(QIODevice *device);
void closeArchive();
QString archiveComment() const;
QString formatError(UnZip::ErrorCode c) const;
bool contains(const QString& file) const;
bool contains(const QString &file) const;
QStringList fileList() const;
QList<ZipEntry> 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)

18
oracle/src/zip/zipglobal.cpp Executable file → Normal file
View file

@ -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 <ctime>
#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

View file

@ -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]

View file

@ -34,7 +34,6 @@
#include <QMetaType>
#include <QTextCodec>
#include <QtGlobal>
#include <google/protobuf/stubs/common.h>
#include <iostream>
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;
}

View file

@ -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>("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,9 +715,10 @@ void Servatrice::shutdownTimeout()
clientsLock.unlock();
delete se;
if (!shutdownMinutes)
if (!shutdownMinutes) {
deleteLater();
}
}
shutdownMinutes--;
}

View file

@ -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<QString, bool> serverRequiredFeatureList;
QString officialWarnings;
Servatrice_DatabaseInterface *servatriceDatabaseInterface;
@ -173,7 +172,6 @@ private:
int shutdownMinutes;
int nextShutdownMessageMinutes;
QTimer *shutdownTimer;
bool isFirstShutdownMessage;
mutable QMutex serverListMutex;
QList<ServerProperties> 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<ServerProperties> getServerList() const;

View file

@ -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
{

View file

@ -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);

View file

@ -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<QString, ServerInfo_User> getBuddyList(const QString &name);
QMap<QString, ServerInfo_User> 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<QString, ServerInfo_User> getBuddyList(const QString &name) override;
QMap<QString, ServerInfo_User> 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<QString> &allPlayersEver,
const QSet<QString> &allSpectatorsEver,
const QList<GameReplay *> &replayList);
DeckList *getDeckFromDatabase(int deckId, int userId);
const QList<GameReplay *> &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<ServerInfo_Ban> 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,

View file

@ -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;

View file

@ -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();

Some files were not shown because too many files have changed in this diff Show more