mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-06 05:23:56 -07:00
Merge branch 'Cockatrice:master' into master
This commit is contained in:
commit
f226a961c4
365 changed files with 23933 additions and 3642 deletions
118
.appveyor.yml
118
.appveyor.yml
|
|
@ -1,118 +0,0 @@
|
||||||
version: build {build}
|
|
||||||
|
|
||||||
# Skipping commits affecting specific files (GitHub only).
|
|
||||||
# More details here: https://www.appveyor.com/docs/appveyor-yml and https://www.appveyor.com/docs/how-to/filtering-commits
|
|
||||||
skip_commits:
|
|
||||||
files:
|
|
||||||
- .ci/travis-*
|
|
||||||
- .github/
|
|
||||||
- .tx/
|
|
||||||
- webclient/
|
|
||||||
- .clang-format
|
|
||||||
- .*ignore
|
|
||||||
- .codacy.yml
|
|
||||||
- .travis.yml
|
|
||||||
- '**/*.md'
|
|
||||||
- Dockerfile
|
|
||||||
- LICENSE
|
|
||||||
|
|
||||||
skip_branch_with_pr: true
|
|
||||||
|
|
||||||
clone_depth: 15
|
|
||||||
|
|
||||||
image: Visual Studio 2017
|
|
||||||
|
|
||||||
cache:
|
|
||||||
- c:\Tools\vcpkg\installed
|
|
||||||
|
|
||||||
environment:
|
|
||||||
matrix:
|
|
||||||
- target_arch: win64
|
|
||||||
qt_ver: 5.12\msvc2017_64
|
|
||||||
cmake_generator: Visual Studio 15 2017 Win64
|
|
||||||
cmake_toolset: v141,host=x64
|
|
||||||
vcpkg_arch: x64
|
|
||||||
|
|
||||||
- target_arch: win32
|
|
||||||
qt_ver: 5.12\msvc2017
|
|
||||||
cmake_generator: Visual Studio 15 2017
|
|
||||||
cmake_toolset: v141
|
|
||||||
vcpkg_arch: x86
|
|
||||||
|
|
||||||
install:
|
|
||||||
- cd C:\Tools\vcpkg
|
|
||||||
- git pull -q
|
|
||||||
- .\bootstrap-vcpkg.bat
|
|
||||||
- cd %APPVEYOR_BUILD_FOLDER%
|
|
||||||
- vcpkg remove --outdated --recurse
|
|
||||||
- vcpkg install openssl protobuf liblzma zlib gtest --triplet %vcpkg_arch%-windows
|
|
||||||
|
|
||||||
services:
|
|
||||||
- mysql
|
|
||||||
|
|
||||||
build_script:
|
|
||||||
- ps: |
|
|
||||||
New-Item -ItemType directory -Path $env:APPVEYOR_BUILD_FOLDER\build
|
|
||||||
Set-Location -Path $env:APPVEYOR_BUILD_FOLDER\build
|
|
||||||
$vcpkgbindir = "C:\Tools\vcpkg\installed\$env:vcpkg_arch-windows\bin"
|
|
||||||
$mysqldll = "c:\Program Files\MySQL\MySQL Server 5.7\lib\libmysql.dll"
|
|
||||||
cmake --version
|
|
||||||
cmake .. -G "$env:cmake_generator" -T "$env:cmake_toolset" "-DCMAKE_C_FLAGS=/MP" "-DCMAKE_CXX_FLAGS=/MP" "-DCMAKE_TOOLCHAIN_FILE=c:/tools/vcpkg/scripts/buildsystems/vcpkg.cmake" "-DCMAKE_PREFIX_PATH=c:/Qt/$env:qt_ver;$vcpkgbindir" "-DWITH_SERVER=1" "-DMYSQLCLIENT_LIBRARIES=$mysqldll" "-DTEST=1"
|
|
||||||
- msbuild PACKAGE.vcxproj /p:Configuration=Release /logger:"C:\Program Files\AppVeyor\BuildAgent\Appveyor.MSBuildLogger.dll" /m
|
|
||||||
- ps: |
|
|
||||||
$exe = dir -name *.exe
|
|
||||||
$new_name = $exe.Replace(".exe", "-${env:target_arch}.exe")
|
|
||||||
Push-AppveyorArtifact $exe -FileName $new_name
|
|
||||||
$cmake_name = $exe.Replace(".exe", "-${env:target_arch}.cmake.txt")
|
|
||||||
Push-AppveyorArtifact CMakeCache.txt -FileName $cmake_name
|
|
||||||
$json = New-Object PSObject
|
|
||||||
(New-Object PSObject | Add-Member -PassThru NoteProperty bin $new_name | Add-Member -PassThru NoteProperty cmake $cmake_name | Add-Member -PassThru NoteProperty commit $env:APPVEYOR_REPO_COMMIT) | ConvertTo-JSON | Out-File -FilePath "latest-$env:target_arch" -Encoding ASCII
|
|
||||||
Push-AppveyorArtifact "latest-$env:target_arch"
|
|
||||||
$version = $matches['content']
|
|
||||||
|
|
||||||
test_script:
|
|
||||||
- ps: |
|
|
||||||
$env:Path += ";c:/Qt/$env:qt_ver/bin"
|
|
||||||
ctest -T Test -C Release
|
|
||||||
$ctest_success = $?
|
|
||||||
$XSLInputElement = New-Object System.Xml.Xsl.XslCompiledTransform
|
|
||||||
$XSLInputElement.Load("https://raw.githubusercontent.com/rpavlik/jenkins-ctest-plugin/master/ctest-to-junit.xsl")
|
|
||||||
$XSLInputElement.Transform((Resolve-Path .\Testing\*\Test.xml), (Join-Path (Resolve-Path .) "ctest-to-junit-results.xml"))
|
|
||||||
$wc = New-Object 'System.Net.WebClient'
|
|
||||||
$wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\ctest-to-junit-results.xml))
|
|
||||||
if (-not $ctest_success) { throw "Tests failed" }
|
|
||||||
|
|
||||||
|
|
||||||
# Builds for pull requests skip the deployment step altogether
|
|
||||||
deploy:
|
|
||||||
# Deploy configuration for "beta" releases
|
|
||||||
- provider: GitHub
|
|
||||||
auth_token:
|
|
||||||
secure: z8Xh1lSCYtvs0SUfhOK6AijCFk0Rgf5jAxu7QvBByR42NG1SxFHPOmyrOllkfy1u
|
|
||||||
tag: "$(APPVEYOR_REPO_TAG_NAME)"
|
|
||||||
release: "Cockatrice $(APPVEYOR_REPO_TAG_NAME)"
|
|
||||||
description: "Beta release of Cockatrice"
|
|
||||||
artifact: /.*\.exe/
|
|
||||||
draft: false
|
|
||||||
prerelease: true
|
|
||||||
on:
|
|
||||||
APPVEYOR_REPO_TAG: true
|
|
||||||
APPVEYOR_REPO_TAG_NAME: /([0-9]|[1-9][0-9])(\.([0-9]|[1-9][0-9])){2}-beta(\.([2-9]|[1-9][0-9]))?$/ # regex to match semver naming convention for beta pre-releases
|
|
||||||
|
|
||||||
# Deploy configuration for "stable" releases
|
|
||||||
- provider: GitHub
|
|
||||||
auth_token:
|
|
||||||
secure: z8Xh1lSCYtvs0SUfhOK6AijCFk0Rgf5jAxu7QvBByR42NG1SxFHPOmyrOllkfy1u
|
|
||||||
tag: "$(APPVEYOR_REPO_TAG_NAME)"
|
|
||||||
release: "Cockatrice $(APPVEYOR_REPO_TAG_NAME)"
|
|
||||||
artifact: /.*\.exe/
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
on:
|
|
||||||
APPVEYOR_REPO_TAG: true
|
|
||||||
APPVEYOR_REPO_TAG_NAME: /([0-9]|[1-9][0-9])(\.([0-9]|[1-9][0-9])){2}$/ # regex to match semver naming convention for stable full releases
|
|
||||||
|
|
||||||
|
|
||||||
# Announcements of build image updates: https://www.appveyor.com/updates/
|
|
||||||
# Official validator for ".appveyor.yml" config file: https://ci.appveyor.com/tools/validate-yaml
|
|
||||||
# AppVeyor config documentation: https://www.appveyor.com/docs/build-configuration/
|
|
||||||
|
|
@ -5,6 +5,7 @@ RUN pacman --sync --refresh --sysupgrade --needed --noconfirm \
|
||||||
ccache \
|
ccache \
|
||||||
cmake \
|
cmake \
|
||||||
git \
|
git \
|
||||||
|
mariadb-libs \
|
||||||
protobuf \
|
protobuf \
|
||||||
qt5-base \
|
qt5-base \
|
||||||
qt5-multimedia \
|
qt5-multimedia \
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
g++ \
|
g++ \
|
||||||
git \
|
git \
|
||||||
liblzma-dev \
|
liblzma-dev \
|
||||||
|
libmariadb-dev-compat \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt5multimedia5-plugins \
|
libqt5multimedia5-plugins \
|
||||||
libqt5sql5-mysql \
|
libqt5sql5-mysql \
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
FROM fedora:32
|
FROM fedora:33
|
||||||
|
|
||||||
RUN dnf install -y \
|
RUN dnf install -y \
|
||||||
@development-tools \
|
@development-tools \
|
||||||
|
|
@ -10,6 +10,7 @@ RUN dnf install -y \
|
||||||
git \
|
git \
|
||||||
hicolor-icon-theme \
|
hicolor-icon-theme \
|
||||||
libappstream-glib \
|
libappstream-glib \
|
||||||
|
mariadb-devel \
|
||||||
protobuf-devel \
|
protobuf-devel \
|
||||||
qt5-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
qt5-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
||||||
rpm-build \
|
rpm-build \
|
||||||
21
.ci/Fedora34/Dockerfile
Normal file
21
.ci/Fedora34/Dockerfile
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
FROM fedora:34
|
||||||
|
|
||||||
|
RUN dnf install -y \
|
||||||
|
@development-tools \
|
||||||
|
ccache \
|
||||||
|
cmake \
|
||||||
|
desktop-file-utils \
|
||||||
|
file \
|
||||||
|
gcc-c++ \
|
||||||
|
git \
|
||||||
|
hicolor-icon-theme \
|
||||||
|
libappstream-glib \
|
||||||
|
mariadb-devel \
|
||||||
|
protobuf-devel \
|
||||||
|
qt5-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel \
|
||||||
|
rpm-build \
|
||||||
|
sqlite-devel \
|
||||||
|
wget \
|
||||||
|
xz-devel \
|
||||||
|
zlib-devel \
|
||||||
|
&& dnf clean all
|
||||||
|
|
@ -9,6 +9,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
g++ \
|
g++ \
|
||||||
git \
|
git \
|
||||||
liblzma-dev \
|
liblzma-dev \
|
||||||
|
libmariadb-dev-compat \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt5multimedia5-plugins \
|
libqt5multimedia5-plugins \
|
||||||
libqt5sql5-mysql \
|
libqt5sql5-mysql \
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ RUN apt-get update && \
|
||||||
g++ \
|
g++ \
|
||||||
git \
|
git \
|
||||||
liblzma-dev \
|
liblzma-dev \
|
||||||
|
libmariadb-dev-compat \
|
||||||
libprotobuf-dev \
|
libprotobuf-dev \
|
||||||
libqt5multimedia5-plugins \
|
libqt5multimedia5-plugins \
|
||||||
libqt5sql5-mysql \
|
libqt5sql5-mysql \
|
||||||
|
|
|
||||||
25
.ci/UbuntuGroovy/Dockerfile
Normal file
25
.ci/UbuntuGroovy/Dockerfile
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
FROM ubuntu:groovy
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
ccache \
|
||||||
|
clang-format \
|
||||||
|
cmake \
|
||||||
|
file \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
liblzma-dev \
|
||||||
|
libmariadb-dev-compat \
|
||||||
|
libprotobuf-dev \
|
||||||
|
libqt5multimedia5-plugins \
|
||||||
|
libqt5sql5-mysql \
|
||||||
|
libqt5svg5-dev \
|
||||||
|
libqt5websockets5-dev \
|
||||||
|
protobuf-compiler \
|
||||||
|
qt5-default \
|
||||||
|
qtmultimedia5-dev \
|
||||||
|
qttools5-dev \
|
||||||
|
qttools5-dev-tools \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
24
.ci/UbuntuHirsute/Dockerfile
Normal file
24
.ci/UbuntuHirsute/Dockerfile
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
FROM ubuntu:hirsute
|
||||||
|
|
||||||
|
RUN apt-get update && \
|
||||||
|
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
|
||||||
|
build-essential \
|
||||||
|
ccache \
|
||||||
|
clang-format \
|
||||||
|
cmake \
|
||||||
|
file \
|
||||||
|
g++ \
|
||||||
|
git \
|
||||||
|
liblzma-dev \
|
||||||
|
libmariadb-dev-compat \
|
||||||
|
libprotobuf-dev \
|
||||||
|
libqt5multimedia5-plugins \
|
||||||
|
libqt5sql5-mysql \
|
||||||
|
libqt5svg5-dev \
|
||||||
|
libqt5websockets5-dev \
|
||||||
|
protobuf-compiler \
|
||||||
|
qtmultimedia5-dev \
|
||||||
|
qttools5-dev \
|
||||||
|
qttools5-dev-tools \
|
||||||
|
&& apt-get clean \
|
||||||
|
&& rm -rf /var/lib/apt/lists/*
|
||||||
142
.ci/compile.sh
Executable file
142
.ci/compile.sh
Executable file
|
|
@ -0,0 +1,142 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# This script is to be used by the ci environment from the project root directory, do not use it from somewhere else.
|
||||||
|
|
||||||
|
# Read arguments
|
||||||
|
while [[ "$@" ]]; do
|
||||||
|
case "$1" in
|
||||||
|
'--')
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
'--format')
|
||||||
|
CHECK_FORMAT=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
'--install')
|
||||||
|
MAKE_INSTALL=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
'--package')
|
||||||
|
MAKE_PACKAGE=1
|
||||||
|
shift
|
||||||
|
if [[ $# != 0 && $1 != -* ]]; then
|
||||||
|
PACKAGE_TYPE="$1"
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
'--suffix')
|
||||||
|
shift
|
||||||
|
if [[ $# == 0 ]]; then
|
||||||
|
echo "::error file=$0::--suffix expects an argument"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
PACKAGE_SUFFIX="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
'--server')
|
||||||
|
MAKE_SERVER=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
'--test')
|
||||||
|
MAKE_TEST=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
'--debug')
|
||||||
|
BUILDTYPE="Debug"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
'--release')
|
||||||
|
BUILDTYPE="Release"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if [[ $1 == -* ]]; then
|
||||||
|
echo "::error file=$0::unrecognized option: $1"
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
BUILDTYPE="$1"
|
||||||
|
shift
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
|
||||||
|
# Check formatting using clang-format
|
||||||
|
if [[ $CHECK_FORMAT ]]; then
|
||||||
|
echo "::group::Run linter"
|
||||||
|
source ./.ci/lint.sh
|
||||||
|
echo "::endgroup::"
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# Setup
|
||||||
|
./servatrice/check_schema_version.sh
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
|
||||||
|
if [[ ! $CMAKE_BUILD_PARALLEL_LEVEL ]]; then
|
||||||
|
CMAKE_BUILD_PARALLEL_LEVEL=2 # default machines have 2 cores
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add cmake flags
|
||||||
|
if [[ $MAKE_SERVER ]]; then
|
||||||
|
flags+=" -DWITH_SERVER=1"
|
||||||
|
fi
|
||||||
|
if [[ $MAKE_TEST ]]; then
|
||||||
|
flags+=" -DTEST=1"
|
||||||
|
fi
|
||||||
|
if [[ $BUILDTYPE ]]; then
|
||||||
|
flags+=" -DCMAKE_BUILD_TYPE=$BUILDTYPE"
|
||||||
|
fi
|
||||||
|
if [[ $PACKAGE_TYPE ]]; then
|
||||||
|
flags+=" -DCPACK_GENERATOR=$PACKAGE_TYPE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $(uname) == "Darwin" ]]; then
|
||||||
|
# prepend ccache compiler binaries to path
|
||||||
|
PATH="/usr/local/opt/ccache/libexec:$PATH"
|
||||||
|
# Add qt install location when using homebrew
|
||||||
|
flags+=" -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5/"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Compile
|
||||||
|
echo "::group::Show ccache stats"
|
||||||
|
ccache --show-stats
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
echo "::group::Configure cmake"
|
||||||
|
cmake --version
|
||||||
|
cmake .. $flags
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
echo "::group::Build project"
|
||||||
|
cmake --build .
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
echo "::group::Show ccache stats again"
|
||||||
|
ccache --show-stats
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
if [[ $MAKE_TEST ]]; then
|
||||||
|
echo "::group::Run tests"
|
||||||
|
cmake --build . --target test
|
||||||
|
echo "::endgroup::"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $MAKE_INSTALL ]]; then
|
||||||
|
echo "::group::Install"
|
||||||
|
cmake --build . --target install
|
||||||
|
echo "::endgroup::"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ $MAKE_PACKAGE ]]; then
|
||||||
|
echo "::group::Create package"
|
||||||
|
cmake --build . --target package
|
||||||
|
echo "::endgroup::"
|
||||||
|
|
||||||
|
if [[ $PACKAGE_SUFFIX ]]; then
|
||||||
|
echo "::group::Update package name"
|
||||||
|
../.ci/name_build.sh "$PACKAGE_SUFFIX"
|
||||||
|
echo "::endgroup::"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# This script is to be sourced in .travis.yaml from the project root directory, do not use it from somewhere else.
|
# This script is to be used by the ci environment from the project root directory, do not use it from somewhere else.
|
||||||
|
|
||||||
# Creates or loads docker images to use in compilation, creates RUN function to start compilation on the docker image.
|
# Creates or loads docker images to use in compilation, creates RUN function to start compilation on the docker image.
|
||||||
# --get loads the image from a previously saved image cache, will build if no image is found
|
# --get loads the image from a previously saved image cache, will build if no image is found
|
||||||
# --build builds the image from the Dockerfile in .ci/$NAME
|
# --build builds the image from the Dockerfile in .ci/$NAME
|
||||||
|
|
@ -9,7 +10,7 @@
|
||||||
# uses env: NAME CACHE BUILD GET SAVE (correspond to args: <name> --set-cache <cache> --build --get --save)
|
# uses env: NAME CACHE BUILD GET SAVE (correspond to args: <name> --set-cache <cache> --build --get --save)
|
||||||
# sets env: RUN CCACHE_DIR IMAGE_NAME RUN_ARGS RUN_OPTS BUILD_SCRIPT
|
# 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
|
# exitcode: 1 for failure, 2 for missing dockerfile, 3 for invalid arguments
|
||||||
export BUILD_SCRIPT=".ci/travis-compile.sh"
|
export BUILD_SCRIPT=".ci/compile.sh"
|
||||||
|
|
||||||
project_name="cockatrice"
|
project_name="cockatrice"
|
||||||
save_extension=".tar.gz"
|
save_extension=".tar.gz"
|
||||||
|
|
@ -56,7 +57,7 @@ if ! [[ $NAME ]]; then
|
||||||
return 3
|
return 3
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export IMAGE_NAME="${project_name,,}_${NAME,,}"
|
export IMAGE_NAME="${project_name,,}_${NAME,,}" # lower case
|
||||||
|
|
||||||
docker_dir=".ci/$NAME"
|
docker_dir=".ci/$NAME"
|
||||||
if ! [[ -r $docker_dir/Dockerfile ]]; then
|
if ! [[ -r $docker_dir/Dockerfile ]]; then
|
||||||
|
|
@ -64,10 +65,14 @@ if ! [[ -r $docker_dir/Dockerfile ]]; then
|
||||||
return 2 # even if the image is cached, we do not want to run if there is no way to build this image
|
return 2 # even if the image is cached, we do not want to run if there is no way to build this image
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if ! [[ -d $CACHE ]]; then
|
if ! [[ $CACHE ]]; then
|
||||||
echo "could not find cache dir: $CACHE" >&2
|
echo "cache dir is not set!" >&2
|
||||||
unset CACHE
|
|
||||||
else
|
else
|
||||||
|
if ! [[ -d $CACHE ]]; then
|
||||||
|
echo "could not find cache dir: $CACHE" >&2
|
||||||
|
mkdir -p $CACHE
|
||||||
|
unset GET # the dir is empty
|
||||||
|
fi
|
||||||
if [[ $GET || $SAVE ]]; then
|
if [[ $GET || $SAVE ]]; then
|
||||||
img_dir="$CACHE/$image_cache"
|
img_dir="$CACHE/$image_cache"
|
||||||
img_save="$img_dir/$IMAGE_NAME$save_extension"
|
img_save="$img_dir/$IMAGE_NAME$save_extension"
|
||||||
|
|
@ -128,7 +133,7 @@ function RUN ()
|
||||||
{
|
{
|
||||||
echo "running image:"
|
echo "running image:"
|
||||||
if docker images | grep "$IMAGE_NAME"; then
|
if docker images | grep "$IMAGE_NAME"; then
|
||||||
args="--mount type=bind,source=$(pwd),target=/src -w=/src"
|
args="--mount type=bind,source=$PWD,target=/src -w=/src"
|
||||||
if [[ $CCACHE_DIR ]]; then
|
if [[ $CCACHE_DIR ]]; then
|
||||||
args+=" --mount type=bind,source=$CCACHE_DIR,target=/.ccache -e CCACHE_DIR=/.ccache"
|
args+=" --mount type=bind,source=$CCACHE_DIR,target=/.ccache -e CCACHE_DIR=/.ccache"
|
||||||
fi
|
fi
|
||||||
|
|
@ -1,9 +1,19 @@
|
||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
# Check formatting using clang-format
|
# fetch master branch
|
||||||
|
git fetch origin master
|
||||||
|
|
||||||
|
# unshallow if needed
|
||||||
|
echo "Finding merge base"
|
||||||
|
if ! git merge-base origin/master HEAD; then
|
||||||
|
echo "Could not find merge base, unshallowing repo"
|
||||||
|
git fetch --unshallow
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check formatting using clangify
|
||||||
echo "Checking your code using clang-format..."
|
echo "Checking your code using clang-format..."
|
||||||
|
|
||||||
diff="$(./clangify.sh --diff --cf-version)"
|
diff="$(./clangify.sh --diff --cf-version --branch origin/master)"
|
||||||
err=$?
|
err=$?
|
||||||
|
|
||||||
case $err in
|
case $err in
|
||||||
50
.ci/name_build.sh
Executable file
50
.ci/name_build.sh
Executable file
|
|
@ -0,0 +1,50 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# used by the ci to rename build artifacts
|
||||||
|
# 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="."
|
||||||
|
findrx="Cockatrice-*.*"
|
||||||
|
|
||||||
|
if [[ $1 ]]; then
|
||||||
|
SUFFIX="$1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check env
|
||||||
|
if [[ ! $SUFFIX ]]; then
|
||||||
|
echo "::error file=$0::SUFFIX is missing"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
# find file
|
||||||
|
found="$(find "$builddir" -maxdepth 1 -type f -name "$findrx" -print -quit)"
|
||||||
|
path="${found%/*}" # remove all after last /
|
||||||
|
file="${found##*/}" # remove all before last /
|
||||||
|
if [[ ! $file ]]; then
|
||||||
|
echo "::error file=$0::could not find package"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
if ! cd "$path"; then
|
||||||
|
echo "::error file=$0::could not get file path"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# set filename
|
||||||
|
name="${file%.*}" # remove all after last .
|
||||||
|
new_name="$name$SUFFIX."
|
||||||
|
if [[ $MAKE_ZIP ]]; then
|
||||||
|
filename="${new_name}zip"
|
||||||
|
echo "creating zip '$filename' from '$file'"
|
||||||
|
zip "$filename" "$file"
|
||||||
|
else
|
||||||
|
extension="${file##*.}" # remove all before last .
|
||||||
|
filename="$new_name$extension"
|
||||||
|
echo "renaming '$file' to '$filename'"
|
||||||
|
mv "$file" "$filename"
|
||||||
|
fi
|
||||||
|
ls -l "$PWD/$filename"
|
||||||
|
echo "::set-output name=path::$PWD/$filename"
|
||||||
|
echo "::set-output name=name::$filename"
|
||||||
112
.ci/prep_release.sh
Executable file
112
.ci/prep_release.sh
Executable file
|
|
@ -0,0 +1,112 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# sets the properties of ci releases
|
||||||
|
# this doesn't have to be 100% foolproof
|
||||||
|
# the releases are first made as drafts and will be vetted by a human
|
||||||
|
# it just has to provide a template
|
||||||
|
# this requires the repo to be unshallowed
|
||||||
|
template_path=".ci/release_template.md"
|
||||||
|
body_path="/tmp/release.md"
|
||||||
|
beta_regex='beta'
|
||||||
|
name_regex='set\(GIT_TAG_RELEASENAME "([[:print:]]+)")'
|
||||||
|
whitespace='^\s*$'
|
||||||
|
|
||||||
|
if [[ $1 ]]; then
|
||||||
|
TAG="$1"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# check env
|
||||||
|
if [[ ! $TAG ]]; then
|
||||||
|
echo "::error file=$0::TAG is missing"
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
# create title
|
||||||
|
if [[ $TAG =~ $beta_regex ]]; then
|
||||||
|
echo "::set-output name=is_beta::yes"
|
||||||
|
title="$TAG"
|
||||||
|
echo "creating beta release '$title'"
|
||||||
|
elif [[ ! $(cat CMakeLists.txt) =~ $name_regex ]]; then
|
||||||
|
echo "::error file=$0::could not find releasename in CMakeLists.txt"
|
||||||
|
exit 1
|
||||||
|
else
|
||||||
|
echo "::set-output name=is_beta::no"
|
||||||
|
name="${BASH_REMATCH[1]}"
|
||||||
|
version="${TAG##*-}"
|
||||||
|
title="Cockatrice $version: $name"
|
||||||
|
no_beta=1
|
||||||
|
echo "::set-output name=friendly_name::$name"
|
||||||
|
echo "creating full release '$title'"
|
||||||
|
fi
|
||||||
|
echo "::set-output name=title::$title"
|
||||||
|
|
||||||
|
# add release notes template
|
||||||
|
if [[ $no_beta ]]; then
|
||||||
|
body="$(cat "$template_path")"
|
||||||
|
if [[ ! $body ]]; then
|
||||||
|
echo "::warning file=$0::could not find release template"
|
||||||
|
fi
|
||||||
|
body="${body//--REPLACE-WITH-RELEASE-TITLE--/$title}"
|
||||||
|
else
|
||||||
|
body="--REPLACE-WITH-COMMIT-COUNT-- commits have been included over the previous --REPLACE-WITH-PREVIOUS-RELEASE-TYPE--
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>show changes</b></summary>
|
||||||
|
|
||||||
|
--REPLACE-WITH-GENERATED-LIST--
|
||||||
|
</details>"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# add git log to release notes
|
||||||
|
all_tags="
|
||||||
|
$(git tag)" # tags are ordered alphabetically
|
||||||
|
before="${all_tags%%
|
||||||
|
$TAG*}" # strip line with current tag an all lines after it
|
||||||
|
# note the extra newlines are needed to always have a last line
|
||||||
|
if [[ $all_tags == $before ]]; then
|
||||||
|
echo "::warning file=$0::could not find current tag"
|
||||||
|
else
|
||||||
|
while
|
||||||
|
previous="${before##*
|
||||||
|
}" # get the last line
|
||||||
|
# skip this tag if this is a full release and it's a beta or if empty
|
||||||
|
[[ $no_beta && $previous =~ $beta_regex || ! $previous ]]
|
||||||
|
do
|
||||||
|
beta_list+=" $previous" # add to list of skipped betas
|
||||||
|
next_before="${before%
|
||||||
|
*}" # strip the last line
|
||||||
|
if [[ $next_before == $before ]]; then
|
||||||
|
unset previous
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
before="$next_before"
|
||||||
|
done
|
||||||
|
if [[ $previous ]]; then
|
||||||
|
if generated_list="$(git log "$previous..$TAG" --pretty="- %s")"; then
|
||||||
|
count="$(git rev-list --count "$previous..$TAG")"
|
||||||
|
[[ $previous =~ $beta_regex ]] && previousreleasetype="beta release" || previousreleasetype="full release"
|
||||||
|
echo "adding list of commits to release notes:"
|
||||||
|
echo "'$previous' to '$TAG' ($count commits)"
|
||||||
|
# --> is the markdown comment escape sequence, emojis are way better
|
||||||
|
generated_list="${generated_list//-->/→}"
|
||||||
|
body="${body//--REPLACE-WITH-GENERATED-LIST--/$generated_list}"
|
||||||
|
body="${body//--REPLACE-WITH-COMMIT-COUNT--/$count}"
|
||||||
|
body="${body//--REPLACE-WITH-PREVIOUS-RELEASE-TAG--/$previous}"
|
||||||
|
body="${body//--REPLACE-WITH-PREVIOUS-RELEASE-TYPE--/$previousreleasetype}"
|
||||||
|
if [[ $beta_list =~ $whitespace ]]; then
|
||||||
|
beta_list="-n there are no betas to delete!"
|
||||||
|
else
|
||||||
|
echo "the following betas should be deleted after publishing:"
|
||||||
|
echo "$beta_list"
|
||||||
|
fi
|
||||||
|
body="${body//--REPLACE-WITH-BETA-LIST--/$beta_list}"
|
||||||
|
else
|
||||||
|
echo "::warning file=$0::failed to produce git log"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
echo "::warning file=$0::could not find previous tag"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# write to file
|
||||||
|
echo "::set-output name=body_path::$body_path"
|
||||||
|
echo "$body" >"$body_path"
|
||||||
94
.ci/release_template.md
Normal file
94
.ci/release_template.md
Normal file
|
|
@ -0,0 +1,94 @@
|
||||||
|
<!-- this template comes from .ci/release_template.md -->
|
||||||
|
|
||||||
|
<!-- Don't forget to delete the previous betas after publishing this!
|
||||||
|
git push -d origin --REPLACE-WITH-BETA-LIST--
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- This list of binaries should be updated every time the ci is changed to
|
||||||
|
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>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>
|
||||||
|
|
||||||
|
|
||||||
|
## General Notes
|
||||||
|
|
||||||
|
<!-- --REPLACE-WITH-RELEASE-TITLE-- should be placed here by the ci -->
|
||||||
|
We're pleased to announce the newest official release: <kbd>--REPLACE-WITH-RELEASE-TITLE--</kbd>
|
||||||
|
|
||||||
|
We hope you enjoy the changes made and we have listed all changes, with their corresponding tickets, since the last version of Cockatrice was released for your convenience.
|
||||||
|
|
||||||
|
If you ever encounter a bug, have a suggestion or idea, or feel a need for a developer to look into something, please feel free to [open a ticket](https://github.com/Cockatrice/Cockatrice/issues). ([How to create a GitHub Ticket for Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/How-to-Create-a-GitHub-Ticket-Regarding-Cockatrice))
|
||||||
|
|
||||||
|
For any information relating to Cockatrice, please take a look at our official site: **https://cockatrice.github.io**
|
||||||
|
|
||||||
|
If you'd like to help contribute to Cockatrice in any way, check out our [README](https://github.com/Cockatrice/Cockatrice#get-involved-). We're always available to answer questions you may have on how the program works and how you can provide a meaningful contribution.
|
||||||
|
|
||||||
|
|
||||||
|
## Upgrading Cockatrice
|
||||||
|
<!-- this optional section puts a warning banner for problems with updating
|
||||||
|
> ⚠️ **With this release, we no longer provide a ready-to-install binary for:**
|
||||||
|
> --DEPRECATED-OS-HERE--
|
||||||
|
-->
|
||||||
|
|
||||||
|
- Run the internal software updater: <kbd>Help → Check for Client Updates</kbd>
|
||||||
|
|
||||||
|
Don't forget to update your card database right after! (<kbd>Help → Check for Card Updates...</kbd>)
|
||||||
|
|
||||||
|
|
||||||
|
## Changelog
|
||||||
|
<!--
|
||||||
|
This list is generated and should be moved to their respective header and
|
||||||
|
possibly edited a little.
|
||||||
|
Append PR numbers of fixups to their main PR to keep the list coherent.
|
||||||
|
Put the quantity of remaining PR's below the highlights section.
|
||||||
|
Remove empty headers when done.
|
||||||
|
|
||||||
|
--REPLACE-WITH-GENERATED-LIST--
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Highlights of the release -->
|
||||||
|
### ⚠️ Important:
|
||||||
|
### ✨ New Features:
|
||||||
|
### 🐛 Fixed Bugs / Resolved issues:
|
||||||
|
|
||||||
|
<!-- Complete list of changes (foldable) -->
|
||||||
|
<details>
|
||||||
|
<summary>
|
||||||
|
📘 <b>Show all changes</b> (--REPLACE-WITH-COMMIT-COUNT-- commits)
|
||||||
|
</summary>
|
||||||
|
|
||||||
|
### User Interface
|
||||||
|
### Under the Hood
|
||||||
|
### Oracle
|
||||||
|
### Servatrice
|
||||||
|
### Webatrice
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
|
||||||
|
## Translations
|
||||||
|
- **Thanks for over 300 people contributing to 20+ different languages up to now!**
|
||||||
|
- Without the help of the community we couldn't offer that great language support... keep up the good work!
|
||||||
|
- It's actually very easy to join and help for yourself - find out more here:
|
||||||
|
- [Help us Translate Cockatrice into your native language!](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ)
|
||||||
|
|
||||||
|
|
||||||
|
## Special Thanks
|
||||||
|
<!-- Personalise this a bit! -->
|
||||||
|
We continue to find it amazing that so many people contribute their time, knowledge, code, testing and more to the project. We'd like to thank the entire Cockatrice community for their efforts.
|
||||||
|
<!-- We'd like to especially recognize @ZeldaZach, --ADD-CONTRIBUTORS-HERE-- for their help in preparing so many amazing new features for the user base. -->
|
||||||
|
|
@ -1,128 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# This script is to be used in .travis.yaml from the project root directory, do not use it from somewhere else.
|
|
||||||
|
|
||||||
# Read arguments
|
|
||||||
while [[ "$@" ]]; do
|
|
||||||
case "$1" in
|
|
||||||
'--format')
|
|
||||||
CHECK_FORMAT=1
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
'--install')
|
|
||||||
MAKE_INSTALL=1
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
'--package')
|
|
||||||
MAKE_PACKAGE=1
|
|
||||||
shift
|
|
||||||
if [[ $# != 0 && $1 != -* ]]; then
|
|
||||||
PACKAGE_NAME="$1"
|
|
||||||
shift
|
|
||||||
if [[ $# != 0 && $1 != -* ]]; then
|
|
||||||
PACKAGE_TYPE="$1"
|
|
||||||
shift
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
;;
|
|
||||||
'--server')
|
|
||||||
MAKE_SERVER=1
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
'--test')
|
|
||||||
MAKE_TEST=1
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
'--debug')
|
|
||||||
BUILDTYPE="Debug"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
'--release')
|
|
||||||
BUILDTYPE="Release"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
'--zip')
|
|
||||||
MAKE_ZIP=1
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
if [[ $1 == -* ]]; then
|
|
||||||
echo "unrecognized option: $1"
|
|
||||||
exit 3
|
|
||||||
fi
|
|
||||||
BUILDTYPE="$1"
|
|
||||||
shift
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
# Check formatting using clang-format
|
|
||||||
if [[ $CHECK_FORMAT ]]; then
|
|
||||||
source ./.ci/travis-lint.sh
|
|
||||||
fi
|
|
||||||
|
|
||||||
set -e
|
|
||||||
|
|
||||||
# Setup
|
|
||||||
./servatrice/check_schema_version.sh
|
|
||||||
mkdir -p build
|
|
||||||
cd build
|
|
||||||
|
|
||||||
if ! [[ $CORE_AMOUNT ]]; then
|
|
||||||
CORE_AMOUNT="2" # travis machines have 2 cores
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add cmake flags
|
|
||||||
if [[ $MAKE_SERVER ]]; then
|
|
||||||
flags+=" -DWITH_SERVER=1"
|
|
||||||
fi
|
|
||||||
if [[ $MAKE_TEST ]]; then
|
|
||||||
flags+=" -DTEST=1"
|
|
||||||
BUILDTYPE="Debug" # test requires buildtype Debug
|
|
||||||
fi
|
|
||||||
if [[ $BUILDTYPE ]]; then
|
|
||||||
flags+=" -DCMAKE_BUILD_TYPE=$BUILDTYPE"
|
|
||||||
fi
|
|
||||||
if [[ $PACKAGE_TYPE ]]; then
|
|
||||||
flags+=" -DCPACK_GENERATOR=$PACKAGE_TYPE"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Add qt install location when using brew
|
|
||||||
if [[ $(uname) == "Darwin" ]]; then
|
|
||||||
PATH="/usr/local/opt/ccache/bin:$PATH"
|
|
||||||
flags+=" -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5/"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# Compile
|
|
||||||
cmake --version
|
|
||||||
cmake .. $flags
|
|
||||||
make -j"$CORE_AMOUNT"
|
|
||||||
|
|
||||||
if [[ $MAKE_TEST ]]; then
|
|
||||||
make test
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $MAKE_INSTALL ]]; then
|
|
||||||
make install
|
|
||||||
fi
|
|
||||||
|
|
||||||
if [[ $MAKE_PACKAGE ]]; then
|
|
||||||
make package
|
|
||||||
if [[ $PACKAGE_NAME ]]; then
|
|
||||||
found="$(find . -maxdepth 1 -type f -name "Cockatrice-*.*" -print -quit)"
|
|
||||||
path="${found%/*}"
|
|
||||||
file="${found##*/}"
|
|
||||||
if [[ ! $file ]]; then
|
|
||||||
echo "could not find package" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
new_name="$path/${file%.*}-$PACKAGE_NAME."
|
|
||||||
if [[ $MAKE_ZIP ]]; then
|
|
||||||
zip "${new_name}zip" "$path/$file"
|
|
||||||
mv "$path/$file" "$path/_$file"
|
|
||||||
else
|
|
||||||
extension="${file##*.}"
|
|
||||||
mv "$path/$file" "$new_name$extension"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
@ -25,3 +25,7 @@ IndentCaseLabels: true
|
||||||
PointerAlignment: Right
|
PointerAlignment: Right
|
||||||
SortIncludes: true
|
SortIncludes: true
|
||||||
IncludeBlocks: Regroup
|
IncludeBlocks: Regroup
|
||||||
|
---
|
||||||
|
Language: Proto
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
.git/
|
.git/
|
||||||
build/
|
build/
|
||||||
.github/
|
.github/
|
||||||
.travis/
|
|
||||||
.tx/
|
.tx/
|
||||||
cockatrice/
|
cockatrice/
|
||||||
doc/
|
doc/
|
||||||
|
|
|
||||||
275
.github/CONTRIBUTING.md
vendored
275
.github/CONTRIBUTING.md
vendored
|
|
@ -1,4 +1,6 @@
|
||||||
[Introduction](#contributing-to-cockatrice) | [Code Style Guide](#code-style-guide) | [Translations](#translations) | [Release Management](#release-management)
|
[Introduction](#contributing-to-cockatrice) | [Code Style Guide](
|
||||||
|
#code-style-guide) | [Translations](#translations) | [Release Management](
|
||||||
|
#release-management)
|
||||||
|
|
||||||
----
|
----
|
||||||
|
|
||||||
|
|
@ -7,50 +9,89 @@
|
||||||
# Contributing to Cockatrice #
|
# Contributing to Cockatrice #
|
||||||
First off, thanks for taking the time to contribute to our project! 🎉 ❤ ️✨
|
First off, thanks for taking the time to contribute to our project! 🎉 ❤ ️✨
|
||||||
|
|
||||||
The following is a set of guidelines for contributing to Cockatrice. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request.
|
The following is a set of guidelines for contributing to Cockatrice. These are
|
||||||
|
mostly guidelines, not rules. Use your best judgment, and feel free to propose
|
||||||
|
changes to this document in a pull request.
|
||||||
|
|
||||||
|
|
||||||
# Recommended Setups #
|
# Recommended Setups #
|
||||||
|
|
||||||
For those developers who like the Linux or MacOS environment, many of our developers like working with a nifty program called [CLion](https://www.jetbrains.com/clion/). The program's a great asset and one of the best tools you'll find on these systems, but you're welcomed to use any IDE you most enjoy.
|
For those developers who like the Linux or MacOS environment, many of our
|
||||||
|
developers like working with a nifty program called [CLion](
|
||||||
|
https://www.jetbrains.com/clion/). The program's a great asset and one of the
|
||||||
|
best tools you'll find on these systems, but you're welcomed to use any IDE
|
||||||
|
you most enjoy.
|
||||||
|
|
||||||
Developers who like Windows development tend to find [Visual Studio](https://www.visualstudio.com/) the best tool for the job.
|
Developers who like Windows development tend to find [Visual Studio](
|
||||||
|
https://www.visualstudio.com/) the best tool for the job.
|
||||||
|
|
||||||
If you have any questions on IDEs, feel free to chat with us on [Gitter](https://gitter.im/Cockatrice/Cockatrice) and we would love to help answer your questions!
|
[](https://discord.gg/ZASRzKu)
|
||||||
|
[](https://gitter.im/Cockatrice/Cockatrice)
|
||||||
|
|
||||||
|
If you'd like to ask questions, get advice, or just want to say hi,
|
||||||
|
the Cockatrice Development Team uses [Discord](https://discord.gg/ZASRzKu)
|
||||||
|
for communications in the #dev channel. If you're not into Discord, we also
|
||||||
|
have a [Gitter](https://gitter.im/Cockatrice/Cockatrice) channel available,
|
||||||
|
albeit slightly less active.
|
||||||
|
|
||||||
|
|
||||||
# Code Style Guide #
|
# Code Style Guide #
|
||||||
|
|
||||||
### Formatting and continuous integration (ci) ###
|
### Formatting and continuous integration (CI) ###
|
||||||
|
|
||||||
We currently use Travis CI to check your code for formatting issues, if your pull request was rejected because of this it would show a message in the logs. Click on "Details" next to the failed Travis CI build and then click on the failed build (most likely the fastest one) to see the log.
|
We use a separate job on the CI to check your code for formatting issues. If
|
||||||
|
your pull request failed the test, you can check the output on the checks tab.
|
||||||
|
It's the first job called "linter", you can click the "Run clangify" step to
|
||||||
|
see the output of the test.
|
||||||
|
|
||||||
The message will look somewhat similar to this:
|
The message will look like this:
|
||||||
```
|
```
|
||||||
************************************************************
|
***********************************************************
|
||||||
*** Your code does not meet our formatting guidelines. ***
|
*** ***
|
||||||
*** Please correct it then commit and push your changes. ***
|
*** Your code does not comply with our style guide. ***
|
||||||
*** See our CONTRIBUTING.md file for more information. ***
|
*** ***
|
||||||
************************************************************
|
*** Please correct it or run the "clangify.sh" script. ***
|
||||||
|
*** Then commit and push those changes to this branch. ***
|
||||||
|
*** Check our CONTRIBUTING.md file for more details. ***
|
||||||
|
*** ***
|
||||||
|
*** Thank you ❤️ ***
|
||||||
|
*** ***
|
||||||
|
***********************************************************
|
||||||
```
|
```
|
||||||
The CONTRIBUTING.md file mentioned is this file. Please read [this section](#Formatting) for full information on our formatting guidelines.
|
The CONTRIBUTING.md file mentioned in that message is the file you are
|
||||||
|
currently reading. Please see [this section](#formatting) below for full
|
||||||
|
information on our formatting guidelines.
|
||||||
|
|
||||||
### Compatibility ###
|
### Compatibility ###
|
||||||
|
|
||||||
Cockatrice is currently compiled on all platforms using <kbd>C++11</kbd>. You'll notice <kbd>C++03</kbd> code throughout the codebase. Please feel free to help convert it over!
|
Cockatrice is currently compiled on all platforms using <kbd>C++11</kbd>.
|
||||||
|
You'll notice <kbd>C++03</kbd> code throughout the codebase. Please feel free
|
||||||
|
to help convert it over!
|
||||||
|
|
||||||
For consistency, we use Qt data structures where possible. For example, `QString` over
|
For consistency, we use Qt data structures where possible. For example,
|
||||||
`std::string` and `QList` over `std::vector`.
|
`QString` over `std::string` and `QList` over `std::vector`.
|
||||||
|
|
||||||
|
Do not use old C style casts in new code, instead use a [`static_cast<>`](
|
||||||
|
https://en.cppreference.com/w/cpp/language/static_cast)
|
||||||
|
or other appropriate conversion.
|
||||||
|
|
||||||
### Formatting ###
|
### Formatting ###
|
||||||
|
|
||||||
The handy tool `clang-format` can format your code for you, it is available for almost any environment. A special `.clang-format` configuration file is included in the project and is used to format your code.
|
The handy tool `clang-format` can format your code for you, it is available for
|
||||||
|
almost any environment. A special `.clang-format` configuration file is
|
||||||
|
included in the project and is used to format your code.
|
||||||
|
|
||||||
We've also included a bash script, `clangify.sh`, that will use clang-format to format all files in one go. Use `./clangify.sh --help` to show a full help page.
|
We've also included a bash script, `clangify.sh`, that will use clang-format to
|
||||||
|
format all files in your pr in one go. Use `./clangify.sh --help` to show a
|
||||||
|
full help page.
|
||||||
|
|
||||||
To run clang-format on a single source file simply use the command `clang-format -i <filename>` to format it in place. (some systems install clang-format with a specific version number appended, `find /usr/bin -name clang-format*` should find it for you)
|
To run clang-format on a single source file simply use the command
|
||||||
|
`clang-format -i <filename>` to format it in place. (Some systems install
|
||||||
|
clang-format with a specific version number appended,
|
||||||
|
`find /usr/bin -name clang-format*` should find it for you)
|
||||||
|
|
||||||
See [the clang-format documentation](https://clang.llvm.org/docs/ClangFormat.html) for more information about the tool.
|
See [the clang-format documentation](
|
||||||
|
https://clang.llvm.org/docs/ClangFormat.html) for more information about the tool.
|
||||||
|
|
||||||
#### Header files ####
|
#### Header files ####
|
||||||
|
|
||||||
|
|
@ -62,7 +103,8 @@ Use header guards in the form of `FILE_NAME_H`.
|
||||||
Simple functions, such as getters, may be written inline in the header file,
|
Simple functions, such as getters, may be written inline in the header file,
|
||||||
but other functions should be written in the source file.
|
but other functions should be written in the source file.
|
||||||
|
|
||||||
Group library includes after project includes, and in alphabetic order. Like this:
|
Group project includes first, followed by library includes. All in alphabetic order.
|
||||||
|
Like this:
|
||||||
```c++
|
```c++
|
||||||
// Good
|
// Good
|
||||||
#include "card.h"
|
#include "card.h"
|
||||||
|
|
@ -88,9 +130,15 @@ Group library includes after project includes, and in alphabetic order. Like thi
|
||||||
Use `UpperCamelCase` for classes, structs, enums, etc. and `lowerCamelCase` for
|
Use `UpperCamelCase` for classes, structs, enums, etc. and `lowerCamelCase` for
|
||||||
function and variable names.
|
function and variable names.
|
||||||
|
|
||||||
Member variables aren't decorated in any way. Don't prefix or suffix with
|
Don't use [Hungarian Notation](
|
||||||
|
https://en.wikipedia.org/wiki/Hungarian_notation).
|
||||||
|
|
||||||
|
Member variables aren't decorated in any way. Don't prefix or suffix them with
|
||||||
underscores, etc.
|
underscores, etc.
|
||||||
|
|
||||||
|
Use a separate line for each declaration, don't use a single line like this
|
||||||
|
`int one = 1, two = 2` and instead split them into two lines.
|
||||||
|
|
||||||
For arguments to constructors which have the same names as member variables,
|
For arguments to constructors which have the same names as member variables,
|
||||||
prefix those arguments with underscores:
|
prefix those arguments with underscores:
|
||||||
```c++
|
```c++
|
||||||
|
|
@ -115,7 +163,8 @@ If you find any usage of the old keywords, we encourage you to fix it.
|
||||||
|
|
||||||
#### Braces ####
|
#### Braces ####
|
||||||
|
|
||||||
Braces should go on their own line except for control statements, the use of braces around single line statements is preferred.
|
Braces should go on their own line except for control statements, the use of
|
||||||
|
braces around single line statements is preferred.
|
||||||
See the following example:
|
See the following example:
|
||||||
```c++
|
```c++
|
||||||
int main()
|
int main()
|
||||||
|
|
@ -136,17 +185,25 @@ int main()
|
||||||
|
|
||||||
#### Indentation and Spacing ####
|
#### Indentation and Spacing ####
|
||||||
|
|
||||||
Always indent using 4 spaces, do not use tabs. Opening and closing braces should be on the same indentation layer, member access specifiers in classes or structs should not be indented.
|
Always indent using 4 spaces, do not use tabs. Opening and closing braces
|
||||||
|
should be on the same indentation layer, member access specifiers in classes or
|
||||||
|
structs should not be indented.
|
||||||
|
|
||||||
All operators and braces should be separated by spaces, do not add a space next to the inside of a brace.
|
All operators and braces should be separated by spaces, do not add a space next
|
||||||
|
to the inside of a brace.
|
||||||
|
|
||||||
If multiple lines of code that follow eachother have single line comments behind them, place all of them on the same indentation level. This indentation level should be equal to the longest line of code for each of these comments, without added spacing.
|
If multiple lines of code that follow eachother have single line comments
|
||||||
|
behind them, place all of them on the same indentation level. This indentation
|
||||||
|
level should be equal to the longest line of code for each of these comments,
|
||||||
|
without added spacing.
|
||||||
|
|
||||||
#### Lines ####
|
#### Lines ####
|
||||||
|
|
||||||
Do not have trailing whitespace in your lines. Most IDEs check for this nowadays and clean it up for you.
|
Do not leave trailing whitespace on any line. Most IDEs check for this
|
||||||
|
nowadays and clean it up for you.
|
||||||
|
|
||||||
Lines should be 120 characters or less. Please break up lines that are too long into smaller parts, for example at spaces or after opening a brace.
|
Lines should be 120 characters or less. Please break up lines that are too long
|
||||||
|
into smaller parts, for example at spaces or after opening a brace.
|
||||||
|
|
||||||
### Memory Management ###
|
### Memory Management ###
|
||||||
|
|
||||||
|
|
@ -182,44 +239,93 @@ as `QScopedPointer`, or, less preferably, `QSharedPointer`.
|
||||||
The servatrice database's schema can be found at `servatrice/servatrice.sql`.
|
The servatrice database's schema can be found at `servatrice/servatrice.sql`.
|
||||||
Everytime the schema gets modified, some other steps are due:
|
Everytime the schema gets modified, some other steps are due:
|
||||||
1. Increment the value of `cockatrice_schema_version` in `servatrice.sql`;
|
1. Increment the value of `cockatrice_schema_version` in `servatrice.sql`;
|
||||||
2. Increment the value of `DATABASE_SCHEMA_VERSION` in `servatrice_database_interface.h` accordingly;
|
2. Increment the value of `DATABASE_SCHEMA_VERSION` in
|
||||||
3. Create a new migration file inside the `servatrice/migrations` directory named after the new schema version.
|
`servatrice_database_interface.h` accordingly;
|
||||||
4. Run the `servatrice/check_schema_version.sh` script to ensure everything is fine.
|
3. Create a new migration file inside the `servatrice/migrations` directory
|
||||||
|
named after the new schema version.
|
||||||
|
4. Run the `servatrice/check_schema_version.sh` script to ensure everything is
|
||||||
|
fine.
|
||||||
|
|
||||||
The migration file should include the sql statements needed to migrate the database schema and data from the previous to the new version, and an additional statement that updates `cockatrice_schema_version` to the correct value.
|
The migration file should include the sql statements needed to migrate the
|
||||||
|
database schema and data from the previous to the new version, and an
|
||||||
|
additional statement that updates `cockatrice_schema_version` to the correct
|
||||||
|
value.
|
||||||
|
|
||||||
Ensure that the migration produces the expected effects; e.g. if you add a new column, make sure the migration places it in the same order as servatrice.sql.
|
Ensure that the migration produces the expected effects; e.g. if you add a
|
||||||
|
new column, make sure the migration places it in the same order as
|
||||||
|
servatrice.sql.
|
||||||
|
|
||||||
### Protocol buffer ###
|
### Protocol buffer ###
|
||||||
|
|
||||||
Cockatrice and Servatrice exchange data using binary messages. The syntax of these messages is defined in the `proto` files in the `common/pb` folder. These files defines the way data contained in each message is serialized using Google's [protocol buffer](https://developers.google.com/protocol-buffers/).
|
Cockatrice and Servatrice exchange data using binary messages. The syntax of
|
||||||
Any change to the `proto` file should be taken with caution and tested intensively before being merged, becaus a change to the protocol could make new clients incompatible to the old server and vice versa.
|
these messages is defined in the `proto` files in the `common/pb` folder. These
|
||||||
|
files define the way data contained in each message is serialized using
|
||||||
|
Google's [protocol buffers](https://developers.google.com/protocol-buffers/).
|
||||||
|
Any change to the `proto` files should be taken with caution and tested
|
||||||
|
intensively before being merged, because a change to the protocol could make
|
||||||
|
new clients incompatible to the old server and vice versa.
|
||||||
|
|
||||||
You can find more information on how we use Protobuf on [our wiki!](https://github.com/Cockatrice/Cockatrice/wiki/Client-server-protocol)
|
You can find more information on how we use Protobuf on [our wiki!](
|
||||||
|
https://github.com/Cockatrice/Cockatrice/wiki/Client-server-protocol)
|
||||||
|
|
||||||
|
# Reviewing Pull Requests #
|
||||||
|
|
||||||
|
After you have finished your changes to the project you should put them on a
|
||||||
|
separate branch of your fork on GitHub and open a [pull request](
|
||||||
|
https://docs.github.com/en/free-pro-team@latest/desktop/contributing-and-collaborating-using-github-desktop/creating-an-issue-or-pull-request
|
||||||
|
).
|
||||||
|
Your code will then be automatically compiled by GitHub actions for Linux and
|
||||||
|
macOS, and by Appveyor for Windows. Additionally GitHub will perform a [Linting
|
||||||
|
check](#formatting-and-continuous-integration-ci). If any issues come up you
|
||||||
|
can check their status at the bottom of the pull request page, click on details
|
||||||
|
to go to the CI website and see the different build logs.
|
||||||
|
|
||||||
|
If your pull request passes our tests and has no merge conflicts, it will be
|
||||||
|
reviewed by our team members. You can then address any requested changes. When
|
||||||
|
all changes have been approved your pull request will be squashed into a single
|
||||||
|
commit and merged into the master branch by a team member. Your change will then
|
||||||
|
be included in the next release 👍
|
||||||
|
|
||||||
# Translations #
|
# Translations #
|
||||||
|
|
||||||
Basic workflow for translations:
|
Basic workflow for translations:
|
||||||
1. Developer adds a `tr("foo")` string in the code;
|
1. Developer adds a `tr("foo")` string in the code;
|
||||||
2. Every few days, a maintainer updates the `*_en.ts files` with the new strings;
|
2. Every few days, a maintainer updates the `*_en.ts files` with the new strings;
|
||||||
3. Transifex picks up the new files from github every 24 hours;
|
3. Transifex picks up the new files from GitHub every 24 hours;
|
||||||
4. Translators translate the new untranslated strings on Transifex;
|
4. Translators translate the new untranslated strings on Transifex;
|
||||||
5. Before a release, a maintainer fetches the updated translations from Transifex.
|
5. Before a release, a maintainer fetches the updated translations from Transifex.
|
||||||
|
|
||||||
### Using Translations (for developers) ###
|
### Using Translations (for developers) ###
|
||||||
|
|
||||||
All the user-interface strings inside Cockatrice's source code must be written in english.
|
All the user-interface strings inside Cockatrice's source code must be written
|
||||||
Translations to other languages are managed using [Transifex](https://www.transifex.com/projects/p/cockatrice/).
|
in English(US).
|
||||||
|
Translations to other languages are managed using [Transifex](
|
||||||
|
https://www.transifex.com/projects/p/cockatrice/).
|
||||||
|
|
||||||
Adding a new string to translate is as easy as adding the string in the 'tr("")' function, the string will be picked up as translatable automatically and translated as needed.
|
Adding a new string to translate is as easy as adding the string in the
|
||||||
For example setting the text of this label in a way that the string "My name is:" can be translated:
|
'tr("")' function, the string will be picked up as translatable automatically
|
||||||
|
and translated as needed.
|
||||||
|
For example, setting the text of a label in the way that the string
|
||||||
|
`"My name is:"` can be translated:
|
||||||
```c++
|
```c++
|
||||||
nameLabel.setText(tr("My name is:"));
|
nameLabel.setText(tr("My name is:"));
|
||||||
```
|
```
|
||||||
|
|
||||||
If you're about to propose a change that adds or modifies any translatable string in the code, you don't need to take care of adding the new strings to the translation files.
|
To translate a string that would have plural forms you can add the amount to
|
||||||
Every few days, or when a lot of new strings have been added, someone from the development team will take care of extracting all the new strings and adding them to the english translation files and making them available to translators on Transifex.
|
the tr call, also you can add an extra string as a hint for translators:
|
||||||
|
```c++
|
||||||
|
QString message = tr("Everyone draws %n cards", "pop up message", amount);
|
||||||
|
```
|
||||||
|
See [QT's wiki on translations](
|
||||||
|
https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals)
|
||||||
|
|
||||||
|
If you're about to propose a change that adds or modifies any translatable
|
||||||
|
string in the code, you don't need to take care of adding the new strings to
|
||||||
|
the translation files.
|
||||||
|
Every few days, or when a lot of new strings have been added, someone from the
|
||||||
|
development team will take care of extracting all the new strings and adding
|
||||||
|
them to the english translation files and making them available to translators
|
||||||
|
on Transifex.
|
||||||
|
|
||||||
### Maintaining Translations (for maintainers) ###
|
### Maintaining Translations (for maintainers) ###
|
||||||
|
|
||||||
|
|
@ -253,8 +359,9 @@ cmake .. -DUPDATE_TRANSLATIONS=OFF
|
||||||
```
|
```
|
||||||
Now you are ready to propose your change.
|
Now you are ready to propose your change.
|
||||||
|
|
||||||
Once your change gets merged, Transifex will pick up the modified files automatically (checked every 24 hours)
|
Once your change gets merged, Transifex will pick up the modified files
|
||||||
and update the interface where translators will be able to translate the new strings.
|
automatically (checked every 24 hours) and update the interface where
|
||||||
|
translators will be able to translate the new strings.
|
||||||
|
|
||||||
### Releasing Translations (for maintainers) ###
|
### Releasing Translations (for maintainers) ###
|
||||||
|
|
||||||
|
|
@ -272,51 +379,85 @@ from Transifex to the source code and vice versa.
|
||||||
|
|
||||||
### Adding Translations (for translators) ###
|
### Adding Translations (for translators) ###
|
||||||
|
|
||||||
As a translator you can help translate the new strings on [Transifex](https://www.transifex.com/projects/p/cockatrice/).
|
As a translator you can help translate the new strings on [Transifex](
|
||||||
Please have a look at the specific [FAQ for translators](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
|
https://www.transifex.com/projects/p/cockatrice/).
|
||||||
|
Please have a look at the specific [FAQ for translators](
|
||||||
|
https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ).
|
||||||
|
|
||||||
|
|
||||||
# Release Management #
|
# Release Management #
|
||||||
|
|
||||||
### Publishing A New Beta Release ###
|
### Publishing A New Release ###
|
||||||
|
|
||||||
Travis and AppVeyor have been configured to upload files to GitHub Releases whenever a <kbd>tag</kbd> is pushed.<br>
|
We use [GitHub Releases](https://github.com/Cockatrice/Cockatrice/releases) to
|
||||||
Usually, tags are created through publishing a (pre-)release, but there's a way around that.
|
publish new stable versions and betas.
|
||||||
|
Whenever a git tag is pushed to the repository github will create a draft
|
||||||
|
release and upload binaries automatically.
|
||||||
|
|
||||||
To trigger Travis and AppVeyor, simply do the following:
|
To create a tag, simply do the following:
|
||||||
```bash
|
```bash
|
||||||
cd $COCKATRICE_REPO
|
|
||||||
git checkout master
|
git checkout master
|
||||||
git remote update -p
|
git remote update -p
|
||||||
git pull
|
git pull
|
||||||
git tag $TAG_NAME
|
git tag $TAG_NAME
|
||||||
git push upstream $TAG_NAME
|
git push $UPSTREAM $TAG_NAME
|
||||||
```
|
```
|
||||||
|
|
||||||
You should define the variables as such:
|
You should define the variables as such:
|
||||||
```
|
```
|
||||||
upstream - git@github.com:Cockatrice/Cockatrice.git
|
`$UPSTREAM` - the remote for git@github.com:Cockatrice/Cockatrice.git
|
||||||
$COCKATRICE_REPO - /Location/of/repository/cockatrice.git
|
`$TAG_NAME` should be formatted as:
|
||||||
`$TAG_NAME` should be:
|
|
||||||
- `YYYY-MM-DD-Release-MAJ.MIN.PATCH` for **stable releases**
|
- `YYYY-MM-DD-Release-MAJ.MIN.PATCH` for **stable releases**
|
||||||
- `YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X` for **beta releases**<br>
|
- `YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X` for **beta releases**<br>
|
||||||
With *MAJ.MIN.PATCH* being the NEXT release version!
|
With *MAJ.MIN.PATCH* being the NEXT release version!
|
||||||
```
|
```
|
||||||
|
|
||||||
This will cause a tagged release to be established on the GitHub repository, which will then lead to the upload of binaries. If you use this method, the tags (releases) that you create will be marked as a "Pre-release". The `/latest` URL will not be impacted (for stable release downloads) so that's good.
|
This will cause a tagged release to be established on the GitHub repository,
|
||||||
|
with the binaries being added to the release whenever they are ready.
|
||||||
|
The release is initially a draft, where the path notes can be edited and after
|
||||||
|
all is good and ready it can be published on GitHub.
|
||||||
|
If you use a SemVer tag including "beta", the release that will be created at
|
||||||
|
GitHub will be marked as a "Pre-release" automatically.
|
||||||
|
The target of the `.../latest` URL will not be changed in that case, it always
|
||||||
|
points to the latest stable release and not pre-releases/betas.
|
||||||
|
|
||||||
If you accidentally push a tag incorrectly (the tag is outdated, you didn't pull in the latest branch accidentally, you named the tag wrong, etc.) you can revoke the tag by doing the following:
|
If you accidentally push a tag incorrectly (the tag is outdated, you didn't
|
||||||
|
pull in the latest branch accidentally, you named the tag wrong, etc.) you can
|
||||||
|
revoke the tag by doing the following:
|
||||||
```bash
|
```bash
|
||||||
git push --delete upstream $TAG_NAME
|
git push --delete upstream $TAG_NAME
|
||||||
git tag -d $TAG_NAME
|
git tag -d $TAG_NAME
|
||||||
```
|
```
|
||||||
|
You can also do this on GitHub, you'll also want to delete the new release.
|
||||||
|
|
||||||
**NOTE:** Unfortunately, due to the method of how Travis and AppVeyor work, to publish a stable release you will need to make a copy of the release notes locally and then paste them into the GitHub GUI once the binaries have been uploaded by them. These CI services will automatically overwrite the name of the release (to "Cockatrice $TAG_NAME"), the status of the release (to "Pre-release"), and the release body (to "Beta build of Cockatrice").
|
In the first lines of [CMakeLists.txt](
|
||||||
|
https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt)
|
||||||
**NOTE 2:** In the first lines of https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt there's an hardcoded version number used when compiling custom (not tagged) versions. While on tagged versions these numbers are overridden by the version numbers coming from the tag title, it's good practice to keep them aligned with the real ones.
|
there's an hardcoded version number and pretty name used when compiling from
|
||||||
|
master or custom (not tagged) versions.
|
||||||
|
While on tagged versions these numbers are overridden by the version numbers
|
||||||
|
coming from the tag title, it's good practice to increment the ones at CMake
|
||||||
|
after every full release to stress that master is ahead of the last stable
|
||||||
|
release.
|
||||||
The preferred flow of operation is:
|
The preferred flow of operation is:
|
||||||
* just before a release, update the version number in CMakeLists.txt to "next release version";
|
* Just before a release, make sure the version number in CMakeLists.txt is set
|
||||||
* tag the release following the previously described syntax in order to get it built by CI;
|
to the same release version you are about to tag.
|
||||||
* wait for CI to upload the binaries, double check if everything is in order
|
* This is also the time to change the pretty name in CMakeLists.txt called
|
||||||
* after the release is complete, update the version number again to "next targeted beta version", typically increasing `PROJECT_VERSION_PATCH` by one.
|
GIT_TAG_RELEASENAME and commit and push these changes.
|
||||||
|
* Tag the release following the previously described syntax in order to get it
|
||||||
|
correctly built and deployed by CI.
|
||||||
|
* Wait for the configure step to create the release and update the patch
|
||||||
|
notes.
|
||||||
|
* Check on the github actions page for build progress which should be the top
|
||||||
|
listed [here](
|
||||||
|
https://github.com/Cockatrice/Cockatrice/actions?query=event%3Apush+-branch%3Amaster
|
||||||
|
).
|
||||||
|
* When the build has been completed you can verify all uploaded files on the
|
||||||
|
release are in order and hit the publish button.
|
||||||
|
* After the release is complete, update the CMake version number again to the
|
||||||
|
next targeted beta version, typically increasing `PROJECT_VERSION_PATCH` by
|
||||||
|
one.
|
||||||
|
|
||||||
**NOTE 3:** When releasing a new stable version, all the previous beta versions should be deleted. This is needed for Cockatrice to update users of the "beta" release channel to the latest version like other users.
|
When releasing a new stable version, all previous beta releases (and tags)
|
||||||
|
should be deleted. This is needed for Cockatrice to update users of the "Beta"
|
||||||
|
release channel correctly to the latest stable version as well.
|
||||||
|
This can be done the same way as revoking tags, mentioned above.
|
||||||
|
|
|
||||||
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
26
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -7,11 +7,27 @@ assignees: ''
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
<b>System Information:</b>
|
<!-- READ THIS BEFORE POSTING
|
||||||
<!-- Go to "Help → View Debug Log" and copy all lines above the separation here! -->
|
Go to "Help → View Debug Log" in Cockatrice and copy all information at the
|
||||||
|
top (above the separation line) below "System Information" in this ticket!
|
||||||
|
If you can't start Cockatrice to access these details, make
|
||||||
|
sure to post your OS and the file name of the setup binary instead. -->
|
||||||
|
|
||||||
|
**System Information:**
|
||||||
|
|
||||||
|
|
||||||
<!-- If you can't install Cockatrice to access that information, make
|
|
||||||
sure to include your OS and the app version from the setup file here -->
|
|
||||||
_______________________________________________________________________________________
|
_______________________________________________________________________________________
|
||||||
|
|
||||||
<!-- Explain your issue in detail here! -->
|
<!-- Explain your issue in detail here! Please attach screenshots if possible. -->
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_______________________________________________________________________________________
|
||||||
|
|
||||||
|
<!-- Describe the sequence of actions needed to experience the bug -->
|
||||||
|
|
||||||
|
**Steps to reproduce:**
|
||||||
|
- Do A
|
||||||
|
- Do B
|
||||||
|
- Do C ...
|
||||||
|
|
|
||||||
4
.github/ISSUE_TEMPLATE/config.yml
vendored
4
.github/ISSUE_TEMPLATE/config.yml
vendored
|
|
@ -3,3 +3,7 @@ contact_links:
|
||||||
- name: 💬 Discord Community (Get help with server issues, e.g. Login)
|
- name: 💬 Discord Community (Get help with server issues, e.g. Login)
|
||||||
url: https://discord.gg/3Z9yzmA
|
url: https://discord.gg/3Z9yzmA
|
||||||
about: Need help with using the client? Want to find some games? Try the Discord server!
|
about: Need help with using the client? Want to find some games? Try the Discord server!
|
||||||
|
- name: 🌐 Translations (Help improve the localization of the app)
|
||||||
|
url: https://www.transifex.com/cockatrice/cockatrice/
|
||||||
|
# it is not possible to add a link to the wiki to this description
|
||||||
|
about: For more information and guidance check our Translation FAQ on our wiki!
|
||||||
|
|
|
||||||
409
.github/workflows/ci-builds.yml
vendored
Normal file
409
.github/workflows/ci-builds.yml
vendored
Normal file
|
|
@ -0,0 +1,409 @@
|
||||||
|
name: Build
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
- 'webclient/**'
|
||||||
|
tags:
|
||||||
|
- '*'
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
- 'webclient/**'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
configure:
|
||||||
|
name: Configure
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
outputs:
|
||||||
|
tag: ${{steps.configure.outputs.tag}}
|
||||||
|
sha: ${{steps.configure.outputs.sha}}
|
||||||
|
upload_url: ${{steps.create_release.outputs.upload_url}}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Cancel previous runs
|
||||||
|
uses: styfle/cancel-workflow-action@0.6.0
|
||||||
|
with:
|
||||||
|
access_token: ${{github.token}} # needs other token https://github.com/styfle/cancel-workflow-action/issues/7
|
||||||
|
|
||||||
|
- name: Configure
|
||||||
|
id: configure
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
tag_regex='^refs/tags/'
|
||||||
|
if [[ $GITHUB_EVENT_NAME == pull-request ]]; then # pull request
|
||||||
|
sha="${{github.event.pull_request.head.sha}}"
|
||||||
|
elif [[ $GITHUB_REF =~ $tag_regex ]]; then # release
|
||||||
|
sha="$GITHUB_SHA"
|
||||||
|
tag="${GITHUB_REF/refs\/tags\//}"
|
||||||
|
echo "::set-output name=tag::$tag"
|
||||||
|
else # push to branch
|
||||||
|
sha="$GITHUB_SHA"
|
||||||
|
fi
|
||||||
|
echo "::set-output name=sha::$sha"
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
if: steps.configure.outputs.tag != null
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Prepare release paramaters
|
||||||
|
id: prepare
|
||||||
|
if: steps.configure.outputs.tag != null
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
TAG: ${{steps.configure.outputs.tag}}
|
||||||
|
run: .ci/prep_release.sh
|
||||||
|
|
||||||
|
- name: Create release
|
||||||
|
if: steps.configure.outputs.tag != null
|
||||||
|
id: create_release
|
||||||
|
uses: actions/create-release@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{github.token}}
|
||||||
|
with:
|
||||||
|
tag_name: ${{github.ref}}
|
||||||
|
release_name: ${{steps.prepare.outputs.title}}
|
||||||
|
body_path: ${{steps.prepare.outputs.body_path}}
|
||||||
|
draft: true
|
||||||
|
prerelease: ${{steps.prepare.outputs.is_beta == 'yes'}}
|
||||||
|
|
||||||
|
build-linux:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# these names correspond to the files in .ci/$distro
|
||||||
|
include:
|
||||||
|
- distro: UbuntuHirsute
|
||||||
|
package: DEB
|
||||||
|
|
||||||
|
- distro: UbuntuGroovy
|
||||||
|
package: DEB
|
||||||
|
test: skip
|
||||||
|
|
||||||
|
- distro: UbuntuFocal
|
||||||
|
package: DEB
|
||||||
|
test: skip # UbuntuFocal has a broken qt for debug builds
|
||||||
|
|
||||||
|
- distro: UbuntuBionic
|
||||||
|
package: DEB
|
||||||
|
|
||||||
|
- distro: ArchLinux
|
||||||
|
package: skip # we are packaged in arch already
|
||||||
|
allow-failure: yes
|
||||||
|
|
||||||
|
- distro: DebianBuster
|
||||||
|
package: DEB
|
||||||
|
|
||||||
|
- distro: Fedora33
|
||||||
|
package: RPM
|
||||||
|
test: skip # Fedora is our slowest build
|
||||||
|
|
||||||
|
- distro: Fedora34
|
||||||
|
package: RPM
|
||||||
|
test: skip # gtest does not compile for some reason
|
||||||
|
|
||||||
|
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?
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Get cache timestamp
|
||||||
|
id: cache_timestamp
|
||||||
|
shell: bash
|
||||||
|
run: echo "::set-output name=timestamp::$(date -u '+%Y%m%d%H%M%S')"
|
||||||
|
|
||||||
|
- name: Restore cache
|
||||||
|
uses: actions/cache@v2
|
||||||
|
env:
|
||||||
|
timestamp: ${{steps.cache_timestamp.outputs.timestamp}}
|
||||||
|
with:
|
||||||
|
path: ${{env.CACHE}}
|
||||||
|
key: docker-${{matrix.distro}}-cache-${{env.timestamp}}
|
||||||
|
restore-keys: |
|
||||||
|
docker-${{matrix.distro}}-cache-
|
||||||
|
|
||||||
|
- name: Build ${{matrix.distro}} Docker image
|
||||||
|
shell: bash
|
||||||
|
run: source .ci/docker.sh --build
|
||||||
|
|
||||||
|
- name: Build debug and test
|
||||||
|
if: matrix.test != 'skip'
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
source .ci/docker.sh
|
||||||
|
RUN --server --debug --test
|
||||||
|
|
||||||
|
- name: Build release package
|
||||||
|
id: package
|
||||||
|
if: matrix.package != 'skip'
|
||||||
|
shell: bash
|
||||||
|
env:
|
||||||
|
suffix: '-${{matrix.distro}}'
|
||||||
|
type: '${{matrix.package}}'
|
||||||
|
run: |
|
||||||
|
source .ci/docker.sh
|
||||||
|
RUN --server --release --package "$type" --suffix "$suffix"
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
if: matrix.package != 'skip'
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: ${{matrix.distro}}-package
|
||||||
|
path: ./build/${{steps.package.outputs.name}}
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Upload to release
|
||||||
|
if: matrix.package != 'skip' && needs.configure.outputs.tag != null
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{github.token}}
|
||||||
|
with:
|
||||||
|
upload_url: ${{needs.configure.outputs.upload_url}}
|
||||||
|
asset_path: ./build/${{steps.package.outputs.name}}
|
||||||
|
asset_name: ${{steps.package.outputs.name}}
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
|
|
||||||
|
build-macos:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
target:
|
||||||
|
- Debug
|
||||||
|
- 10.14_Mojave
|
||||||
|
- 10.15_Catalina
|
||||||
|
- 11.0_Big_Sur
|
||||||
|
include:
|
||||||
|
- target: Debug # tests only
|
||||||
|
os: macos-latest
|
||||||
|
xcode: 11.7
|
||||||
|
type: Debug
|
||||||
|
do_tests: 0 # tests do not work yet on mac
|
||||||
|
make_package: false
|
||||||
|
|
||||||
|
- target: 10.14_Mojave
|
||||||
|
os: macos-10.15 # runs on Catalina
|
||||||
|
xcode: 10.3 # allows compatibility with macos 10.14
|
||||||
|
type: Release
|
||||||
|
do_tests: 0
|
||||||
|
make_package: true
|
||||||
|
|
||||||
|
- target: 10.15_Catalina
|
||||||
|
os: macos-10.15
|
||||||
|
xcode: 11.7
|
||||||
|
type: Release
|
||||||
|
do_tests: 0
|
||||||
|
make_package: true
|
||||||
|
|
||||||
|
- target: 11.0_Big_Sur
|
||||||
|
os: macos-11.0
|
||||||
|
xcode: 12.2
|
||||||
|
type: Release
|
||||||
|
do_tests: 0
|
||||||
|
make_package: true
|
||||||
|
|
||||||
|
name: macOS ${{matrix.target}}
|
||||||
|
|
||||||
|
needs: configure
|
||||||
|
|
||||||
|
runs-on: ${{matrix.os}}
|
||||||
|
|
||||||
|
continue-on-error: ${{matrix.allow-failure == 'yes'}}
|
||||||
|
|
||||||
|
env:
|
||||||
|
CCACHE_DIR: ~/.ccache
|
||||||
|
DEVELOPER_DIR:
|
||||||
|
/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Install dependencies using homebrew
|
||||||
|
shell: bash
|
||||||
|
# cmake cannot find the mysql connector
|
||||||
|
# neither of these works: mariadb-connector-c mysql-connector-c++
|
||||||
|
run: brew install ccache 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
|
||||||
|
|
||||||
|
- name: Get ccache timestamp
|
||||||
|
id: ccache_timestamp
|
||||||
|
shell: bash
|
||||||
|
run: echo "::set-output name=timestamp::$(date -u '+%Y%m%d%H%M%S')"
|
||||||
|
|
||||||
|
- name: Restore ccache cache
|
||||||
|
uses: actions/cache@v2
|
||||||
|
env:
|
||||||
|
timestamp: ${{steps.ccache_timestamp.outputs.timestamp}}
|
||||||
|
with:
|
||||||
|
path: ${{env.CCACHE_DIR}}
|
||||||
|
key: ${{runner.os}}-xcode-${{matrix.xcode}}-ccache-${{env.timestamp}}
|
||||||
|
restore-keys: |
|
||||||
|
${{runner.os}}-xcode-${{matrix.xcode}}-ccache-
|
||||||
|
|
||||||
|
- name: Build on Xcode ${{matrix.xcode}}
|
||||||
|
shell: bash
|
||||||
|
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}}"
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
if: matrix.make_package
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: macOS-${{matrix.target}}-xcode-${{matrix.xcode}}-dmg
|
||||||
|
path: ${{steps.package.outputs.path}}
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Upload to release
|
||||||
|
if: matrix.make_package && needs.configure.outputs.tag != null
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
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_content_type: application/octet-stream
|
||||||
|
|
||||||
|
build-windows:
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
arch:
|
||||||
|
- 64
|
||||||
|
- 32
|
||||||
|
include:
|
||||||
|
- arch: 64
|
||||||
|
triplet: x64
|
||||||
|
cmake: x64
|
||||||
|
append: _64
|
||||||
|
|
||||||
|
- arch: 32
|
||||||
|
triplet: x86
|
||||||
|
cmake: Win32
|
||||||
|
|
||||||
|
name: Windows ${{matrix.arch}}
|
||||||
|
|
||||||
|
needs: configure
|
||||||
|
|
||||||
|
runs-on: windows-latest
|
||||||
|
|
||||||
|
env:
|
||||||
|
QT_VERSION: '5.12.9'
|
||||||
|
QT_ARCH: msvc2017${{matrix.append}}
|
||||||
|
CMAKE_GENERATOR: 'Visual Studio 16 2019'
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Add msbuild to PATH
|
||||||
|
id: add-msbuild
|
||||||
|
uses: microsoft/setup-msbuild@v1.0.2
|
||||||
|
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
submodules: recursive
|
||||||
|
|
||||||
|
- name: Restore Qt ${{env.QT_VERSION}} ${{matrix.arch}}-bit from cache
|
||||||
|
id: cache-qt
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
key: ${{runner.os}}-QtCache-${{env.QT_VERSION}}-${{matrix.arch}}
|
||||||
|
path: ${{runner.workspace}}/Qt
|
||||||
|
|
||||||
|
- name: Install ${{matrix.arch}}-bit Qt
|
||||||
|
uses: jurplel/install-qt-action@v2
|
||||||
|
with:
|
||||||
|
cached: ${{steps.cache-qt.outputs.cache-hit}}
|
||||||
|
version: ${{env.QT_VERSION}}
|
||||||
|
arch: win${{matrix.arch}}_${{env.QT_ARCH}}
|
||||||
|
|
||||||
|
- name: Restore or setup vcpkg
|
||||||
|
uses: lukka/run-vcpkg@v6
|
||||||
|
with:
|
||||||
|
vcpkgArguments: '@${{github.workspace}}/vcpkg.txt'
|
||||||
|
vcpkgDirectory: ${{github.workspace}}/vcpkg
|
||||||
|
appendedCacheKey: ${{hashFiles('**/vcpkg.txt')}}
|
||||||
|
vcpkgTriplet: ${{matrix.triplet}}-windows
|
||||||
|
|
||||||
|
- name: Configure Cockatrice ${{matrix.arch}}-bit
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
export QTDIR="${{runner.workspace}}/Qt/$QT_VERSION/$QT_ARCH"
|
||||||
|
cmake .. -G "${{env.CMAKE_GENERATOR}}" -A "${{matrix.cmake}}" -DCMAKE_BUILD_TYPE="Release" -DWITH_SERVER=1 -DTEST=1
|
||||||
|
|
||||||
|
- name: Build Cockatrice ${{matrix.arch}}-bit
|
||||||
|
id: package
|
||||||
|
shell: bash
|
||||||
|
working-directory: build
|
||||||
|
run: |
|
||||||
|
cmake --build . --target package --config Release
|
||||||
|
../.ci/name_build.sh "-win${{matrix.arch}}"
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
shell: bash
|
||||||
|
working-directory: build
|
||||||
|
run: ctest -T Test -C Release
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-artifact@v2
|
||||||
|
with:
|
||||||
|
name: Windows-${{matrix.arch}}bit-installer
|
||||||
|
path: ./build/${{steps.package.outputs.name}}
|
||||||
|
if-no-files-found: error
|
||||||
|
|
||||||
|
- name: Upload to release
|
||||||
|
if: needs.configure.outputs.tag != null
|
||||||
|
uses: actions/upload-release-asset@v1
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{github.token}}
|
||||||
|
with:
|
||||||
|
upload_url: ${{needs.configure.outputs.upload_url}}
|
||||||
|
asset_path: ./build/${{steps.package.outputs.name}}
|
||||||
|
asset_name: ${{steps.package.outputs.name}}
|
||||||
|
asset_content_type: application/octet-stream
|
||||||
28
.github/workflows/clangify.yml
vendored
Normal file
28
.github/workflows/clangify.yml
vendored
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
name: Clangify
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches:
|
||||||
|
- master
|
||||||
|
paths-ignore:
|
||||||
|
- '**.md'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
linter:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 20 # should be enough to find merge base
|
||||||
|
|
||||||
|
- name: Install clang-format
|
||||||
|
shell: bash
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y --no-install-recommends clang-format
|
||||||
|
|
||||||
|
- name: Run clangify
|
||||||
|
shell: bash
|
||||||
|
run: ./.ci/lint.sh
|
||||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
[submodule "vcpkg"]
|
||||||
|
path = vcpkg
|
||||||
|
url = https://github.com/microsoft/vcpkg.git
|
||||||
276
.travis.yml
276
.travis.yml
|
|
@ -1,276 +0,0 @@
|
||||||
os: linux
|
|
||||||
dist: bionic
|
|
||||||
language: cpp
|
|
||||||
compiler: gcc
|
|
||||||
|
|
||||||
git:
|
|
||||||
depth: 15
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
include:
|
|
||||||
|
|
||||||
#Static Code Analysis
|
|
||||||
- name: Check code style / Linting
|
|
||||||
if: tag IS NOT present
|
|
||||||
os: linux
|
|
||||||
group: stable
|
|
||||||
script: bash ./.ci/travis-lint.sh
|
|
||||||
|
|
||||||
|
|
||||||
#Ubuntu Bionic (on Docker)
|
|
||||||
- name: Ubuntu Bionic (Debug + Tests)
|
|
||||||
if: tag IS NOT present
|
|
||||||
os: linux
|
|
||||||
services: docker
|
|
||||||
language: minimal
|
|
||||||
env: NAME=UbuntuBionic CACHE=$HOME/$NAME
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $CACHE
|
|
||||||
before_install: source .ci/travis-docker.sh --build
|
|
||||||
script: RUN --server --debug --test
|
|
||||||
|
|
||||||
- name: Ubuntu Bionic (Release)
|
|
||||||
if: (branch = master AND NOT type = pull_request) OR tag IS present
|
|
||||||
os: linux
|
|
||||||
services: docker
|
|
||||||
language: minimal
|
|
||||||
env: NAME=UbuntuBionic CACHE=$HOME/$NAME
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $CACHE
|
|
||||||
before_install: source .ci/travis-docker.sh --build
|
|
||||||
script: RUN --server --package $NAME --release
|
|
||||||
|
|
||||||
#Ubuntu Focal (on Docker)
|
|
||||||
- name: Ubuntu Focal (Compile)
|
|
||||||
if: tag IS NOT present
|
|
||||||
os: linux
|
|
||||||
services: docker
|
|
||||||
language: minimal
|
|
||||||
env: NAME=UbuntuFocal CACHE=$HOME/$NAME
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $CACHE
|
|
||||||
before_install: source .ci/travis-docker.sh --build
|
|
||||||
script: RUN --server
|
|
||||||
|
|
||||||
- name: Ubuntu Focal (Release)
|
|
||||||
if: (branch = master AND NOT type = pull_request) OR tag IS present
|
|
||||||
os: linux
|
|
||||||
services: docker
|
|
||||||
language: minimal
|
|
||||||
env: NAME=UbuntuFocal CACHE=$HOME/$NAME
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $CACHE
|
|
||||||
before_install: source .ci/travis-docker.sh --build
|
|
||||||
script: RUN --server --package $NAME --release
|
|
||||||
|
|
||||||
#Debian Buster (on Docker)
|
|
||||||
- name: Debian Buster (Compile)
|
|
||||||
if: tag IS NOT present
|
|
||||||
os: linux
|
|
||||||
services: docker
|
|
||||||
language: minimal
|
|
||||||
env: NAME=DebianBuster CACHE=$HOME/$NAME
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $CACHE
|
|
||||||
before_install: source .ci/travis-docker.sh --build
|
|
||||||
script: RUN --server
|
|
||||||
|
|
||||||
- name: Debian Buster (Release)
|
|
||||||
if: (branch = master AND NOT type = pull_request) OR tag IS present
|
|
||||||
os: linux
|
|
||||||
services: docker
|
|
||||||
language: minimal
|
|
||||||
env: NAME=DebianBuster CACHE=$HOME/$NAME
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $CACHE
|
|
||||||
before_install: source .ci/travis-docker.sh --build
|
|
||||||
script: RUN --server --package $NAME --release
|
|
||||||
|
|
||||||
|
|
||||||
#Fedora 32 (on Docker)
|
|
||||||
- name: Fedora 32 (Compile)
|
|
||||||
if: tag IS NOT present
|
|
||||||
services: docker
|
|
||||||
language: minimal
|
|
||||||
env: NAME=Fedora32 CACHE=$HOME/$NAME
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $CACHE
|
|
||||||
before_install: source .ci/travis-docker.sh --build
|
|
||||||
script: RUN --server
|
|
||||||
|
|
||||||
- name: Fedora 32 (Release)
|
|
||||||
if: (branch = master AND NOT type = pull_request) OR tag IS present
|
|
||||||
services: docker
|
|
||||||
language: minimal
|
|
||||||
env: NAME=Fedora32 CACHE=$HOME/$NAME
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $CACHE
|
|
||||||
before_install: source .ci/travis-docker.sh --build
|
|
||||||
script: RUN --server --package $NAME RPM --release
|
|
||||||
|
|
||||||
|
|
||||||
#macOS High Sierra
|
|
||||||
- name: macOS High Sierra (Debug)
|
|
||||||
if: tag IS NOT present
|
|
||||||
os: osx
|
|
||||||
osx_image: xcode10.1
|
|
||||||
cache:
|
|
||||||
- ccache
|
|
||||||
- directories:
|
|
||||||
- $HOME/Library/Caches/Homebrew
|
|
||||||
addons:
|
|
||||||
homebrew:
|
|
||||||
packages:
|
|
||||||
- ccache
|
|
||||||
- protobuf
|
|
||||||
- qt
|
|
||||||
- xz
|
|
||||||
update: true
|
|
||||||
script: bash ./.ci/travis-compile.sh --server --install --debug
|
|
||||||
before_cache:
|
|
||||||
- brew cleanup
|
|
||||||
|
|
||||||
- name: macOS High Sierra (Release)
|
|
||||||
if: (branch = master AND NOT type = pull_request) OR tag IS present
|
|
||||||
os: osx
|
|
||||||
osx_image: xcode10.1
|
|
||||||
env: OSX_VERSION=10.13
|
|
||||||
cache:
|
|
||||||
- ccache
|
|
||||||
- directories:
|
|
||||||
- $HOME/Library/Caches/Homebrew
|
|
||||||
addons:
|
|
||||||
homebrew:
|
|
||||||
packages:
|
|
||||||
- ccache
|
|
||||||
- protobuf
|
|
||||||
- qt
|
|
||||||
- xz
|
|
||||||
update: true
|
|
||||||
script: bash ./.ci/travis-compile.sh --server --package "macos$OSX_VERSION" --release
|
|
||||||
before_cache:
|
|
||||||
- brew cleanup
|
|
||||||
|
|
||||||
#macOS Catalina
|
|
||||||
- name: macOS Catalina (Debug)
|
|
||||||
if: tag IS NOT present
|
|
||||||
os: osx
|
|
||||||
osx_image: xcode11.6
|
|
||||||
cache:
|
|
||||||
- ccache
|
|
||||||
- directories:
|
|
||||||
- $HOME/Library/Caches/Homebrew
|
|
||||||
addons:
|
|
||||||
homebrew:
|
|
||||||
packages:
|
|
||||||
- ccache
|
|
||||||
- protobuf
|
|
||||||
- qt
|
|
||||||
- xz
|
|
||||||
update: true
|
|
||||||
script: bash ./.ci/travis-compile.sh --server --install --debug
|
|
||||||
before_cache:
|
|
||||||
- brew cleanup
|
|
||||||
|
|
||||||
- name: macOS Catalina (Release)
|
|
||||||
if: (branch = master AND NOT type = pull_request) OR tag IS present
|
|
||||||
os: osx
|
|
||||||
osx_image: xcode11.6
|
|
||||||
env: OSX_VERSION=10.15
|
|
||||||
cache:
|
|
||||||
- ccache
|
|
||||||
- directories:
|
|
||||||
- $HOME/Library/Caches/Homebrew
|
|
||||||
addons:
|
|
||||||
homebrew:
|
|
||||||
packages:
|
|
||||||
- ccache
|
|
||||||
- protobuf
|
|
||||||
- qt
|
|
||||||
- xz
|
|
||||||
update: true
|
|
||||||
script: bash ./.ci/travis-compile.sh --server --package "macos$OSX_VERSION" --release --zip
|
|
||||||
before_cache:
|
|
||||||
- brew cleanup
|
|
||||||
|
|
||||||
|
|
||||||
#Arch Linux (on Docker) (allow failures)
|
|
||||||
- name: Arch Linux (Debug)
|
|
||||||
if: tag IS NOT present
|
|
||||||
os: linux
|
|
||||||
services: docker
|
|
||||||
language: minimal
|
|
||||||
env: NAME=ArchLinux CACHE=$HOME/$NAME
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $CACHE
|
|
||||||
before_install: source .ci/travis-docker.sh --build
|
|
||||||
script: RUN --server --debug
|
|
||||||
|
|
||||||
allow_failures:
|
|
||||||
# Arch linux is always the latest version and by definition not stable
|
|
||||||
- name: Arch Linux (Debug)
|
|
||||||
# Report build completion even if optional builds are not completed
|
|
||||||
fast_finish: true
|
|
||||||
|
|
||||||
|
|
||||||
# Builds for pull requests skip the deployment step altogether
|
|
||||||
deploy:
|
|
||||||
# Deploy configuration for "beta" releases
|
|
||||||
- provider: releases
|
|
||||||
token:
|
|
||||||
secure: mLMF41q7xgOR1sjczsilEy7HQis2PkZCzhfOGbn/8FoOQnmmPOZjrsdhn06ZSl3SFsbfCLuClDYXAbFscQmdgjcGN5AmHV+JYfW650QEuQa/f4/lQFsVRtEqUA1O3FQ0OuRxdpCfJubZBdFVH8SbZ93GLC5zXJbkWQNq+xCX1fU=
|
|
||||||
name: "Cockatrice $TRAVIS_TAG"
|
|
||||||
release_notes: "Beta release of Cockatrice"
|
|
||||||
skip_cleanup: true
|
|
||||||
file_glob: true
|
|
||||||
file: "build/Cockatrice-*"
|
|
||||||
overwrite: true
|
|
||||||
draft: false
|
|
||||||
prerelease: true
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
repo: Cockatrice/Cockatrice
|
|
||||||
condition: $TRAVIS_TAG =~ ([0-9]|[1-9][0-9])(\.([0-9]|[1-9][0-9])){2}-beta(\.([2-9]|[1-9][0-9]))?$ # regex to match semver naming convention for beta pre-releases
|
|
||||||
|
|
||||||
# Deploy configuration for "stable" releases
|
|
||||||
- provider: releases
|
|
||||||
token:
|
|
||||||
secure: mLMF41q7xgOR1sjczsilEy7HQis2PkZCzhfOGbn/8FoOQnmmPOZjrsdhn06ZSl3SFsbfCLuClDYXAbFscQmdgjcGN5AmHV+JYfW650QEuQa/f4/lQFsVRtEqUA1O3FQ0OuRxdpCfJubZBdFVH8SbZ93GLC5zXJbkWQNq+xCX1fU=
|
|
||||||
skip_cleanup: true
|
|
||||||
file_glob: true
|
|
||||||
file: "build/Cockatrice-*"
|
|
||||||
overwrite: true
|
|
||||||
draft: false
|
|
||||||
prerelease: false
|
|
||||||
on:
|
|
||||||
tags: true
|
|
||||||
repo: Cockatrice/Cockatrice
|
|
||||||
condition: $TRAVIS_TAG =~ ([0-9]|[1-9][0-9])(\.([0-9]|[1-9][0-9])){2}$ # regex to match semver naming convention for stable full releases
|
|
||||||
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
email: false
|
|
||||||
webhooks:
|
|
||||||
urls:
|
|
||||||
- https://webhooks.gitter.im/e/d94969c3b01b22cbdcb7
|
|
||||||
on_success: change
|
|
||||||
on_failure: change
|
|
||||||
on_start: never
|
|
||||||
on_cancel: change
|
|
||||||
on_error: change
|
|
||||||
|
|
||||||
|
|
||||||
# Announcements of build image updates: https://docs.travis-ci.com/user/build-environment-updates/
|
|
||||||
# For precise versions of preinstalled tools on the VM, check “Build system information” in the build log!
|
|
||||||
# Official validator for ".travis.yml" config file: https://yaml.travis-ci.org
|
|
||||||
# Official Travis CI Build Config Explorer: https://config.travis-ci.com/explore
|
|
||||||
# Travis CI config documentation: https://docs.travis-ci.com/user/customizing-the-build
|
|
||||||
|
|
@ -6,15 +6,7 @@
|
||||||
# like the installation path, compilation flags etc..
|
# like the installation path, compilation flags etc..
|
||||||
|
|
||||||
# Cmake 3.1 is required to enable C++11 support correctly
|
# Cmake 3.1 is required to enable C++11 support correctly
|
||||||
cmake_minimum_required(VERSION 3.1)
|
cmake_minimum_required(VERSION 3.10)
|
||||||
|
|
||||||
if(POLICY CMP0064)
|
|
||||||
cmake_policy(SET CMP0064 NEW)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(POLICY CMP0071)
|
|
||||||
cmake_policy(SET CMP0071 NEW)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Default to "Release" build type
|
# Default to "Release" build type
|
||||||
# User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call
|
# User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call
|
||||||
|
|
@ -35,9 +27,26 @@ if(USE_CCACHE)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(WIN32)
|
||||||
|
# Use vcpkg toolchain on Windows
|
||||||
|
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake
|
||||||
|
CACHE STRING "Vcpkg toolchain file")
|
||||||
|
# Qt path set by user or env var
|
||||||
|
if (QTDIR OR DEFINED ENV{QTDIR} OR DEFINED ENV{QTDIR32} OR DEFINED ENV{QTDIR64})
|
||||||
|
else()
|
||||||
|
set(QTDIR "" CACHE PATH "Path to Qt (e.g. C:/Qt/5.7/msvc2015_64)")
|
||||||
|
message(WARNING "QTDIR variable is missing. Please set this variable to specify path to Qt (e.g. C:/Qt/5.7/msvc2015_64)")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
# A project name is needed for CPack
|
# A project name is needed for CPack
|
||||||
# Version can be overriden by git tags, see cmake/getversion.cmake
|
# Version can be overriden by git tags, see cmake/getversion.cmake
|
||||||
PROJECT("Cockatrice" VERSION 2.7.6)
|
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
|
# Use c++11 for all targets
|
||||||
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ ISO Standard")
|
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ ISO Standard")
|
||||||
|
|
@ -49,7 +58,6 @@ set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
|
||||||
# Search path for cmake modules
|
# Search path for cmake modules
|
||||||
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
|
||||||
|
|
||||||
# Retrieve git version hash
|
|
||||||
include(getversion)
|
include(getversion)
|
||||||
|
|
||||||
# Create a header and a cpp file containing the version hash
|
# Create a header and a cpp file containing the version hash
|
||||||
|
|
@ -92,7 +100,7 @@ if(UNIX)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/release)
|
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/rundir/${CMAKE_BUILD_TYPE})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Treat warnings as errors (Debug builds only)
|
# Treat warnings as errors (Debug builds only)
|
||||||
|
|
@ -100,10 +108,8 @@ option(WARNING_AS_ERROR "Treat warnings as errors in debug builds" ON)
|
||||||
|
|
||||||
# Define proper compilation flags
|
# Define proper compilation flags
|
||||||
IF(MSVC)
|
IF(MSVC)
|
||||||
# Visual Studio:
|
# Visual Studio: Maximum optimization, disable warning C4251
|
||||||
# Maximum optimization
|
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251 ")
|
||||||
# Disable warning C4251
|
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251")
|
|
||||||
# Generate complete debugging information
|
# Generate complete debugging information
|
||||||
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
|
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
|
||||||
ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
|
ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
|
@ -128,7 +134,11 @@ ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
|
||||||
ELSE()
|
ELSE()
|
||||||
# other: osx/llvm, bsd/llvm
|
# other: osx/llvm, bsd/llvm
|
||||||
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
|
set(CMAKE_CXX_FLAGS_RELEASE "-O2")
|
||||||
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
|
if(WARNING_AS_ERROR)
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra -Werror")
|
||||||
|
else()
|
||||||
|
set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra")
|
||||||
|
endif()
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
# GNU systems need to define the Mersenne exponent for the RNG to compile w/o warning
|
# GNU systems need to define the Mersenne exponent for the RNG to compile w/o warning
|
||||||
|
|
@ -139,8 +149,21 @@ ENDIF()
|
||||||
FIND_PACKAGE(Threads REQUIRED)
|
FIND_PACKAGE(Threads REQUIRED)
|
||||||
|
|
||||||
# Find Qt5
|
# Find Qt5
|
||||||
OPTION(UPDATE_TRANSLATIONS "Update translations on compile" OFF)
|
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}")
|
set(_lib_suffix 64)
|
||||||
|
else()
|
||||||
|
set(_lib_suffix 32)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(DEFINED QTDIR${_lib_suffix})
|
||||||
|
list(APPEND CMAKE_PREFIX_PATH "${QTDIR${_lib_suffix}}")
|
||||||
|
elseif(DEFINED QTDIR)
|
||||||
|
list(APPEND CMAKE_PREFIX_PATH "${QTDIR}")
|
||||||
|
elseif(DEFINED ENV{QTDIR${_lib_suffix}})
|
||||||
|
list(APPEND CMAKE_PREFIX_PATH "$ENV{QTDIR${_lib_suffix}}")
|
||||||
|
elseif(DEFINED ENV{QTDIR})
|
||||||
|
list(APPEND CMAKE_PREFIX_PATH "$ENV{QTDIR}")
|
||||||
|
endif()
|
||||||
|
|
||||||
FIND_PACKAGE(Qt5Core 5.5.0 REQUIRED)
|
FIND_PACKAGE(Qt5Core 5.5.0 REQUIRED)
|
||||||
|
|
||||||
|
|
@ -161,12 +184,18 @@ ELSE()
|
||||||
MESSAGE(FATAL_ERROR "No Qt5 found!")
|
MESSAGE(FATAL_ERROR "No Qt5 found!")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
|
# Check for translation updates
|
||||||
|
OPTION(UPDATE_TRANSLATIONS "Update translations on compile" OFF)
|
||||||
|
MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}")
|
||||||
|
|
||||||
set(CMAKE_AUTOMOC TRUE)
|
set(CMAKE_AUTOMOC TRUE)
|
||||||
|
|
||||||
# Find other needed libraries
|
# Find other needed libraries
|
||||||
FIND_PACKAGE(Protobuf REQUIRED)
|
FIND_PACKAGE(Protobuf REQUIRED)
|
||||||
IF(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
|
IF(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
|
||||||
MESSAGE(FATAL_ERROR "No protoc command found!")
|
MESSAGE(FATAL_ERROR "No protoc command found!")
|
||||||
|
ELSE()
|
||||||
|
MESSAGE(STATUS "Protoc version ${Protobuf_VERSION} found!")
|
||||||
ENDIF()
|
ENDIF()
|
||||||
|
|
||||||
#Find OpenSSL
|
#Find OpenSSL
|
||||||
|
|
@ -215,7 +244,7 @@ if(UNIX)
|
||||||
endif()
|
endif()
|
||||||
elseif(WIN32)
|
elseif(WIN32)
|
||||||
set(CPACK_GENERATOR NSIS ${CPACK_GENERATOR})
|
set(CPACK_GENERATOR NSIS ${CPACK_GENERATOR})
|
||||||
if("${CMAKE_GENERATOR}" MATCHES "(Win64|IA64)")
|
if("${CMAKE_GENERATOR_PLATFORM}" MATCHES "(x64)")
|
||||||
set(TRICE_IS_64_BIT 1)
|
set(TRICE_IS_64_BIT 1)
|
||||||
else()
|
else()
|
||||||
set(TRICE_IS_64_BIT 0)
|
set(TRICE_IS_64_BIT 0)
|
||||||
|
|
@ -258,7 +287,7 @@ if(WITH_ORACLE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Compile dbconverter (default on)
|
# Compile dbconverter (default on)
|
||||||
option(WITH_DBCONVERTER "build oracle" ON)
|
option(WITH_DBCONVERTER "build dbconverter" ON)
|
||||||
if(WITH_DBCONVERTER)
|
if(WITH_DBCONVERTER)
|
||||||
add_subdirectory(dbconverter)
|
add_subdirectory(dbconverter)
|
||||||
SET(CPACK_INSTALL_CMAKE_PROJECTS "Dbconverter;Dbconverter;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
|
SET(CPACK_INSTALL_CMAKE_PROJECTS "Dbconverter;Dbconverter;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
|
||||||
|
|
|
||||||
28
README.md
28
README.md
|
|
@ -5,10 +5,10 @@
|
||||||
<p align='center'>
|
<p align='center'>
|
||||||
<a href="#cockatrice"><b>Cockatrice</b></a> <b>|</b>
|
<a href="#cockatrice"><b>Cockatrice</b></a> <b>|</b>
|
||||||
<a href="#download-">Download</a> <b>|</b>
|
<a href="#download-">Download</a> <b>|</b>
|
||||||
<a href="#get-involved-">Get Involved</a> <b>|</b>
|
<a href="#get-involved--">Get Involved</a> <b>|</b>
|
||||||
<a href="#community-resources">Community</a> <b>|</b>
|
<a href="#community-resources">Community</a> <b>|</b>
|
||||||
<a href="#translations-">Translations</a> <b>|</b>
|
<a href="#translations-">Translations</a> <b>|</b>
|
||||||
<a href="#build---">Build</a> <b>|</b>
|
<a href="#build-">Build</a> <b>|</b>
|
||||||
<a href="#run">Run</a> <b>|</b>
|
<a href="#run">Run</a> <b>|</b>
|
||||||
<a href="#license-">License</a>
|
<a href="#license-">License</a>
|
||||||
</p>
|
</p>
|
||||||
|
|
@ -29,21 +29,21 @@ Cockatrice is an open-source, multiplatform program for playing tabletop card ga
|
||||||
|
|
||||||
# Download [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)
|
# Download [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)
|
||||||
|
|
||||||
Downloads are available for full releases and the current beta version in development.<br>
|
Downloads are available for full releases and the current beta version in development. There is no strict release schedule for either of them.
|
||||||
Full releases are checkpoints featuring major feature or UI enhancements - we recommend to use those. There is no strict schedule for new full releases.
|
|
||||||
|
|
||||||
The beta release contains the most recently added features and bugfixes, but can be unstable. They are released as we feel need.
|
- Latest `stable` release: [](https://github.com/cockatrice/cockatrice/releases/latest) [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)<br>
|
||||||
|
- Stable versions are checkpoints featuring major feature and UI enhancements.
|
||||||
- Latest `stable` release (**recommended**): [](https://github.com/cockatrice/cockatrice/releases/latest) [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)<br>
|
- **Recommended for most users!**
|
||||||
|
|
||||||
- Latest `beta` release: [](https://github.com/cockatrice/cockatrice/releases) [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)
|
- Latest `beta` release: [](https://github.com/cockatrice/cockatrice/releases) [](https://tooomm.github.io/github-release-stats/?username=Cockatrice&repository=Cockatrice)
|
||||||
- Beta versions may be unstable and contain bugs.
|
- Beta versions include the most recently added features and bugfixes, but can be unstable.
|
||||||
- To be a Cockatrice Beta Tester, use this version. Find more information [here](https://github.com/Cockatrice/Cockatrice/wiki/Release-Channels)!
|
- To be a Cockatrice Beta Tester, use this version. Find more information [here](https://github.com/Cockatrice/Cockatrice/wiki/Release-Channels)!
|
||||||
|
|
||||||
|
|
||||||
# Get Involved [](https://gitter.im/Cockatrice/Cockatrice)
|
# Get Involved [](https://discord.gg/3Z9yzmA) [](https://gitter.im/Cockatrice/Cockatrice)
|
||||||
|
|
||||||
[Chat](https://gitter.im/Cockatrice/Cockatrice) with the Cockatrice developers on Gitter. Come here to talk about the application, features, or just to hang out. For support regarding specific servers, please contact that server's admin or forum for support rather than asking here.<br>
|
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with the project or fellow users of the app. The Cockatrice developers are also available on [Gitter](https://gitter.im/Cockatrice/Cockatrice). Come here to talk about the application, features, or just to hang out.<br>
|
||||||
|
For support regarding specific servers, please contact that server's admin or forum for support rather than asking here.<br>
|
||||||
|
|
||||||
To contribute code to the project, please review [the guidelines](https://github.com/Cockatrice/Cockatrice/blob/master/.github/CONTRIBUTING.md).
|
To contribute code to the project, please review [the guidelines](https://github.com/Cockatrice/Cockatrice/blob/master/.github/CONTRIBUTING.md).
|
||||||
We maintain two tags for contributors to find issues to work on:
|
We maintain two tags for contributors to find issues to work on:
|
||||||
|
|
@ -67,7 +67,7 @@ Cockatrice uses the [Google Developer Documentation Style Guide](https://develop
|
||||||
- [reddit r/Cockatrice](https://reddit.com/r/cockatrice)
|
- [reddit r/Cockatrice](https://reddit.com/r/cockatrice)
|
||||||
|
|
||||||
|
|
||||||
# Translations [](https://www.transifex.com/projects/p/cockatrice/)
|
# Translations [](https://www.transifex.com/projects/p/cockatrice/)
|
||||||
|
|
||||||
Cockatrice uses Transifex for translations. You can help us bring Cockatrice and Oracle to your language or just edit single wordings right from within your browser by visiting our [Transifex project page](https://www.transifex.com/projects/p/cockatrice/).<br>
|
Cockatrice uses Transifex for translations. You can help us bring Cockatrice and Oracle to your language or just edit single wordings right from within your browser by visiting our [Transifex project page](https://www.transifex.com/projects/p/cockatrice/).<br>
|
||||||
|
|
||||||
|
|
@ -78,9 +78,9 @@ Cockatrice uses Transifex for translations. You can help us bring Cockatrice and
|
||||||
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about contributing!<br>
|
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about contributing!<br>
|
||||||
|
|
||||||
|
|
||||||
# Build [](https://travis-ci.org/Cockatrice/Cockatrice) [](https://ci.appveyor.com/project/ZeldaZach/cockatrice/branch/master) <!-- link to zachs appveyor not correct yet -->
|
# Build [](https://github.com/Cockatrice/Cockatrice/actions/workflows/ci-builds.yml?query=branch%3Amaster+event%3Apush)
|
||||||
|
|
||||||
**Detailed compiling instructions are on the Cockatrice wiki under [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)**
|
**Detailed compiling instructions can be found on the Cockatrice wiki under [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)**
|
||||||
|
|
||||||
Dependencies: *(for minimum requirements search our [CMake file](https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt))*
|
Dependencies: *(for minimum requirements search our [CMake file](https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt))*
|
||||||
- [Qt](https://www.qt.io/developers/)
|
- [Qt](https://www.qt.io/developers/)
|
||||||
|
|
@ -125,7 +125,6 @@ The following flags can be passed to `cmake`:
|
||||||
`Oracle` fetches card data<br>
|
`Oracle` fetches card data<br>
|
||||||
`Servatrice` is the server<br>
|
`Servatrice` is the server<br>
|
||||||
|
|
||||||
|
|
||||||
**Servatrice Docker container**
|
**Servatrice Docker container**
|
||||||
|
|
||||||
You can run an instance of Servatrice (the Cockatrice server) using [Docker](https://www.docker.com/what-docker) and the Cockatrice Dockerfile.<br>
|
You can run an instance of Servatrice (the Cockatrice server) using [Docker](https://www.docker.com/what-docker) and the Cockatrice Dockerfile.<br>
|
||||||
|
|
@ -160,6 +159,7 @@ A out of box working docker-compose file has been added to help setup in Windows
|
||||||
|
|
||||||
Docker in Windows requires additional steps in form of using Docker Desktop to allow resource sharing from the drive the volumes are mapped from, as well as potential workarounds needed to get file sharing working in Windows. This [StackOverflow discussion sheds some light on it](https://stackoverflow.com/questions/42203488/settings-to-windows-firewall-to-allow-docker-for-windows-to-share-drive)
|
Docker in Windows requires additional steps in form of using Docker Desktop to allow resource sharing from the drive the volumes are mapped from, as well as potential workarounds needed to get file sharing working in Windows. This [StackOverflow discussion sheds some light on it](https://stackoverflow.com/questions/42203488/settings-to-windows-firewall-to-allow-docker-for-windows-to-share-drive)
|
||||||
|
|
||||||
|
|
||||||
# License [](https://github.com/Cockatrice/Cockatrice/blob/master/LICENSE)
|
# License [](https://github.com/Cockatrice/Cockatrice/blob/master/LICENSE)
|
||||||
|
|
||||||
Cockatrice is free software, licensed under the [GPLv2](https://github.com/Cockatrice/Cockatrice/blob/master/LICENSE).
|
Cockatrice is free software, licensed under the [GPLv2](https://github.com/Cockatrice/Cockatrice/blob/master/LICENSE).
|
||||||
|
|
|
||||||
|
|
@ -11,14 +11,15 @@ cd "${BASH_SOURCE%/*}/" || exit 2 # could not find path, this could happen with
|
||||||
include=("common" \
|
include=("common" \
|
||||||
"cockatrice/src" \
|
"cockatrice/src" \
|
||||||
"oracle/src" \
|
"oracle/src" \
|
||||||
"servatrice/src")
|
"servatrice/src" \
|
||||||
|
"tests")
|
||||||
exclude=("servatrice/src/smtp" \
|
exclude=("servatrice/src/smtp" \
|
||||||
"common/sfmt" \
|
"common/sfmt" \
|
||||||
"common/lib" \
|
"common/lib" \
|
||||||
"oracle/src/zip" \
|
"oracle/src/zip" \
|
||||||
"oracle/src/lzma" \
|
"oracle/src/lzma" \
|
||||||
"oracle/src/qt-json")
|
"oracle/src/qt-json")
|
||||||
exts=("cpp" "h")
|
exts=("cpp" "h" "proto")
|
||||||
cf_cmd="clang-format"
|
cf_cmd="clang-format"
|
||||||
branch="origin/master"
|
branch="origin/master"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,23 +38,6 @@ function(get_commit_date)
|
||||||
set(GIT_COMMIT_DATE "${GIT_COM_DATE}" PARENT_SCOPE)
|
set(GIT_COMMIT_DATE "${GIT_COM_DATE}" PARENT_SCOPE)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(clean_release_name name)
|
|
||||||
# <title>Release Cockatrice 2.7.3: Dawn of Hope · Cockatrice/Cockatrice · GitHub</title>
|
|
||||||
# Remove prefix
|
|
||||||
STRING(REGEX REPLACE "<title>Release Cockatrice [0-9\.]+: " "" name "${name}")
|
|
||||||
# Remove suffix
|
|
||||||
STRING(REPLACE " · Cockatrice/Cockatrice · GitHub</title>" "" name "${name}")
|
|
||||||
# Remove all unwanted chars
|
|
||||||
STRING(REGEX REPLACE "[^A-Za-z0-9_ ]" "" name "${name}")
|
|
||||||
# Strip (trim) whitespaces
|
|
||||||
STRING(STRIP "${name}" name)
|
|
||||||
# Replace all spaces with underscores
|
|
||||||
STRING(REPLACE " " "_" name "${name}")
|
|
||||||
|
|
||||||
MESSAGE(STATUS "Friendly tag name: ${name}")
|
|
||||||
set(GIT_TAG_RELEASENAME "${name}" PARENT_SCOPE)
|
|
||||||
endfunction()
|
|
||||||
|
|
||||||
function(get_tag_name commit)
|
function(get_tag_name commit)
|
||||||
if(${commit} STREQUAL "unknown")
|
if(${commit} STREQUAL "unknown")
|
||||||
return()
|
return()
|
||||||
|
|
@ -163,22 +146,7 @@ function(get_tag_name commit)
|
||||||
set(PROJECT_VERSION_LABEL ${GIT_TAG_LABEL} PARENT_SCOPE)
|
set(PROJECT_VERSION_LABEL ${GIT_TAG_LABEL} PARENT_SCOPE)
|
||||||
elseif(${GIT_TAG_TYPE} STREQUAL "Release")
|
elseif(${GIT_TAG_TYPE} STREQUAL "Release")
|
||||||
set(PROJECT_VERSION_LABEL "" PARENT_SCOPE)
|
set(PROJECT_VERSION_LABEL "" PARENT_SCOPE)
|
||||||
|
# set release name from env var
|
||||||
# get version name from github
|
|
||||||
set(GIT_TAG_TEMP_FILE "${PROJECT_BINARY_DIR}/tag_informations.txt")
|
|
||||||
set(GIT_TAG_TEMP_URL "https://github.com/Cockatrice/Cockatrice/releases/tag/${GIT_TAG}")
|
|
||||||
message(STATUS "Fetching tag informations from ${GIT_TAG_TEMP_URL}")
|
|
||||||
file(REMOVE "${GIT_TAG_TEMP_FILE}")
|
|
||||||
file(DOWNLOAD "${GIT_TAG_TEMP_URL}" "${GIT_TAG_TEMP_FILE}" STATUS status LOG log INACTIVITY_TIMEOUT 30 TIMEOUT 300 SHOW_PROGRESS)
|
|
||||||
list(GET status 0 err)
|
|
||||||
list(GET status 1 msg)
|
|
||||||
if(err)
|
|
||||||
message(WARNING "Download failed with error ${msg}: ${log}")
|
|
||||||
return()
|
|
||||||
endif()
|
|
||||||
file(STRINGS "${GIT_TAG_TEMP_FILE}" GIT_TAG_RAW_RELEASENAME REGEX "<title>Release Cockatrice .*</title>" LIMIT_COUNT 1 ENCODING UTF-8)
|
|
||||||
|
|
||||||
clean_release_name("${GIT_TAG_RAW_RELEASENAME}")
|
|
||||||
set(PROJECT_VERSION_RELEASENAME "${GIT_TAG_RELEASENAME}" PARENT_SCOPE)
|
set(PROJECT_VERSION_RELEASENAME "${GIT_TAG_RELEASENAME}" PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
@ -188,9 +156,9 @@ endfunction()
|
||||||
|
|
||||||
# fallback defaults
|
# fallback defaults
|
||||||
set(GIT_COMMIT_ID "unknown")
|
set(GIT_COMMIT_ID "unknown")
|
||||||
set(GIT_COMMIT_DATE "unknown")
|
set(GIT_COMMIT_DATE "")
|
||||||
set(GIT_COMMIT_DATE_FRIENDLY "unknown")
|
set(GIT_COMMIT_DATE_FRIENDLY "")
|
||||||
set(PROJECT_VERSION_LABEL "custom(unknown)")
|
set(PROJECT_VERSION_LABEL "")
|
||||||
set(PROJECT_VERSION_RELEASENAME "")
|
set(PROJECT_VERSION_RELEASENAME "")
|
||||||
|
|
||||||
find_package(Git)
|
find_package(Git)
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ SET(cockatrice_SOURCES
|
||||||
src/dlg_forgotpasswordrequest.cpp
|
src/dlg_forgotpasswordrequest.cpp
|
||||||
src/dlg_forgotpasswordreset.cpp
|
src/dlg_forgotpasswordreset.cpp
|
||||||
src/dlg_forgotpasswordchallenge.cpp
|
src/dlg_forgotpasswordchallenge.cpp
|
||||||
|
src/dlg_manage_sets.cpp
|
||||||
src/dlg_register.cpp
|
src/dlg_register.cpp
|
||||||
src/dlg_tip_of_the_day.cpp
|
src/dlg_tip_of_the_day.cpp
|
||||||
src/tip_of_the_day.cpp
|
src/tip_of_the_day.cpp
|
||||||
|
|
@ -62,7 +63,6 @@ SET(cockatrice_SOURCES
|
||||||
src/carddragitem.cpp
|
src/carddragitem.cpp
|
||||||
src/carddatabasemodel.cpp
|
src/carddatabasemodel.cpp
|
||||||
src/setsmodel.cpp
|
src/setsmodel.cpp
|
||||||
src/window_sets.cpp
|
|
||||||
src/abstractgraphicsitem.cpp
|
src/abstractgraphicsitem.cpp
|
||||||
src/abstractcarddragitem.cpp
|
src/abstractcarddragitem.cpp
|
||||||
src/dlg_settings.cpp
|
src/dlg_settings.cpp
|
||||||
|
|
@ -79,7 +79,7 @@ SET(cockatrice_SOURCES
|
||||||
src/tab_replays.cpp
|
src/tab_replays.cpp
|
||||||
src/tab_supervisor.cpp
|
src/tab_supervisor.cpp
|
||||||
src/tab_admin.cpp
|
src/tab_admin.cpp
|
||||||
src/tab_userlists.cpp
|
src/tab_account.cpp
|
||||||
src/tab_deck_editor.cpp
|
src/tab_deck_editor.cpp
|
||||||
src/tab_logs.cpp
|
src/tab_logs.cpp
|
||||||
src/replay_timeline_widget.cpp
|
src/replay_timeline_widget.cpp
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,7 @@ The search bar recognizes a set of special commands similar to some other card d
|
||||||
<dd>[e:lea,leb](#e:lea,leb) <small>(Cards that appear in Alpha or Beta)</small></dd>
|
<dd>[e:lea,leb](#e:lea,leb) <small>(Cards that appear in Alpha or Beta)</small></dd>
|
||||||
<dd><a href="#e:lea,leb -(e:lea e:leb)">e:lea,leb -(e:lea e:leb)</a> <small>(Cards that appear in Alpha or Beta but not in both editions)</small></dd>
|
<dd><a href="#e:lea,leb -(e:lea e:leb)">e:lea,leb -(e:lea e:leb)</a> <small>(Cards that appear in Alpha or Beta but not in both editions)</small></dd>
|
||||||
|
|
||||||
<dt>Inverse:</dt>
|
<dt>Negate:</dt>
|
||||||
<dd>[c:wu -c:m](#c:wu -c:m) <small>(Any card that is white or blue, but not multicolored)</small></dd>
|
<dd>[c:wu -c:m](#c:wu -c:m) <small>(Any card that is white or blue, but not multicolored)</small></dd>
|
||||||
|
|
||||||
<dt>Branching:</dt>
|
<dt>Branching:</dt>
|
||||||
|
|
|
||||||
|
|
@ -287,14 +287,14 @@ void AbstractCardItem::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
}
|
}
|
||||||
if (event->button() == Qt::LeftButton)
|
if (event->button() == Qt::LeftButton)
|
||||||
setCursor(Qt::ClosedHandCursor);
|
setCursor(Qt::ClosedHandCursor);
|
||||||
else if (event->button() == Qt::MidButton)
|
else if (event->button() == Qt::MiddleButton)
|
||||||
emit showCardInfoPopup(event->screenPos(), name);
|
emit showCardInfoPopup(event->screenPos(), name);
|
||||||
event->accept();
|
event->accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
void AbstractCardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::MidButton)
|
if (event->button() == Qt::MiddleButton)
|
||||||
emit deleteCardInfoPopup(name);
|
emit deleteCardInfoPopup(name);
|
||||||
|
|
||||||
// This function ensures the parent function doesn't mess around with our selection.
|
// This function ensures the parent function doesn't mess around with our selection.
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ void AbstractCounter::setValue(int _value)
|
||||||
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (isUnderMouse() && player->getLocalOrJudge()) {
|
if (isUnderMouse() && player->getLocalOrJudge()) {
|
||||||
if (event->button() == Qt::MidButton || (QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
|
if (event->button() == Qt::MiddleButton || (QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
|
||||||
if (menu)
|
if (menu)
|
||||||
menu->exec(event->screenPos());
|
menu->exec(event->screenPos());
|
||||||
event->accept();
|
event->accept();
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,10 @@
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
#include <QDirIterator>
|
||||||
#include <QFile>
|
#include <QFile>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
|
@ -291,22 +293,23 @@ void CardInfo::refreshCachedSetNames()
|
||||||
|
|
||||||
QString CardInfo::simplifyName(const QString &name)
|
QString CardInfo::simplifyName(const QString &name)
|
||||||
{
|
{
|
||||||
QString simpleName(name);
|
static const QRegularExpression spaceOrSplit("(\\s+|\\/\\/.*)");
|
||||||
|
static const QRegularExpression nonAlnum("[^a-z0-9]");
|
||||||
|
|
||||||
|
QString simpleName = name.toLower();
|
||||||
|
|
||||||
|
// remove spaces and right halves of split cards
|
||||||
|
simpleName.remove(spaceOrSplit);
|
||||||
|
|
||||||
// So Aetherling would work, but not Ætherling since 'Æ' would get replaced
|
// So Aetherling would work, but not Ætherling since 'Æ' would get replaced
|
||||||
// with nothing.
|
// with nothing.
|
||||||
simpleName.replace("æ", "ae");
|
simpleName.replace("æ", "ae");
|
||||||
simpleName.replace("Æ", "AE");
|
|
||||||
|
|
||||||
// Replace Jötun Grunt with Jotun Grunt.
|
// Replace Jötun Grunt with Jotun Grunt.
|
||||||
simpleName = simpleName.normalized(QString::NormalizationForm_KD);
|
simpleName = simpleName.normalized(QString::NormalizationForm_KD);
|
||||||
|
|
||||||
// Replace dashes with spaces so that we can say "garruk the veil cursed"
|
// remove all non alphanumeric characters from the name
|
||||||
// instead of the unintuitive "garruk the veilcursed".
|
simpleName.remove(nonAlnum);
|
||||||
simpleName = simpleName.replace("-", " ");
|
|
||||||
|
|
||||||
simpleName.remove(QRegExp("[^a-zA-Z0-9 ]"));
|
|
||||||
simpleName = simpleName.toLower();
|
|
||||||
return simpleName;
|
return simpleName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -437,6 +440,19 @@ CardInfoPtr CardDatabase::getCardBySimpleName(const QString &cardName) const
|
||||||
return getCardFromMap(simpleNameCards, CardInfo::simplifyName(cardName));
|
return getCardFromMap(simpleNameCards, CardInfo::simplifyName(cardName));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CardInfoPtr CardDatabase::guessCard(const QString &cardName) const
|
||||||
|
{
|
||||||
|
CardInfoPtr temp = getCard(cardName);
|
||||||
|
if (temp == nullptr) { // get card by simple name instead
|
||||||
|
temp = getCardBySimpleName(cardName);
|
||||||
|
if (temp == nullptr) { // still could not find the card, so simplify the cardName too
|
||||||
|
QString simpleCardName = CardInfo::simplifyName(cardName);
|
||||||
|
temp = getCardBySimpleName(simpleCardName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return temp; // returns nullptr if not found
|
||||||
|
}
|
||||||
|
|
||||||
CardSetPtr CardDatabase::getSet(const QString &setName)
|
CardSetPtr CardDatabase::getSet(const QString &setName)
|
||||||
{
|
{
|
||||||
if (sets.contains(setName)) {
|
if (sets.contains(setName)) {
|
||||||
|
|
@ -494,6 +510,7 @@ LoadStatus CardDatabase::loadFromFile(const QString &fileName)
|
||||||
|
|
||||||
LoadStatus CardDatabase::loadCardDatabase(const QString &path)
|
LoadStatus CardDatabase::loadCardDatabase(const QString &path)
|
||||||
{
|
{
|
||||||
|
auto startTime = QTime::currentTime();
|
||||||
LoadStatus tempLoadStatus = NotLoaded;
|
LoadStatus tempLoadStatus = NotLoaded;
|
||||||
if (!path.isEmpty()) {
|
if (!path.isEmpty()) {
|
||||||
loadFromFileMutex->lock();
|
loadFromFileMutex->lock();
|
||||||
|
|
@ -501,8 +518,9 @@ LoadStatus CardDatabase::loadCardDatabase(const QString &path)
|
||||||
loadFromFileMutex->unlock();
|
loadFromFileMutex->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int msecs = startTime.msecsTo(QTime::currentTime());
|
||||||
qDebug() << "[CardDatabase] loadCardDatabase(): Path =" << path << "Status =" << tempLoadStatus
|
qDebug() << "[CardDatabase] loadCardDatabase(): Path =" << path << "Status =" << tempLoadStatus
|
||||||
<< "Cards =" << cards.size() << "Sets=" << sets.size();
|
<< "Cards =" << cards.size() << "Sets =" << sets.size() << QString("%1ms").arg(msecs);
|
||||||
|
|
||||||
return tempLoadStatus;
|
return tempLoadStatus;
|
||||||
}
|
}
|
||||||
|
|
@ -519,11 +537,21 @@ LoadStatus CardDatabase::loadCardDatabases()
|
||||||
loadCardDatabase(SettingsCache::instance().getTokenDatabasePath()); // load tokens database
|
loadCardDatabase(SettingsCache::instance().getTokenDatabasePath()); // load tokens database
|
||||||
loadCardDatabase(SettingsCache::instance().getSpoilerCardDatabasePath()); // load spoilers database
|
loadCardDatabase(SettingsCache::instance().getSpoilerCardDatabasePath()); // load spoilers database
|
||||||
|
|
||||||
// load custom card databases
|
// find all custom card databases, recursively & following symlinks
|
||||||
QDir dir(SettingsCache::instance().getCustomCardDatabasePath());
|
// then load them alphabetically
|
||||||
for (const QString &fileName :
|
QDirIterator customDatabaseIterator(SettingsCache::instance().getCustomCardDatabasePath(), QStringList() << "*.xml",
|
||||||
dir.entryList(QStringList("*.xml"), QDir::Files | QDir::Readable, QDir::Name | QDir::IgnoreCase)) {
|
QDir::Files, QDirIterator::Subdirectories | QDirIterator::FollowSymlinks);
|
||||||
loadCardDatabase(dir.absoluteFilePath(fileName));
|
QStringList databasePaths;
|
||||||
|
while (customDatabaseIterator.hasNext()) {
|
||||||
|
customDatabaseIterator.next();
|
||||||
|
databasePaths.push_back(customDatabaseIterator.filePath());
|
||||||
|
}
|
||||||
|
databasePaths.sort();
|
||||||
|
|
||||||
|
for (auto i = 0; i < databasePaths.size(); ++i) {
|
||||||
|
const auto &databasePath = databasePaths.at(i);
|
||||||
|
qDebug() << "Loading Custom Set" << i << "(" << databasePath << ")";
|
||||||
|
loadCardDatabase(databasePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// AFTER all the cards have been loaded
|
// AFTER all the cards have been loaded
|
||||||
|
|
|
||||||
|
|
@ -409,6 +409,7 @@ public:
|
||||||
void removeCard(CardInfoPtr card);
|
void removeCard(CardInfoPtr card);
|
||||||
CardInfoPtr getCard(const QString &cardName) const;
|
CardInfoPtr getCard(const QString &cardName) const;
|
||||||
QList<CardInfoPtr> getCards(const QStringList &cardNames) const;
|
QList<CardInfoPtr> getCards(const QStringList &cardNames) const;
|
||||||
|
CardInfoPtr guessCard(const QString &cardName) const;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Get a card by its simple name. The name will be simplified in this
|
* Get a card by its simple name. The name will be simplified in this
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,9 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
||||||
// NOTE: attributes but be read before readElementText()
|
// NOTE: attributes but be read before readElementText()
|
||||||
QXmlStreamAttributes attrs = xml.attributes();
|
QXmlStreamAttributes attrs = xml.attributes();
|
||||||
QString setName = xml.readElementText(QXmlStreamReader::IncludeChildElements);
|
QString setName = xml.readElementText(QXmlStreamReader::IncludeChildElements);
|
||||||
CardInfoPerSet setInfo(internalAddSet(setName));
|
auto set = internalAddSet(setName);
|
||||||
|
if (set->getEnabled()) {
|
||||||
|
CardInfoPerSet setInfo(set);
|
||||||
for (QXmlStreamAttribute attr : attrs) {
|
for (QXmlStreamAttribute attr : attrs) {
|
||||||
QString attrName = attr.name().toString();
|
QString attrName = attr.name().toString();
|
||||||
if (attrName == "picURL")
|
if (attrName == "picURL")
|
||||||
|
|
@ -168,6 +170,7 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
||||||
setInfo.setProperty(attrName, attr.value().toString());
|
setInfo.setProperty(attrName, attr.value().toString());
|
||||||
}
|
}
|
||||||
sets.insert(setName, setInfo);
|
sets.insert(setName, setInfo);
|
||||||
|
}
|
||||||
// relatd cards
|
// relatd cards
|
||||||
} else if (xml.name() == "related" || xml.name() == "reverse-related") {
|
} else if (xml.name() == "related" || xml.name() == "reverse-related") {
|
||||||
bool attach = false;
|
bool attach = false;
|
||||||
|
|
|
||||||
|
|
@ -107,7 +107,7 @@ void CardFrame::setCard(CardInfoPtr card)
|
||||||
|
|
||||||
void CardFrame::setCard(const QString &cardName)
|
void CardFrame::setCard(const QString &cardName)
|
||||||
{
|
{
|
||||||
setCard(db->getCardBySimpleName(cardName));
|
setCard(db->guessCard(cardName));
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardFrame::setCard(AbstractCardItem *card)
|
void CardFrame::setCard(AbstractCardItem *card)
|
||||||
|
|
|
||||||
|
|
@ -65,9 +65,10 @@ void CardInfoWidget::setCard(CardInfoPtr card)
|
||||||
|
|
||||||
void CardInfoWidget::setCard(const QString &cardName)
|
void CardInfoWidget::setCard(const QString &cardName)
|
||||||
{
|
{
|
||||||
setCard(db->getCardBySimpleName(cardName));
|
setCard(db->guessCard(cardName));
|
||||||
if (!info)
|
if (info == nullptr) {
|
||||||
text->setInvalidCardName(cardName);
|
text->setInvalidCardName(cardName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardInfoWidget::setCard(AbstractCardItem *card)
|
void CardInfoWidget::setCard(AbstractCardItem *card)
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,15 @@
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
|
|
||||||
CardItem::CardItem(Player *_owner, const QString &_name, int _cardid, bool _revealedCard, QGraphicsItem *parent)
|
CardItem::CardItem(Player *_owner,
|
||||||
: AbstractCardItem(_name, _owner, _cardid, parent), zone(0), revealedCard(_revealedCard), attacking(false),
|
const QString &_name,
|
||||||
destroyOnZoneChange(false), doesntUntap(false), dragItem(0), attachedTo(0)
|
int _cardid,
|
||||||
|
bool _revealedCard,
|
||||||
|
QGraphicsItem *parent,
|
||||||
|
CardZone *_zone,
|
||||||
|
bool updateMenu)
|
||||||
|
: AbstractCardItem(_name, _owner, _cardid, parent), zone(_zone), revealedCard(_revealedCard), attacking(false),
|
||||||
|
destroyOnZoneChange(false), doesntUntap(false), dragItem(nullptr), attachedTo(nullptr)
|
||||||
{
|
{
|
||||||
owner->addCard(this);
|
owner->addCard(this);
|
||||||
|
|
||||||
|
|
@ -29,7 +35,9 @@ CardItem::CardItem(Player *_owner, const QString &_name, int _cardid, bool _reve
|
||||||
moveMenu = new QMenu;
|
moveMenu = new QMenu;
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
|
if (updateMenu) { // avoid updating card menu too often
|
||||||
emit updateCardMenu(this);
|
emit updateCardMenu(this);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CardItem::~CardItem()
|
CardItem::~CardItem()
|
||||||
|
|
@ -48,22 +56,22 @@ CardItem::~CardItem()
|
||||||
|
|
||||||
void CardItem::prepareDelete()
|
void CardItem::prepareDelete()
|
||||||
{
|
{
|
||||||
if (owner) {
|
if (owner != nullptr) {
|
||||||
if (owner->getCardMenu() == cardMenu) {
|
if (owner->getCardMenu() == cardMenu) {
|
||||||
owner->setCardMenu(0);
|
owner->setCardMenu(nullptr);
|
||||||
owner->getGame()->setActiveCard(0);
|
owner->getGame()->setActiveCard(nullptr);
|
||||||
}
|
}
|
||||||
owner = 0;
|
owner = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!attachedCards.isEmpty()) {
|
while (!attachedCards.isEmpty()) {
|
||||||
attachedCards.first()->setZone(0); // so that it won't try to call reorganizeCards()
|
attachedCards.first()->setZone(nullptr); // so that it won't try to call reorganizeCards()
|
||||||
attachedCards.first()->setAttachedTo(0);
|
attachedCards.first()->setAttachedTo(nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (attachedTo) {
|
if (attachedTo != nullptr) {
|
||||||
attachedTo->removeAttachedCard(this);
|
attachedTo->removeAttachedCard(this);
|
||||||
attachedTo = 0;
|
attachedTo = nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -265,9 +273,10 @@ CardDragItem *CardItem::createDragItem(int _id, const QPointF &_pos, const QPoin
|
||||||
|
|
||||||
void CardItem::deleteDragItem()
|
void CardItem::deleteDragItem()
|
||||||
{
|
{
|
||||||
if (dragItem)
|
if (dragItem) {
|
||||||
dragItem->deleteLater();
|
dragItem->deleteLater();
|
||||||
dragItem = NULL;
|
}
|
||||||
|
dragItem = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CardItem::drawArrow(const QColor &arrowColor)
|
void CardItem::drawArrow(const QColor &arrowColor)
|
||||||
|
|
@ -362,7 +371,7 @@ void CardItem::playCard(bool faceDown)
|
||||||
void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
{
|
{
|
||||||
if (event->button() == Qt::RightButton) {
|
if (event->button() == Qt::RightButton) {
|
||||||
if (cardMenu && !cardMenu->isEmpty() && owner) {
|
if (cardMenu && !cardMenu->isEmpty() && owner != nullptr) {
|
||||||
owner->updateCardMenu(this);
|
owner->updateCardMenu(this);
|
||||||
cardMenu->exec(event->screenPos());
|
cardMenu->exec(event->screenPos());
|
||||||
}
|
}
|
||||||
|
|
@ -370,7 +379,7 @@ void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
(!SettingsCache::instance().getDoubleClickToPlay())) {
|
(!SettingsCache::instance().getDoubleClickToPlay())) {
|
||||||
bool hideCard = false;
|
bool hideCard = false;
|
||||||
if (zone && zone->getIsView()) {
|
if (zone && zone->getIsView()) {
|
||||||
ZoneViewZone *view = static_cast<ZoneViewZone *>(zone);
|
auto *view = static_cast<ZoneViewZone *>(zone);
|
||||||
if (view->getRevealZone() && !view->getWriteableRevealZone())
|
if (view->getRevealZone() && !view->getWriteableRevealZone())
|
||||||
hideCard = true;
|
hideCard = true;
|
||||||
}
|
}
|
||||||
|
|
@ -381,7 +390,9 @@ void CardItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (owner != nullptr) { // cards without owner will be deleted
|
||||||
setCursor(Qt::OpenHandCursor);
|
setCursor(Qt::OpenHandCursor);
|
||||||
|
}
|
||||||
AbstractCardItem::mouseReleaseEvent(event);
|
AbstractCardItem::mouseReleaseEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,9 @@ public:
|
||||||
const QString &_name = QString(),
|
const QString &_name = QString(),
|
||||||
int _cardid = -1,
|
int _cardid = -1,
|
||||||
bool revealedCard = false,
|
bool revealedCard = false,
|
||||||
QGraphicsItem *parent = nullptr);
|
QGraphicsItem *parent = nullptr,
|
||||||
|
CardZone *_zone = nullptr,
|
||||||
|
bool updateMenu = false);
|
||||||
~CardItem();
|
~CardItem();
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
CardZone *getZone() const
|
CardZone *getZone() const
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ CardZone::CardZone(Player *_p,
|
||||||
bool _contentsKnown,
|
bool _contentsKnown,
|
||||||
QGraphicsItem *parent,
|
QGraphicsItem *parent,
|
||||||
bool _isView)
|
bool _isView)
|
||||||
: AbstractGraphicsItem(parent), player(_p), name(_name), cards(_contentsKnown), view(NULL), menu(NULL),
|
: AbstractGraphicsItem(parent), player(_p), name(_name), cards(_contentsKnown), views{}, menu(nullptr),
|
||||||
doubleClickAction(0), hasCardAttr(_hasCardAttr), isShufflable(_isShufflable), isView(_isView)
|
doubleClickAction(0), hasCardAttr(_hasCardAttr), isShufflable(_isShufflable), isView(_isView)
|
||||||
{
|
{
|
||||||
if (!isView)
|
if (!isView)
|
||||||
|
|
@ -28,7 +28,11 @@ CardZone::CardZone(Player *_p,
|
||||||
CardZone::~CardZone()
|
CardZone::~CardZone()
|
||||||
{
|
{
|
||||||
qDebug() << "CardZone destructor: " << name;
|
qDebug() << "CardZone destructor: " << name;
|
||||||
delete view;
|
for (auto *view : views) {
|
||||||
|
if (view != nullptr) {
|
||||||
|
view->deleteLater();
|
||||||
|
}
|
||||||
|
}
|
||||||
clearContents();
|
clearContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -120,9 +124,11 @@ void CardZone::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
|
||||||
void CardZone::addCard(CardItem *card, bool reorganize, int x, int y)
|
void CardZone::addCard(CardItem *card, bool reorganize, int x, int y)
|
||||||
{
|
{
|
||||||
if (view)
|
for (auto *view : views) {
|
||||||
if ((x <= view->getCards().size()) || (view->getNumberCards() == -1))
|
if ((x <= view->getCards().size()) || (view->getNumberCards() == -1)) {
|
||||||
view->addCard(new CardItem(player, card->getName(), card->getId()), reorganize, x, y);
|
view->addCard(new CardItem(player, card->getName(), card->getId()), reorganize, x, y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
card->setZone(this);
|
card->setZone(this);
|
||||||
addCardImpl(card, x, y);
|
addCardImpl(card, x, y);
|
||||||
|
|
@ -168,8 +174,9 @@ CardItem *CardZone::takeCard(int position, int cardId, bool /*canResize*/)
|
||||||
|
|
||||||
CardItem *c = cards.takeAt(position);
|
CardItem *c = cards.takeAt(position);
|
||||||
|
|
||||||
if (view)
|
for (auto *view : views) {
|
||||||
view->removeCard(position);
|
view->removeCard(position);
|
||||||
|
}
|
||||||
|
|
||||||
c->setId(cardId);
|
c->setId(cardId);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ protected:
|
||||||
Player *player;
|
Player *player;
|
||||||
QString name;
|
QString name;
|
||||||
CardList cards;
|
CardList cards;
|
||||||
ZoneViewZone *view;
|
QList<ZoneViewZone *> views;
|
||||||
QMenu *menu;
|
QMenu *menu;
|
||||||
QAction *doubleClickAction;
|
QAction *doubleClickAction;
|
||||||
bool hasCardAttr;
|
bool hasCardAttr;
|
||||||
|
|
@ -98,13 +98,9 @@ public:
|
||||||
// takeCard() finds a card by position and removes it from the zone and from all of its views.
|
// takeCard() finds a card by position and removes it from the zone and from all of its views.
|
||||||
virtual CardItem *takeCard(int position, int cardId, bool canResize = true);
|
virtual CardItem *takeCard(int position, int cardId, bool canResize = true);
|
||||||
void removeCard(CardItem *card);
|
void removeCard(CardItem *card);
|
||||||
ZoneViewZone *getView() const
|
QList<ZoneViewZone *> &getViews()
|
||||||
{
|
{
|
||||||
return view;
|
return views;
|
||||||
}
|
|
||||||
void setView(ZoneViewZone *_view)
|
|
||||||
{
|
|
||||||
view = _view;
|
|
||||||
}
|
}
|
||||||
virtual void reorganizeCards() = 0;
|
virtual void reorganizeCards() = 0;
|
||||||
virtual QPointF closestGridPoint(const QPointF &point);
|
virtual QPointF closestGridPoint(const QPointF &point);
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
#include "../pixmapgenerator.h"
|
#include "../pixmapgenerator.h"
|
||||||
#include "../settingscache.h"
|
#include "../settingscache.h"
|
||||||
#include "../soundengine.h"
|
#include "../soundengine.h"
|
||||||
#include "../tab_userlists.h"
|
#include "../tab_account.h"
|
||||||
#include "../user_context_menu.h"
|
#include "../user_context_menu.h"
|
||||||
#include "user_level.h"
|
#include "user_level.h"
|
||||||
|
|
||||||
|
|
@ -529,12 +529,12 @@ void ChatView::mousePressEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
switch (hoveredItemType) {
|
switch (hoveredItemType) {
|
||||||
case HoveredCard: {
|
case HoveredCard: {
|
||||||
if ((event->button() == Qt::MidButton) || (event->button() == Qt::LeftButton))
|
if ((event->button() == Qt::MiddleButton) || (event->button() == Qt::LeftButton))
|
||||||
emit showCardInfoPopup(event->globalPos(), hoveredContent);
|
emit showCardInfoPopup(event->globalPos(), hoveredContent);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case HoveredUser: {
|
case HoveredUser: {
|
||||||
if (event->button() != Qt::MidButton) {
|
if (event->button() != Qt::MiddleButton) {
|
||||||
const int delimiterIndex = hoveredContent.indexOf("_");
|
const int delimiterIndex = hoveredContent.indexOf("_");
|
||||||
const QString userName = hoveredContent.mid(delimiterIndex + 1);
|
const QString userName = hoveredContent.mid(delimiterIndex + 1);
|
||||||
switch (event->button()) {
|
switch (event->button()) {
|
||||||
|
|
@ -564,7 +564,7 @@ void ChatView::mousePressEvent(QMouseEvent *event)
|
||||||
|
|
||||||
void ChatView::mouseReleaseEvent(QMouseEvent *event)
|
void ChatView::mouseReleaseEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
if ((event->button() == Qt::MidButton) || (event->button() == Qt::LeftButton))
|
if ((event->button() == Qt::MiddleButton) || (event->button() == Qt::LeftButton))
|
||||||
emit deleteCardInfoPopup(QString("_"));
|
emit deleteCardInfoPopup(QString("_"));
|
||||||
|
|
||||||
QTextBrowser::mouseReleaseEvent(event);
|
QTextBrowser::mouseReleaseEvent(event);
|
||||||
|
|
|
||||||
|
|
@ -291,7 +291,7 @@ QString DeckLoader::getCardZoneFromName(QString cardName, QString currentZoneNam
|
||||||
QString DeckLoader::getCompleteCardName(const QString cardName) const
|
QString DeckLoader::getCompleteCardName(const QString cardName) const
|
||||||
{
|
{
|
||||||
if (db) {
|
if (db) {
|
||||||
CardInfoPtr temp = db->getCardBySimpleName(cardName);
|
CardInfoPtr temp = db->guessCard(cardName);
|
||||||
if (temp) {
|
if (temp) {
|
||||||
return temp->getName();
|
return temp->getName();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,11 +63,12 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
|
||||||
autoConnectCheckBox = new QCheckBox(tr("A&uto connect"));
|
autoConnectCheckBox = new QCheckBox(tr("A&uto connect"));
|
||||||
autoConnectCheckBox->setToolTip(tr("Automatically connect to the most recent login when Cockatrice opens"));
|
autoConnectCheckBox->setToolTip(tr("Automatically connect to the most recent login when Cockatrice opens"));
|
||||||
|
|
||||||
if (SettingsCache::instance().servers().getSavePassword()) {
|
auto &servers = SettingsCache::instance().servers();
|
||||||
autoConnectCheckBox->setChecked(static_cast<bool>(SettingsCache::instance().servers().getAutoConnect()));
|
if (servers.getSavePassword()) {
|
||||||
|
autoConnectCheckBox->setChecked(servers.getAutoConnect() > 0);
|
||||||
autoConnectCheckBox->setEnabled(true);
|
autoConnectCheckBox->setEnabled(true);
|
||||||
} else {
|
} else {
|
||||||
SettingsCache::instance().servers().setAutoConnect(0);
|
servers.setAutoConnect(0);
|
||||||
autoConnectCheckBox->setChecked(false);
|
autoConnectCheckBox->setChecked(false);
|
||||||
autoConnectCheckBox->setEnabled(false);
|
autoConnectCheckBox->setEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
@ -87,7 +88,7 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
|
||||||
|
|
||||||
btnForgotPassword = new QPushButton(this);
|
btnForgotPassword = new QPushButton(this);
|
||||||
btnForgotPassword->setIcon(QPixmap("theme:icons/forgot_password"));
|
btnForgotPassword->setIcon(QPixmap("theme:icons/forgot_password"));
|
||||||
btnForgotPassword->setToolTip(tr("Forgot Password"));
|
btnForgotPassword->setToolTip(tr("Reset Password"));
|
||||||
btnForgotPassword->setFixedWidth(30);
|
btnForgotPassword->setFixedWidth(30);
|
||||||
connect(btnForgotPassword, SIGNAL(released()), this, SLOT(actForgotPassword()));
|
connect(btnForgotPassword, SIGNAL(released()), this, SLOT(actForgotPassword()));
|
||||||
|
|
||||||
|
|
@ -192,13 +193,15 @@ void DlgConnect::rebuildComboBoxList(int failure)
|
||||||
UserConnection_Information uci;
|
UserConnection_Information uci;
|
||||||
savedHostList = uci.getServerInfo();
|
savedHostList = uci.getServerInfo();
|
||||||
|
|
||||||
bool autoConnectEnabled = static_cast<bool>(SettingsCache::instance().servers().getAutoConnect());
|
auto &servers = SettingsCache::instance().servers();
|
||||||
QString autoConnectSaveName = SettingsCache::instance().servers().getSaveName();
|
bool autoConnectEnabled = servers.getAutoConnect() > 0;
|
||||||
|
QString previousHostName = servers.getPrevioushostName();
|
||||||
|
QString autoConnectSaveName = servers.getSaveName();
|
||||||
|
|
||||||
int index = 0;
|
int index = 0;
|
||||||
|
|
||||||
for (const auto &pair : savedHostList) {
|
for (const auto &pair : savedHostList) {
|
||||||
auto tmp = pair.second;
|
const auto &tmp = pair.second;
|
||||||
QString saveName = tmp.getSaveName();
|
QString saveName = tmp.getSaveName();
|
||||||
if (saveName.size()) {
|
if (saveName.size()) {
|
||||||
previousHosts->addItem(saveName);
|
previousHosts->addItem(saveName);
|
||||||
|
|
@ -207,7 +210,7 @@ void DlgConnect::rebuildComboBoxList(int failure)
|
||||||
if (saveName.compare(autoConnectSaveName) == 0) {
|
if (saveName.compare(autoConnectSaveName) == 0) {
|
||||||
previousHosts->setCurrentIndex(index);
|
previousHosts->setCurrentIndex(index);
|
||||||
}
|
}
|
||||||
} else if (saveName.compare("Rooster Ranges") == 0) {
|
} else if (saveName.compare(previousHostName) == 0) {
|
||||||
previousHosts->setCurrentIndex(index);
|
previousHosts->setCurrentIndex(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -346,6 +349,11 @@ bool DeleteHighlightedItemWhenShiftDelPressedEventFilter::eventFilter(QObject *o
|
||||||
|
|
||||||
void DlgConnect::actForgotPassword()
|
void DlgConnect::actForgotPassword()
|
||||||
{
|
{
|
||||||
|
ServersSettings &servers = SettingsCache::instance().servers();
|
||||||
|
servers.setFPHostName(hostEdit->text());
|
||||||
|
servers.setFPPort(portEdit->text());
|
||||||
|
servers.setFPPlayerName(playernameEdit->text().trimmed());
|
||||||
|
|
||||||
emit sigStartForgotPasswordRequest();
|
emit sigStartForgotPasswordRequest();
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -83,11 +83,13 @@ void DlgCreateGame::sharedCtor()
|
||||||
spectatorsNeedPasswordCheckBox = new QCheckBox(tr("Spectators &need a password to watch"));
|
spectatorsNeedPasswordCheckBox = new QCheckBox(tr("Spectators &need a password to watch"));
|
||||||
spectatorsCanTalkCheckBox = new QCheckBox(tr("Spectators can &chat"));
|
spectatorsCanTalkCheckBox = new QCheckBox(tr("Spectators can &chat"));
|
||||||
spectatorsSeeEverythingCheckBox = new QCheckBox(tr("Spectators can see &hands"));
|
spectatorsSeeEverythingCheckBox = new QCheckBox(tr("Spectators can see &hands"));
|
||||||
|
createGameAsSpectatorCheckBox = new QCheckBox(tr("Create game as spectator"));
|
||||||
QVBoxLayout *spectatorsLayout = new QVBoxLayout;
|
QVBoxLayout *spectatorsLayout = new QVBoxLayout;
|
||||||
spectatorsLayout->addWidget(spectatorsAllowedCheckBox);
|
spectatorsLayout->addWidget(spectatorsAllowedCheckBox);
|
||||||
spectatorsLayout->addWidget(spectatorsNeedPasswordCheckBox);
|
spectatorsLayout->addWidget(spectatorsNeedPasswordCheckBox);
|
||||||
spectatorsLayout->addWidget(spectatorsCanTalkCheckBox);
|
spectatorsLayout->addWidget(spectatorsCanTalkCheckBox);
|
||||||
spectatorsLayout->addWidget(spectatorsSeeEverythingCheckBox);
|
spectatorsLayout->addWidget(spectatorsSeeEverythingCheckBox);
|
||||||
|
spectatorsLayout->addWidget(createGameAsSpectatorCheckBox);
|
||||||
spectatorsGroupBox = new QGroupBox(tr("Spectators"));
|
spectatorsGroupBox = new QGroupBox(tr("Spectators"));
|
||||||
spectatorsGroupBox->setLayout(spectatorsLayout);
|
spectatorsGroupBox->setLayout(spectatorsLayout);
|
||||||
|
|
||||||
|
|
@ -95,7 +97,7 @@ void DlgCreateGame::sharedCtor()
|
||||||
grid->addWidget(generalGroupBox, 0, 0);
|
grid->addWidget(generalGroupBox, 0, 0);
|
||||||
grid->addWidget(joinRestrictionsGroupBox, 0, 1);
|
grid->addWidget(joinRestrictionsGroupBox, 0, 1);
|
||||||
grid->addWidget(gameTypeGroupBox, 1, 0);
|
grid->addWidget(gameTypeGroupBox, 1, 0);
|
||||||
grid->addWidget(spectatorsGroupBox, 1, 1);
|
grid->addWidget(spectatorsGroupBox, 1, 1, Qt::AlignTop);
|
||||||
grid->addWidget(rememberGameSettings, 2, 0);
|
grid->addWidget(rememberGameSettings, 2, 0);
|
||||||
|
|
||||||
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
|
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
|
||||||
|
|
@ -129,6 +131,7 @@ DlgCreateGame::DlgCreateGame(TabRoom *_room, const QMap<int, QString> &_gameType
|
||||||
spectatorsNeedPasswordCheckBox->setChecked(SettingsCache::instance().getSpectatorsNeedPassword());
|
spectatorsNeedPasswordCheckBox->setChecked(SettingsCache::instance().getSpectatorsNeedPassword());
|
||||||
spectatorsCanTalkCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanTalk());
|
spectatorsCanTalkCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanTalk());
|
||||||
spectatorsSeeEverythingCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanSeeEverything());
|
spectatorsSeeEverythingCheckBox->setChecked(SettingsCache::instance().getSpectatorsCanSeeEverything());
|
||||||
|
createGameAsSpectatorCheckBox->setChecked(SettingsCache::instance().getCreateGameAsSpectator());
|
||||||
|
|
||||||
if (!rememberGameSettings->isChecked()) {
|
if (!rememberGameSettings->isChecked()) {
|
||||||
actReset();
|
actReset();
|
||||||
|
|
@ -159,6 +162,7 @@ DlgCreateGame::DlgCreateGame(const ServerInfo_Game &gameInfo, const QMap<int, QS
|
||||||
spectatorsNeedPasswordCheckBox->setEnabled(false);
|
spectatorsNeedPasswordCheckBox->setEnabled(false);
|
||||||
spectatorsCanTalkCheckBox->setEnabled(false);
|
spectatorsCanTalkCheckBox->setEnabled(false);
|
||||||
spectatorsSeeEverythingCheckBox->setEnabled(false);
|
spectatorsSeeEverythingCheckBox->setEnabled(false);
|
||||||
|
createGameAsSpectatorCheckBox->setEnabled(false);
|
||||||
|
|
||||||
descriptionEdit->setText(QString::fromStdString(gameInfo.description()));
|
descriptionEdit->setText(QString::fromStdString(gameInfo.description()));
|
||||||
maxPlayersEdit->setValue(gameInfo.max_players());
|
maxPlayersEdit->setValue(gameInfo.max_players());
|
||||||
|
|
@ -200,6 +204,7 @@ void DlgCreateGame::actReset()
|
||||||
spectatorsNeedPasswordCheckBox->setChecked(false);
|
spectatorsNeedPasswordCheckBox->setChecked(false);
|
||||||
spectatorsCanTalkCheckBox->setChecked(false);
|
spectatorsCanTalkCheckBox->setChecked(false);
|
||||||
spectatorsSeeEverythingCheckBox->setChecked(false);
|
spectatorsSeeEverythingCheckBox->setChecked(false);
|
||||||
|
createGameAsSpectatorCheckBox->setChecked(false);
|
||||||
|
|
||||||
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
||||||
while (gameTypeCheckBoxIterator.hasNext()) {
|
while (gameTypeCheckBoxIterator.hasNext()) {
|
||||||
|
|
@ -226,6 +231,7 @@ void DlgCreateGame::actOK()
|
||||||
cmd.set_spectators_can_talk(spectatorsCanTalkCheckBox->isChecked());
|
cmd.set_spectators_can_talk(spectatorsCanTalkCheckBox->isChecked());
|
||||||
cmd.set_spectators_see_everything(spectatorsSeeEverythingCheckBox->isChecked());
|
cmd.set_spectators_see_everything(spectatorsSeeEverythingCheckBox->isChecked());
|
||||||
cmd.set_join_as_judge(QApplication::keyboardModifiers() & Qt::ShiftModifier);
|
cmd.set_join_as_judge(QApplication::keyboardModifiers() & Qt::ShiftModifier);
|
||||||
|
cmd.set_join_as_spectator(createGameAsSpectatorCheckBox->isChecked());
|
||||||
|
|
||||||
QString gameTypes = QString();
|
QString gameTypes = QString();
|
||||||
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
QMapIterator<int, QRadioButton *> gameTypeCheckBoxIterator(gameTypeCheckBoxes);
|
||||||
|
|
@ -247,6 +253,7 @@ void DlgCreateGame::actOK()
|
||||||
SettingsCache::instance().setSpectatorsNeedPassword(spectatorsNeedPasswordCheckBox->isChecked());
|
SettingsCache::instance().setSpectatorsNeedPassword(spectatorsNeedPasswordCheckBox->isChecked());
|
||||||
SettingsCache::instance().setSpectatorsCanTalk(spectatorsCanTalkCheckBox->isChecked());
|
SettingsCache::instance().setSpectatorsCanTalk(spectatorsCanTalkCheckBox->isChecked());
|
||||||
SettingsCache::instance().setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked());
|
SettingsCache::instance().setSpectatorsCanSeeEverything(spectatorsSeeEverythingCheckBox->isChecked());
|
||||||
|
SettingsCache::instance().setCreateGameAsSpectator(createGameAsSpectatorCheckBox->isChecked());
|
||||||
SettingsCache::instance().setGameTypes(gameTypes);
|
SettingsCache::instance().setGameTypes(gameTypes);
|
||||||
}
|
}
|
||||||
PendingCommand *pend = room->prepareRoomCommand(cmd);
|
PendingCommand *pend = room->prepareRoomCommand(cmd);
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ private:
|
||||||
QSpinBox *maxPlayersEdit;
|
QSpinBox *maxPlayersEdit;
|
||||||
QCheckBox *onlyBuddiesCheckBox, *onlyRegisteredCheckBox;
|
QCheckBox *onlyBuddiesCheckBox, *onlyRegisteredCheckBox;
|
||||||
QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox,
|
QCheckBox *spectatorsAllowedCheckBox, *spectatorsNeedPasswordCheckBox, *spectatorsCanTalkCheckBox,
|
||||||
*spectatorsSeeEverythingCheckBox;
|
*spectatorsSeeEverythingCheckBox, *createGameAsSpectatorCheckBox;
|
||||||
QDialogButtonBox *buttonBox;
|
QDialogButtonBox *buttonBox;
|
||||||
QPushButton *clearButton;
|
QPushButton *clearButton;
|
||||||
QCheckBox *rememberGameSettings;
|
QCheckBox *rememberGameSettings;
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,13 @@
|
||||||
|
|
||||||
DlgEditPassword::DlgEditPassword(QWidget *parent) : QDialog(parent)
|
DlgEditPassword::DlgEditPassword(QWidget *parent) : QDialog(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
oldPasswordLabel = new QLabel(tr("Old password:"));
|
oldPasswordLabel = new QLabel(tr("Old password:"));
|
||||||
oldPasswordEdit = new QLineEdit();
|
oldPasswordEdit = new QLineEdit();
|
||||||
|
|
||||||
if (SettingsCache::instance().servers().getSavePassword())
|
auto &servers = SettingsCache::instance().servers();
|
||||||
oldPasswordEdit->setText(SettingsCache::instance().servers().getPassword());
|
if (servers.getSavePassword()) {
|
||||||
|
oldPasswordEdit->setText(servers.getPassword());
|
||||||
|
}
|
||||||
|
|
||||||
oldPasswordLabel->setBuddy(oldPasswordEdit);
|
oldPasswordLabel->setBuddy(oldPasswordEdit);
|
||||||
oldPasswordEdit->setEchoMode(QLineEdit::Password);
|
oldPasswordEdit->setEchoMode(QLineEdit::Password);
|
||||||
|
|
@ -59,7 +60,5 @@ void DlgEditPassword::actOk()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// always save the password so it will be picked up by the connect dialog
|
|
||||||
SettingsCache::instance().servers().setPassword(newPasswordEdit->text());
|
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "dlg_filter_games.h"
|
#include "dlg_filter_games.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
#include <QComboBox>
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
|
@ -15,13 +16,22 @@
|
||||||
DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
|
DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
|
||||||
const GamesProxyModel *_gamesProxyModel,
|
const GamesProxyModel *_gamesProxyModel,
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QDialog(parent), allGameTypes(_allGameTypes), gamesProxyModel(_gamesProxyModel)
|
: QDialog(parent), allGameTypes(_allGameTypes), gamesProxyModel(_gamesProxyModel),
|
||||||
|
gameAgeMap({{QTime(), tr("no limit")},
|
||||||
|
{QTime(0, 5), tr("5 minutes")},
|
||||||
|
{QTime(0, 10), tr("10 minutes")},
|
||||||
|
{QTime(0, 30), tr("30 minutes")},
|
||||||
|
{QTime(1, 0), tr("1 hour")},
|
||||||
|
{QTime(2, 0), tr("2 hours")}})
|
||||||
{
|
{
|
||||||
showBuddiesOnlyGames = new QCheckBox(tr("Show '&buddies only' games"));
|
showBuddiesOnlyGames = new QCheckBox(tr("Show '&buddies only' games"));
|
||||||
showBuddiesOnlyGames->setChecked(gamesProxyModel->getShowBuddiesOnlyGames());
|
showBuddiesOnlyGames->setChecked(gamesProxyModel->getShowBuddiesOnlyGames());
|
||||||
|
|
||||||
unavailableGamesVisibleCheckBox = new QCheckBox(tr("Show &unavailable games"));
|
showFullGames = new QCheckBox(tr("Show &full games"));
|
||||||
unavailableGamesVisibleCheckBox->setChecked(gamesProxyModel->getUnavailableGamesVisible());
|
showFullGames->setChecked(gamesProxyModel->getShowFullGames());
|
||||||
|
|
||||||
|
showGamesThatStarted = new QCheckBox(tr("Show games &that have started"));
|
||||||
|
showGamesThatStarted->setChecked(gamesProxyModel->getShowGamesThatStarted());
|
||||||
|
|
||||||
showPasswordProtectedGames = new QCheckBox(tr("Show &password protected games"));
|
showPasswordProtectedGames = new QCheckBox(tr("Show &password protected games"));
|
||||||
showPasswordProtectedGames->setChecked(gamesProxyModel->getShowPasswordProtectedGames());
|
showPasswordProtectedGames->setChecked(gamesProxyModel->getShowPasswordProtectedGames());
|
||||||
|
|
@ -29,29 +39,39 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
|
||||||
hideIgnoredUserGames = new QCheckBox(tr("Hide '&ignored user' games"));
|
hideIgnoredUserGames = new QCheckBox(tr("Hide '&ignored user' games"));
|
||||||
hideIgnoredUserGames->setChecked(gamesProxyModel->getHideIgnoredUserGames());
|
hideIgnoredUserGames->setChecked(gamesProxyModel->getHideIgnoredUserGames());
|
||||||
|
|
||||||
|
maxGameAgeComboBox = new QComboBox();
|
||||||
|
maxGameAgeComboBox->setEditable(false);
|
||||||
|
maxGameAgeComboBox->addItems(gameAgeMap.values());
|
||||||
|
QTime gameAge = gamesProxyModel->getMaxGameAge();
|
||||||
|
maxGameAgeComboBox->setCurrentIndex(gameAgeMap.keys().indexOf(gameAge)); // index is -1 if unknown
|
||||||
|
auto *maxGameAgeLabel = new QLabel(tr("&Newer than:"));
|
||||||
|
maxGameAgeLabel->setBuddy(maxGameAgeComboBox);
|
||||||
|
|
||||||
gameNameFilterEdit = new QLineEdit;
|
gameNameFilterEdit = new QLineEdit;
|
||||||
gameNameFilterEdit->setText(gamesProxyModel->getGameNameFilter());
|
gameNameFilterEdit->setText(gamesProxyModel->getGameNameFilter());
|
||||||
QLabel *gameNameFilterLabel = new QLabel(tr("Game &description:"));
|
auto *gameNameFilterLabel = new QLabel(tr("Game &description:"));
|
||||||
gameNameFilterLabel->setBuddy(gameNameFilterEdit);
|
gameNameFilterLabel->setBuddy(gameNameFilterEdit);
|
||||||
creatorNameFilterEdit = new QLineEdit;
|
creatorNameFilterEdit = new QLineEdit;
|
||||||
creatorNameFilterEdit->setText(gamesProxyModel->getCreatorNameFilter());
|
creatorNameFilterEdit->setText(gamesProxyModel->getCreatorNameFilter());
|
||||||
QLabel *creatorNameFilterLabel = new QLabel(tr("&Creator name:"));
|
auto *creatorNameFilterLabel = new QLabel(tr("&Creator name:"));
|
||||||
creatorNameFilterLabel->setBuddy(creatorNameFilterEdit);
|
creatorNameFilterLabel->setBuddy(creatorNameFilterEdit);
|
||||||
|
|
||||||
QGridLayout *generalGrid = new QGridLayout;
|
auto *generalGrid = new QGridLayout;
|
||||||
generalGrid->addWidget(gameNameFilterLabel, 0, 0);
|
generalGrid->addWidget(gameNameFilterLabel, 0, 0);
|
||||||
generalGrid->addWidget(gameNameFilterEdit, 0, 1);
|
generalGrid->addWidget(gameNameFilterEdit, 0, 1);
|
||||||
generalGrid->addWidget(creatorNameFilterLabel, 1, 0);
|
generalGrid->addWidget(creatorNameFilterLabel, 1, 0);
|
||||||
generalGrid->addWidget(creatorNameFilterEdit, 1, 1);
|
generalGrid->addWidget(creatorNameFilterEdit, 1, 1);
|
||||||
|
generalGrid->addWidget(maxGameAgeLabel, 2, 0);
|
||||||
|
generalGrid->addWidget(maxGameAgeComboBox, 2, 1);
|
||||||
generalGroupBox = new QGroupBox(tr("General"));
|
generalGroupBox = new QGroupBox(tr("General"));
|
||||||
generalGroupBox->setLayout(generalGrid);
|
generalGroupBox->setLayout(generalGrid);
|
||||||
|
|
||||||
QVBoxLayout *gameTypeFilterLayout = new QVBoxLayout;
|
auto *gameTypeFilterLayout = new QVBoxLayout;
|
||||||
QMapIterator<int, QString> gameTypesIterator(allGameTypes);
|
QMapIterator<int, QString> gameTypesIterator(allGameTypes);
|
||||||
while (gameTypesIterator.hasNext()) {
|
while (gameTypesIterator.hasNext()) {
|
||||||
gameTypesIterator.next();
|
gameTypesIterator.next();
|
||||||
|
|
||||||
QCheckBox *temp = new QCheckBox(gameTypesIterator.value());
|
auto *temp = new QCheckBox(gameTypesIterator.value());
|
||||||
temp->setChecked(gamesProxyModel->getGameTypeFilter().contains(gameTypesIterator.key()));
|
temp->setChecked(gamesProxyModel->getGameTypeFilter().contains(gameTypesIterator.key()));
|
||||||
|
|
||||||
gameTypeFilterCheckBoxes.insert(gameTypesIterator.key(), temp);
|
gameTypeFilterCheckBoxes.insert(gameTypesIterator.key(), temp);
|
||||||
|
|
@ -62,66 +82,95 @@ DlgFilterGames::DlgFilterGames(const QMap<int, QString> &_allGameTypes,
|
||||||
gameTypeFilterGroupBox = new QGroupBox(tr("&Game types"));
|
gameTypeFilterGroupBox = new QGroupBox(tr("&Game types"));
|
||||||
gameTypeFilterGroupBox->setLayout(gameTypeFilterLayout);
|
gameTypeFilterGroupBox->setLayout(gameTypeFilterLayout);
|
||||||
} else
|
} else
|
||||||
gameTypeFilterGroupBox = 0;
|
gameTypeFilterGroupBox = nullptr;
|
||||||
|
|
||||||
QLabel *maxPlayersFilterMinLabel = new QLabel(tr("at &least:"));
|
auto *maxPlayersFilterMinLabel = new QLabel(tr("at &least:"));
|
||||||
maxPlayersFilterMinSpinBox = new QSpinBox;
|
maxPlayersFilterMinSpinBox = new QSpinBox;
|
||||||
maxPlayersFilterMinSpinBox->setMinimum(1);
|
maxPlayersFilterMinSpinBox->setMinimum(0);
|
||||||
maxPlayersFilterMinSpinBox->setMaximum(99);
|
maxPlayersFilterMinSpinBox->setMaximum(99);
|
||||||
maxPlayersFilterMinSpinBox->setValue(gamesProxyModel->getMaxPlayersFilterMin());
|
maxPlayersFilterMinSpinBox->setValue(gamesProxyModel->getMaxPlayersFilterMin());
|
||||||
maxPlayersFilterMinLabel->setBuddy(maxPlayersFilterMinSpinBox);
|
maxPlayersFilterMinLabel->setBuddy(maxPlayersFilterMinSpinBox);
|
||||||
|
|
||||||
QLabel *maxPlayersFilterMaxLabel = new QLabel(tr("at &most:"));
|
auto *maxPlayersFilterMaxLabel = new QLabel(tr("at &most:"));
|
||||||
maxPlayersFilterMaxSpinBox = new QSpinBox;
|
maxPlayersFilterMaxSpinBox = new QSpinBox;
|
||||||
maxPlayersFilterMaxSpinBox->setMinimum(1);
|
maxPlayersFilterMaxSpinBox->setMinimum(0);
|
||||||
maxPlayersFilterMaxSpinBox->setMaximum(99);
|
maxPlayersFilterMaxSpinBox->setMaximum(99);
|
||||||
maxPlayersFilterMaxSpinBox->setValue(gamesProxyModel->getMaxPlayersFilterMax());
|
maxPlayersFilterMaxSpinBox->setValue(gamesProxyModel->getMaxPlayersFilterMax());
|
||||||
maxPlayersFilterMaxLabel->setBuddy(maxPlayersFilterMaxSpinBox);
|
maxPlayersFilterMaxLabel->setBuddy(maxPlayersFilterMaxSpinBox);
|
||||||
|
|
||||||
QGridLayout *maxPlayersFilterLayout = new QGridLayout;
|
auto *maxPlayersFilterLayout = new QGridLayout;
|
||||||
maxPlayersFilterLayout->addWidget(maxPlayersFilterMinLabel, 0, 0);
|
maxPlayersFilterLayout->addWidget(maxPlayersFilterMinLabel, 0, 0);
|
||||||
maxPlayersFilterLayout->addWidget(maxPlayersFilterMinSpinBox, 0, 1);
|
maxPlayersFilterLayout->addWidget(maxPlayersFilterMinSpinBox, 0, 1);
|
||||||
maxPlayersFilterLayout->addWidget(maxPlayersFilterMaxLabel, 1, 0);
|
maxPlayersFilterLayout->addWidget(maxPlayersFilterMaxLabel, 1, 0);
|
||||||
maxPlayersFilterLayout->addWidget(maxPlayersFilterMaxSpinBox, 1, 1);
|
maxPlayersFilterLayout->addWidget(maxPlayersFilterMaxSpinBox, 1, 1);
|
||||||
|
|
||||||
QGroupBox *maxPlayersGroupBox = new QGroupBox(tr("Maximum player count"));
|
auto *maxPlayersGroupBox = new QGroupBox(tr("Maximum player count"));
|
||||||
maxPlayersGroupBox->setLayout(maxPlayersFilterLayout);
|
maxPlayersGroupBox->setLayout(maxPlayersFilterLayout);
|
||||||
|
|
||||||
QGridLayout *restrictionsLayout = new QGridLayout;
|
auto *restrictionsLayout = new QGridLayout;
|
||||||
restrictionsLayout->addWidget(unavailableGamesVisibleCheckBox, 0, 0);
|
restrictionsLayout->addWidget(showFullGames, 0, 0);
|
||||||
restrictionsLayout->addWidget(showPasswordProtectedGames, 1, 0);
|
restrictionsLayout->addWidget(showGamesThatStarted, 1, 0);
|
||||||
restrictionsLayout->addWidget(showBuddiesOnlyGames, 2, 0);
|
restrictionsLayout->addWidget(showPasswordProtectedGames, 2, 0);
|
||||||
restrictionsLayout->addWidget(hideIgnoredUserGames, 3, 0);
|
restrictionsLayout->addWidget(showBuddiesOnlyGames, 3, 0);
|
||||||
|
restrictionsLayout->addWidget(hideIgnoredUserGames, 4, 0);
|
||||||
|
|
||||||
QGroupBox *restrictionsGroupBox = new QGroupBox(tr("Restrictions"));
|
auto *restrictionsGroupBox = new QGroupBox(tr("Restrictions"));
|
||||||
restrictionsGroupBox->setLayout(restrictionsLayout);
|
restrictionsGroupBox->setLayout(restrictionsLayout);
|
||||||
|
|
||||||
QGridLayout *leftGrid = new QGridLayout;
|
showOnlyIfSpectatorsCanWatch = new QCheckBox(tr("Show games only if &spectators can watch"));
|
||||||
|
showOnlyIfSpectatorsCanWatch->setChecked(gamesProxyModel->getShowOnlyIfSpectatorsCanWatch());
|
||||||
|
connect(showOnlyIfSpectatorsCanWatch, SIGNAL(toggled(bool)), this, SLOT(toggleSpectatorCheckboxEnabledness(bool)));
|
||||||
|
|
||||||
|
showSpectatorPasswordProtected = new QCheckBox(tr("Show spectator password p&rotected games"));
|
||||||
|
showSpectatorPasswordProtected->setChecked(gamesProxyModel->getShowSpectatorPasswordProtected());
|
||||||
|
showOnlyIfSpectatorsCanChat = new QCheckBox(tr("Show only if spectators can ch&at"));
|
||||||
|
showOnlyIfSpectatorsCanChat->setChecked(gamesProxyModel->getShowOnlyIfSpectatorsCanChat());
|
||||||
|
showOnlyIfSpectatorsCanSeeHands = new QCheckBox(tr("Show only if spectators can see &hands"));
|
||||||
|
showOnlyIfSpectatorsCanSeeHands->setChecked(gamesProxyModel->getShowOnlyIfSpectatorsCanSeeHands());
|
||||||
|
toggleSpectatorCheckboxEnabledness(getShowOnlyIfSpectatorsCanWatch());
|
||||||
|
|
||||||
|
auto *spectatorsLayout = new QGridLayout;
|
||||||
|
spectatorsLayout->addWidget(showOnlyIfSpectatorsCanWatch, 0, 0);
|
||||||
|
spectatorsLayout->addWidget(showSpectatorPasswordProtected, 1, 0);
|
||||||
|
spectatorsLayout->addWidget(showOnlyIfSpectatorsCanChat, 2, 0);
|
||||||
|
spectatorsLayout->addWidget(showOnlyIfSpectatorsCanSeeHands, 3, 0);
|
||||||
|
|
||||||
|
auto *spectatorsGroupBox = new QGroupBox(tr("Spectators"));
|
||||||
|
spectatorsGroupBox->setLayout(spectatorsLayout);
|
||||||
|
|
||||||
|
auto *leftGrid = new QGridLayout;
|
||||||
leftGrid->addWidget(generalGroupBox, 0, 0, 1, 2);
|
leftGrid->addWidget(generalGroupBox, 0, 0, 1, 2);
|
||||||
leftGrid->addWidget(maxPlayersGroupBox, 2, 0, 1, 2);
|
leftGrid->addWidget(maxPlayersGroupBox, 2, 0, 1, 2);
|
||||||
leftGrid->addWidget(restrictionsGroupBox, 3, 0, 1, 2);
|
leftGrid->addWidget(restrictionsGroupBox, 3, 0, 1, 2);
|
||||||
|
|
||||||
QVBoxLayout *leftColumn = new QVBoxLayout;
|
auto *leftColumn = new QVBoxLayout;
|
||||||
leftColumn->addLayout(leftGrid);
|
leftColumn->addLayout(leftGrid);
|
||||||
leftColumn->addStretch();
|
leftColumn->addStretch();
|
||||||
|
|
||||||
QVBoxLayout *rightColumn = new QVBoxLayout;
|
auto *rightGrid = new QGridLayout;
|
||||||
rightColumn->addWidget(gameTypeFilterGroupBox);
|
rightGrid->addWidget(gameTypeFilterGroupBox, 0, 0, 1, 1);
|
||||||
|
rightGrid->addWidget(spectatorsGroupBox, 1, 0, 1, 1);
|
||||||
|
|
||||||
QHBoxLayout *hbox = new QHBoxLayout;
|
auto *rightColumn = new QVBoxLayout;
|
||||||
|
rightColumn->addLayout(rightGrid);
|
||||||
|
rightColumn->addStretch();
|
||||||
|
|
||||||
|
auto *hbox = new QHBoxLayout;
|
||||||
hbox->addLayout(leftColumn);
|
hbox->addLayout(leftColumn);
|
||||||
hbox->addLayout(rightColumn);
|
hbox->addLayout(rightColumn);
|
||||||
|
|
||||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
||||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
auto *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(hbox);
|
mainLayout->addLayout(hbox);
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
setWindowTitle(tr("Filter games"));
|
setWindowTitle(tr("Filter games"));
|
||||||
|
|
||||||
|
setFixedHeight(sizeHint().height());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgFilterGames::actOk()
|
void DlgFilterGames::actOk()
|
||||||
|
|
@ -129,14 +178,21 @@ void DlgFilterGames::actOk()
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DlgFilterGames::getUnavailableGamesVisible() const
|
void DlgFilterGames::toggleSpectatorCheckboxEnabledness(bool spectatorsEnabled)
|
||||||
{
|
{
|
||||||
return unavailableGamesVisibleCheckBox->isChecked();
|
showSpectatorPasswordProtected->setDisabled(!spectatorsEnabled);
|
||||||
|
showOnlyIfSpectatorsCanChat->setDisabled(!spectatorsEnabled);
|
||||||
|
showOnlyIfSpectatorsCanSeeHands->setDisabled(!spectatorsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgFilterGames::setUnavailableGamesVisible(bool _unavailableGamesVisible)
|
bool DlgFilterGames::getShowFullGames() const
|
||||||
{
|
{
|
||||||
unavailableGamesVisibleCheckBox->setChecked(_unavailableGamesVisible);
|
return showFullGames->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DlgFilterGames::getShowGamesThatStarted() const
|
||||||
|
{
|
||||||
|
return showGamesThatStarted->isChecked();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DlgFilterGames::getShowBuddiesOnlyGames() const
|
bool DlgFilterGames::getShowBuddiesOnlyGames() const
|
||||||
|
|
@ -220,9 +276,38 @@ int DlgFilterGames::getMaxPlayersFilterMax() const
|
||||||
return maxPlayersFilterMaxSpinBox->value();
|
return maxPlayersFilterMaxSpinBox->value();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const QTime &DlgFilterGames::getMaxGameAge() const
|
||||||
|
{
|
||||||
|
int index = maxGameAgeComboBox->currentIndex();
|
||||||
|
if (index < 0 || index >= gameAgeMap.size()) { // index is out of bounds
|
||||||
|
return gamesProxyModel->getMaxGameAge(); // leave the setting unchanged
|
||||||
|
}
|
||||||
|
return gameAgeMap.keys().at(index);
|
||||||
|
}
|
||||||
|
|
||||||
void DlgFilterGames::setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax)
|
void DlgFilterGames::setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax)
|
||||||
{
|
{
|
||||||
maxPlayersFilterMinSpinBox->setValue(_maxPlayersFilterMin);
|
maxPlayersFilterMinSpinBox->setValue(_maxPlayersFilterMin);
|
||||||
maxPlayersFilterMaxSpinBox->setValue(_maxPlayersFilterMax == -1 ? maxPlayersFilterMaxSpinBox->maximum()
|
maxPlayersFilterMaxSpinBox->setValue(_maxPlayersFilterMax == -1 ? maxPlayersFilterMaxSpinBox->maximum()
|
||||||
: _maxPlayersFilterMax);
|
: _maxPlayersFilterMax);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DlgFilterGames::getShowOnlyIfSpectatorsCanWatch() const
|
||||||
|
{
|
||||||
|
return showOnlyIfSpectatorsCanWatch->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DlgFilterGames::getShowSpectatorPasswordProtected() const
|
||||||
|
{
|
||||||
|
return showSpectatorPasswordProtected->isEnabled() && showSpectatorPasswordProtected->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DlgFilterGames::getShowOnlyIfSpectatorsCanChat() const
|
||||||
|
{
|
||||||
|
return showOnlyIfSpectatorsCanChat->isEnabled() && showOnlyIfSpectatorsCanChat->isChecked();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DlgFilterGames::getShowOnlyIfSpectatorsCanSeeHands() const
|
||||||
|
{
|
||||||
|
return showOnlyIfSpectatorsCanSeeHands->isEnabled() && showOnlyIfSpectatorsCanSeeHands->isChecked();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,11 +4,14 @@
|
||||||
#include "gamesmodel.h"
|
#include "gamesmodel.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
#include <QComboBox>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QMap>
|
#include <QMap>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
|
#include <QTime>
|
||||||
|
|
||||||
class QCheckBox;
|
class QCheckBox;
|
||||||
|
class QComboBox;
|
||||||
class QGroupBox;
|
class QGroupBox;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
class QSpinBox;
|
class QSpinBox;
|
||||||
|
|
@ -19,7 +22,8 @@ class DlgFilterGames : public QDialog
|
||||||
private:
|
private:
|
||||||
QGroupBox *generalGroupBox;
|
QGroupBox *generalGroupBox;
|
||||||
QCheckBox *showBuddiesOnlyGames;
|
QCheckBox *showBuddiesOnlyGames;
|
||||||
QCheckBox *unavailableGamesVisibleCheckBox;
|
QCheckBox *showFullGames;
|
||||||
|
QCheckBox *showGamesThatStarted;
|
||||||
QCheckBox *showPasswordProtectedGames;
|
QCheckBox *showPasswordProtectedGames;
|
||||||
QCheckBox *hideIgnoredUserGames;
|
QCheckBox *hideIgnoredUserGames;
|
||||||
QLineEdit *gameNameFilterEdit;
|
QLineEdit *gameNameFilterEdit;
|
||||||
|
|
@ -27,20 +31,27 @@ private:
|
||||||
QMap<int, QCheckBox *> gameTypeFilterCheckBoxes;
|
QMap<int, QCheckBox *> gameTypeFilterCheckBoxes;
|
||||||
QSpinBox *maxPlayersFilterMinSpinBox;
|
QSpinBox *maxPlayersFilterMinSpinBox;
|
||||||
QSpinBox *maxPlayersFilterMaxSpinBox;
|
QSpinBox *maxPlayersFilterMaxSpinBox;
|
||||||
|
QComboBox *maxGameAgeComboBox;
|
||||||
|
|
||||||
|
QCheckBox *showOnlyIfSpectatorsCanWatch;
|
||||||
|
QCheckBox *showSpectatorPasswordProtected;
|
||||||
|
QCheckBox *showOnlyIfSpectatorsCanChat;
|
||||||
|
QCheckBox *showOnlyIfSpectatorsCanSeeHands;
|
||||||
|
|
||||||
const QMap<int, QString> &allGameTypes;
|
const QMap<int, QString> &allGameTypes;
|
||||||
const GamesProxyModel *gamesProxyModel;
|
const GamesProxyModel *gamesProxyModel;
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void actOk();
|
void actOk();
|
||||||
|
void toggleSpectatorCheckboxEnabledness(bool spectatorsEnabled);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DlgFilterGames(const QMap<int, QString> &_allGameTypes,
|
DlgFilterGames(const QMap<int, QString> &_allGameTypes,
|
||||||
const GamesProxyModel *_gamesProxyModel,
|
const GamesProxyModel *_gamesProxyModel,
|
||||||
QWidget *parent = nullptr);
|
QWidget *parent = nullptr);
|
||||||
|
|
||||||
bool getUnavailableGamesVisible() const;
|
bool getShowFullGames() const;
|
||||||
void setUnavailableGamesVisible(bool _unavailableGamesVisible);
|
bool getShowGamesThatStarted() const;
|
||||||
bool getShowPasswordProtectedGames() const;
|
bool getShowPasswordProtectedGames() const;
|
||||||
void setShowPasswordProtectedGames(bool _passwordProtectedGamesHidden);
|
void setShowPasswordProtectedGames(bool _passwordProtectedGamesHidden);
|
||||||
bool getShowBuddiesOnlyGames() const;
|
bool getShowBuddiesOnlyGames() const;
|
||||||
|
|
@ -56,6 +67,12 @@ public:
|
||||||
int getMaxPlayersFilterMin() const;
|
int getMaxPlayersFilterMin() const;
|
||||||
int getMaxPlayersFilterMax() const;
|
int getMaxPlayersFilterMax() const;
|
||||||
void setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax);
|
void setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax);
|
||||||
|
const QTime &getMaxGameAge() const;
|
||||||
|
const QMap<QTime, QString> gameAgeMap;
|
||||||
|
bool getShowOnlyIfSpectatorsCanWatch() const;
|
||||||
|
bool getShowSpectatorPasswordProtected() const;
|
||||||
|
bool getShowOnlyIfSpectatorsCanChat() const;
|
||||||
|
bool getShowOnlyIfSpectatorsCanSeeHands() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,13 @@
|
||||||
|
|
||||||
DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialog(parent)
|
DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialog(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
QString lastfphost;
|
QString lastfphost;
|
||||||
QString lastfpport;
|
QString lastfpport;
|
||||||
QString lastfpplayername;
|
QString lastfpplayername;
|
||||||
ServersSettings &servers = SettingsCache::instance().servers();
|
ServersSettings &servers = SettingsCache::instance().servers();
|
||||||
lastfphost = servers.getHostname("server.cockatrice.us");
|
lastfphost = servers.getHostname();
|
||||||
lastfpport = servers.getPort("4747");
|
lastfpport = servers.getPort();
|
||||||
lastfpplayername = servers.getPlayerName("Player");
|
lastfpplayername = servers.getPlayerName();
|
||||||
|
|
||||||
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
|
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
|
||||||
lastfphost = servers.getFPHostname();
|
lastfphost = servers.getFPHostname();
|
||||||
|
|
@ -28,12 +27,15 @@ DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialo
|
||||||
}
|
}
|
||||||
|
|
||||||
if (servers.getFPHostname().isEmpty() && servers.getFPPort().isEmpty() && servers.getFPPlayerName().isEmpty()) {
|
if (servers.getFPHostname().isEmpty() && servers.getFPPort().isEmpty() && servers.getFPPlayerName().isEmpty()) {
|
||||||
QMessageBox::warning(this, tr("Forgot Password Challenge Warning"),
|
QMessageBox::warning(this, tr("Reset Password Challenge Warning"),
|
||||||
tr("Oops, looks like something has gone wrong. Please restart the forgot password "
|
tr("A problem has occurred. Please try to request a new password again."));
|
||||||
"process by using the forgot password button on the connection screen."));
|
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infoLabel =
|
||||||
|
new QLabel(tr("Enter the information of the server and the account you'd like to request a new password for."));
|
||||||
|
infoLabel->setWordWrap(true);
|
||||||
|
|
||||||
hostLabel = new QLabel(tr("&Host:"));
|
hostLabel = new QLabel(tr("&Host:"));
|
||||||
hostEdit = new QLineEdit(lastfphost);
|
hostEdit = new QLineEdit(lastfphost);
|
||||||
hostLabel->setBuddy(hostEdit);
|
hostLabel->setBuddy(hostEdit);
|
||||||
|
|
@ -60,14 +62,15 @@ DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialo
|
||||||
}
|
}
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
QGridLayout *grid = new QGridLayout;
|
||||||
grid->addWidget(hostLabel, 0, 0);
|
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
||||||
grid->addWidget(hostEdit, 0, 1);
|
grid->addWidget(hostLabel, 1, 0);
|
||||||
grid->addWidget(portLabel, 1, 0);
|
grid->addWidget(hostEdit, 1, 1);
|
||||||
grid->addWidget(portEdit, 1, 1);
|
grid->addWidget(portLabel, 2, 0);
|
||||||
grid->addWidget(playernameLabel, 2, 0);
|
grid->addWidget(portEdit, 2, 1);
|
||||||
grid->addWidget(playernameEdit, 2, 1);
|
grid->addWidget(playernameLabel, 3, 0);
|
||||||
grid->addWidget(emailLabel, 3, 0);
|
grid->addWidget(playernameEdit, 3, 1);
|
||||||
grid->addWidget(emailEdit, 3, 1);
|
grid->addWidget(emailLabel, 4, 0);
|
||||||
|
grid->addWidget(emailEdit, 4, 1);
|
||||||
|
|
||||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
||||||
|
|
@ -78,7 +81,7 @@ DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialo
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
setWindowTitle(tr("Forgot Password Challenge"));
|
setWindowTitle(tr("Reset Password Challenge"));
|
||||||
setFixedHeight(sizeHint().height());
|
setFixedHeight(sizeHint().height());
|
||||||
setMinimumWidth(300);
|
setMinimumWidth(300);
|
||||||
}
|
}
|
||||||
|
|
@ -86,7 +89,7 @@ DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialo
|
||||||
void DlgForgotPasswordChallenge::actOk()
|
void DlgForgotPasswordChallenge::actOk()
|
||||||
{
|
{
|
||||||
if (emailEdit->text().isEmpty()) {
|
if (emailEdit->text().isEmpty()) {
|
||||||
QMessageBox::critical(this, tr("Forgot Password Challenge Warning"), tr("The email address can't be empty."));
|
QMessageBox::critical(this, tr("Reset Password Challenge Error"), tr("The email address can't be empty."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ private slots:
|
||||||
void actOk();
|
void actOk();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *hostLabel, *portLabel, *playernameLabel, *emailLabel;
|
QLabel *infoLabel, *hostLabel, *portLabel, *playernameLabel, *emailLabel;
|
||||||
QLineEdit *hostEdit, *portEdit, *playernameEdit, *emailEdit;
|
QLineEdit *hostEdit, *portEdit, *playernameEdit, *emailEdit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,13 @@
|
||||||
|
|
||||||
DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(parent)
|
DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
QString lastfphost;
|
QString lastfphost;
|
||||||
QString lastfpport;
|
QString lastfpport;
|
||||||
QString lastfpplayername;
|
QString lastfpplayername;
|
||||||
ServersSettings &servers = SettingsCache::instance().servers();
|
ServersSettings &servers = SettingsCache::instance().servers();
|
||||||
lastfphost = servers.getHostname("server.cockatrice.us");
|
lastfphost = servers.getHostname();
|
||||||
lastfpport = servers.getPort("4747");
|
lastfpport = servers.getPort();
|
||||||
lastfpplayername = servers.getPlayerName("Player");
|
lastfpplayername = servers.getPlayerName();
|
||||||
|
|
||||||
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
|
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
|
||||||
lastfphost = servers.getFPHostname();
|
lastfphost = servers.getFPHostname();
|
||||||
|
|
@ -27,6 +26,9 @@ DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(pa
|
||||||
lastfpplayername = servers.getFPPlayerName();
|
lastfpplayername = servers.getFPPlayerName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infoLabel = new QLabel(tr("Enter the information of the server you'd like to request a new password for."));
|
||||||
|
infoLabel->setWordWrap(true);
|
||||||
|
|
||||||
hostLabel = new QLabel(tr("&Host:"));
|
hostLabel = new QLabel(tr("&Host:"));
|
||||||
hostEdit = new QLineEdit(lastfphost);
|
hostEdit = new QLineEdit(lastfphost);
|
||||||
hostLabel->setBuddy(hostEdit);
|
hostLabel->setBuddy(hostEdit);
|
||||||
|
|
@ -40,12 +42,13 @@ DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(pa
|
||||||
playernameLabel->setBuddy(playernameEdit);
|
playernameLabel->setBuddy(playernameEdit);
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
QGridLayout *grid = new QGridLayout;
|
||||||
grid->addWidget(hostLabel, 0, 0);
|
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
||||||
grid->addWidget(hostEdit, 0, 1);
|
grid->addWidget(hostLabel, 1, 0);
|
||||||
grid->addWidget(portLabel, 1, 0);
|
grid->addWidget(hostEdit, 1, 1);
|
||||||
grid->addWidget(portEdit, 1, 1);
|
grid->addWidget(portLabel, 2, 0);
|
||||||
grid->addWidget(playernameLabel, 2, 0);
|
grid->addWidget(portEdit, 2, 1);
|
||||||
grid->addWidget(playernameEdit, 2, 1);
|
grid->addWidget(playernameLabel, 3, 0);
|
||||||
|
grid->addWidget(playernameEdit, 3, 1);
|
||||||
|
|
||||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
||||||
|
|
@ -56,7 +59,7 @@ DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(pa
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
setWindowTitle(tr("Forgot Password Request"));
|
setWindowTitle(tr("Reset Password Request"));
|
||||||
setFixedHeight(sizeHint().height());
|
setFixedHeight(sizeHint().height());
|
||||||
setMinimumWidth(300);
|
setMinimumWidth(300);
|
||||||
}
|
}
|
||||||
|
|
@ -64,7 +67,7 @@ DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(pa
|
||||||
void DlgForgotPasswordRequest::actOk()
|
void DlgForgotPasswordRequest::actOk()
|
||||||
{
|
{
|
||||||
if (playernameEdit->text().isEmpty()) {
|
if (playernameEdit->text().isEmpty()) {
|
||||||
QMessageBox::critical(this, tr("Forgot Password Request Warning"), tr("The player name can't be empty."));
|
QMessageBox::critical(this, tr("Reset Password Error"), tr("The player name can't be empty."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,7 @@ private slots:
|
||||||
void actOk();
|
void actOk();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *hostLabel, *portLabel, *playernameLabel;
|
QLabel *infoLabel, *hostLabel, *portLabel, *playernameLabel;
|
||||||
QLineEdit *hostEdit, *portEdit, *playernameEdit;
|
QLineEdit *hostEdit, *portEdit, *playernameEdit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,14 +12,13 @@
|
||||||
|
|
||||||
DlgForgotPasswordReset::DlgForgotPasswordReset(QWidget *parent) : QDialog(parent)
|
DlgForgotPasswordReset::DlgForgotPasswordReset(QWidget *parent) : QDialog(parent)
|
||||||
{
|
{
|
||||||
|
|
||||||
QString lastfphost;
|
QString lastfphost;
|
||||||
QString lastfpport;
|
QString lastfpport;
|
||||||
QString lastfpplayername;
|
QString lastfpplayername;
|
||||||
ServersSettings &servers = SettingsCache::instance().servers();
|
ServersSettings &servers = SettingsCache::instance().servers();
|
||||||
lastfphost = servers.getHostname("server.cockatrice.us");
|
lastfphost = servers.getHostname();
|
||||||
lastfpport = servers.getPort("4747");
|
lastfpport = servers.getPort();
|
||||||
lastfpplayername = servers.getPlayerName("Player");
|
lastfpplayername = servers.getPlayerName();
|
||||||
|
|
||||||
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
|
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {
|
||||||
lastfphost = servers.getFPHostname();
|
lastfphost = servers.getFPHostname();
|
||||||
|
|
@ -28,12 +27,14 @@ DlgForgotPasswordReset::DlgForgotPasswordReset(QWidget *parent) : QDialog(parent
|
||||||
}
|
}
|
||||||
|
|
||||||
if (servers.getFPHostname().isEmpty() && servers.getFPPort().isEmpty() && servers.getFPPlayerName().isEmpty()) {
|
if (servers.getFPHostname().isEmpty() && servers.getFPPort().isEmpty() && servers.getFPPlayerName().isEmpty()) {
|
||||||
QMessageBox::warning(this, tr("Forgot Password Reset Warning"),
|
QMessageBox::warning(this, tr("Reset Password Warning"),
|
||||||
tr("Oops, looks like something has gone wrong. Please re-start the forgot password "
|
tr("A problem has occurred. Please try to request a new password again."));
|
||||||
"process by using the forgot password button on the connection screen."));
|
|
||||||
reject();
|
reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
infoLabel = new QLabel(tr("Enter the received token and the new password in order to set your new password."));
|
||||||
|
infoLabel->setWordWrap(true);
|
||||||
|
|
||||||
hostLabel = new QLabel(tr("&Host:"));
|
hostLabel = new QLabel(tr("&Host:"));
|
||||||
hostEdit = new QLineEdit(lastfphost);
|
hostEdit = new QLineEdit(lastfphost);
|
||||||
hostLabel->setBuddy(hostEdit);
|
hostLabel->setBuddy(hostEdit);
|
||||||
|
|
@ -70,18 +71,19 @@ DlgForgotPasswordReset::DlgForgotPasswordReset(QWidget *parent) : QDialog(parent
|
||||||
}
|
}
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
QGridLayout *grid = new QGridLayout;
|
||||||
grid->addWidget(hostLabel, 0, 0);
|
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
||||||
grid->addWidget(hostEdit, 0, 1);
|
grid->addWidget(hostLabel, 1, 0);
|
||||||
grid->addWidget(portLabel, 1, 0);
|
grid->addWidget(hostEdit, 1, 1);
|
||||||
grid->addWidget(portEdit, 1, 1);
|
grid->addWidget(portLabel, 2, 0);
|
||||||
grid->addWidget(playernameLabel, 2, 0);
|
grid->addWidget(portEdit, 2, 1);
|
||||||
grid->addWidget(playernameEdit, 2, 1);
|
grid->addWidget(playernameLabel, 3, 0);
|
||||||
grid->addWidget(tokenLabel, 3, 0);
|
grid->addWidget(playernameEdit, 3, 1);
|
||||||
grid->addWidget(tokenEdit, 3, 1);
|
grid->addWidget(tokenLabel, 4, 0);
|
||||||
grid->addWidget(newpasswordLabel, 4, 0);
|
grid->addWidget(tokenEdit, 4, 1);
|
||||||
grid->addWidget(newpasswordEdit, 4, 1);
|
grid->addWidget(newpasswordLabel, 5, 0);
|
||||||
grid->addWidget(newpasswordverifyLabel, 5, 0);
|
grid->addWidget(newpasswordEdit, 5, 1);
|
||||||
grid->addWidget(newpasswordverifyEdit, 5, 1);
|
grid->addWidget(newpasswordverifyLabel, 6, 0);
|
||||||
|
grid->addWidget(newpasswordverifyEdit, 6, 1);
|
||||||
|
|
||||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
||||||
|
|
@ -92,7 +94,7 @@ DlgForgotPasswordReset::DlgForgotPasswordReset(QWidget *parent) : QDialog(parent
|
||||||
mainLayout->addWidget(buttonBox);
|
mainLayout->addWidget(buttonBox);
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
|
||||||
setWindowTitle(tr("Forgot Password Reset"));
|
setWindowTitle(tr("Reset Password"));
|
||||||
setFixedHeight(sizeHint().height());
|
setFixedHeight(sizeHint().height());
|
||||||
setMinimumWidth(300);
|
setMinimumWidth(300);
|
||||||
}
|
}
|
||||||
|
|
@ -100,22 +102,22 @@ DlgForgotPasswordReset::DlgForgotPasswordReset(QWidget *parent) : QDialog(parent
|
||||||
void DlgForgotPasswordReset::actOk()
|
void DlgForgotPasswordReset::actOk()
|
||||||
{
|
{
|
||||||
if (playernameEdit->text().isEmpty()) {
|
if (playernameEdit->text().isEmpty()) {
|
||||||
QMessageBox::critical(this, tr("Forgot Password Reset Warning"), tr("The player name can't be empty."));
|
QMessageBox::critical(this, tr("Reset Password Error"), tr("The player name can't be empty."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tokenEdit->text().isEmpty()) {
|
if (tokenEdit->text().isEmpty()) {
|
||||||
QMessageBox::critical(this, tr("Forgot Password Reset Warning"), tr("The token can't be empty."));
|
QMessageBox::critical(this, tr("Reset Password Error"), tr("The token can't be empty."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newpasswordEdit->text().isEmpty()) {
|
if (newpasswordEdit->text().isEmpty()) {
|
||||||
QMessageBox::critical(this, tr("Forgot Password Reset Warning"), tr("The new password can't be empty."));
|
QMessageBox::critical(this, tr("Reset Password Error"), tr("The new password can't be empty."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newpasswordEdit->text() != newpasswordverifyEdit->text()) {
|
if (newpasswordEdit->text() != newpasswordverifyEdit->text()) {
|
||||||
QMessageBox::critical(this, tr("Forgot Password Reset Warning"), tr("The passwords do not match."));
|
QMessageBox::critical(this, tr("Reset Password Error"), tr("The passwords do not match."));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,7 +38,8 @@ private slots:
|
||||||
void actOk();
|
void actOk();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *hostLabel, *portLabel, *playernameLabel, *tokenLabel, *newpasswordLabel, *newpasswordverifyLabel;
|
QLabel *infoLabel, *hostLabel, *portLabel, *playernameLabel, *tokenLabel, *newpasswordLabel,
|
||||||
|
*newpasswordverifyLabel;
|
||||||
QLineEdit *hostEdit, *portEdit, *playernameEdit, *tokenEdit, *newpasswordEdit, *newpasswordverifyEdit;
|
QLineEdit *hostEdit, *portEdit, *playernameEdit, *tokenEdit, *newpasswordEdit, *newpasswordverifyEdit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "window_sets.h"
|
#include "dlg_manage_sets.h"
|
||||||
|
|
||||||
#include "customlineedit.h"
|
#include "customlineedit.h"
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
|
|
@ -84,6 +84,7 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
||||||
displayModel->setDynamicSortFilter(false);
|
displayModel->setDynamicSortFilter(false);
|
||||||
view = new QTreeView;
|
view = new QTreeView;
|
||||||
view->setModel(displayModel);
|
view->setModel(displayModel);
|
||||||
|
view->setMinimumSize(QSize(500, 250));
|
||||||
|
|
||||||
view->setAlternatingRowColors(true);
|
view->setAlternatingRowColors(true);
|
||||||
view->setUniformRowHeights(true);
|
view->setUniformRowHeights(true);
|
||||||
|
|
@ -128,16 +129,17 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
||||||
labNotes->setWordWrap(true);
|
labNotes->setWordWrap(true);
|
||||||
labNotes->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
labNotes->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||||
labNotes->setOpenExternalLinks(true);
|
labNotes->setOpenExternalLinks(true);
|
||||||
labNotes->setText("<b>" + tr("Deck Editor") + ":</b> " +
|
labNotes->setText(tr("Use CTRL+A to select all sets in the view.") + "<br><b>" + tr("Deck Editor") + ":</b> " +
|
||||||
tr("Only cards in enabled sets will appear in the card list of the deck editor") + "<br><br>" +
|
tr("Only cards in enabled sets will appear in the card list of the deck editor.") + "<br><b>" +
|
||||||
"<b>" + tr("Card Art") + ":</b> " + tr("Image priority is decided in the following order") +
|
tr("Card Art") + ":</b> " + tr("Image priority is decided in the following order:") + "<br>" +
|
||||||
"<ol><li>" + tr("CUSTOM Folder") +
|
tr("first the CUSTOM Folder (%1), then the Enabled Sets in this dialog (Top to Bottom)",
|
||||||
" (<a href='https://github.com/Cockatrice/Cockatrice/wiki/Custom-Cards-%26-Sets"
|
"%1 is a link to the wiki")
|
||||||
|
.arg("<a href='https://github.com/Cockatrice/Cockatrice/wiki/Custom-Cards-%26-Sets"
|
||||||
"#to-add-custom-art-for-cards-the-easiest-way-is-to-use-the-custom-folder'>" +
|
"#to-add-custom-art-for-cards-the-easiest-way-is-to-use-the-custom-folder'>" +
|
||||||
tr("How to use custom card art") + "</a>)</li><li>" + tr("Enabled Sets (Top to Bottom)") +
|
tr("How to use custom card art") + "</a>"));
|
||||||
"</li><li>" + tr("Disabled Sets (Top to Bottom)") + "</li></ol>");
|
|
||||||
|
|
||||||
QGridLayout *hintsGrid = new QGridLayout;
|
QGridLayout *hintsGrid = new QGridLayout;
|
||||||
|
hintsGrid->setMargin(2);
|
||||||
hintsGrid->addWidget(labNotes, 0, 0);
|
hintsGrid->addWidget(labNotes, 0, 0);
|
||||||
hintsGroupBox = new QGroupBox(tr("Hints"));
|
hintsGroupBox = new QGroupBox(tr("Hints"));
|
||||||
hintsGroupBox->setLayout(hintsGrid);
|
hintsGroupBox->setLayout(hintsGrid);
|
||||||
|
|
@ -163,8 +165,8 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
||||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(actRestore()));
|
connect(buttonBox, SIGNAL(rejected()), this, SLOT(actRestore()));
|
||||||
|
|
||||||
mainLayout = new QGridLayout;
|
mainLayout = new QGridLayout;
|
||||||
mainLayout->addWidget(setsEditToolBar, 1, 0, 2, 1);
|
|
||||||
mainLayout->addLayout(filterBox, 0, 1, 1, 2);
|
mainLayout->addLayout(filterBox, 0, 1, 1, 2);
|
||||||
|
mainLayout->addWidget(setsEditToolBar, 1, 0, 2, 1);
|
||||||
mainLayout->addWidget(view, 1, 1, 1, 2);
|
mainLayout->addWidget(view, 1, 1, 1, 2);
|
||||||
mainLayout->addWidget(enableAllButton, 2, 1);
|
mainLayout->addWidget(enableAllButton, 2, 1);
|
||||||
mainLayout->addWidget(disableAllButton, 2, 2);
|
mainLayout->addWidget(disableAllButton, 2, 2);
|
||||||
|
|
@ -184,7 +186,7 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
||||||
setCentralWidget(centralWidget);
|
setCentralWidget(centralWidget);
|
||||||
|
|
||||||
setWindowTitle(tr("Manage sets"));
|
setWindowTitle(tr("Manage sets"));
|
||||||
resize(700, 400);
|
resize(800, 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
WndSets::~WndSets()
|
WndSets::~WndSets()
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef WINDOW_SETS_H
|
#ifndef DLG_MANAGE_SETS_H
|
||||||
#define WINDOW_SETS_H
|
#define DLG_MANAGE_SETS_H
|
||||||
|
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QGridLayout>
|
#include <QGridLayout>
|
||||||
|
|
@ -14,20 +14,24 @@
|
||||||
DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
|
DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
|
||||||
{
|
{
|
||||||
ServersSettings &servers = SettingsCache::instance().servers();
|
ServersSettings &servers = SettingsCache::instance().servers();
|
||||||
|
infoLabel = new QLabel(tr("Enter your information and the information of the server you'd like to register to.\n"
|
||||||
|
"Your email will be used to verify your account."));
|
||||||
|
infoLabel->setWordWrap(true);
|
||||||
|
|
||||||
hostLabel = new QLabel(tr("&Host:"));
|
hostLabel = new QLabel(tr("&Host:"));
|
||||||
hostEdit = new QLineEdit(servers.getHostname("server.cockatrice.us"));
|
hostEdit = new QLineEdit(servers.getHostname());
|
||||||
hostLabel->setBuddy(hostEdit);
|
hostLabel->setBuddy(hostEdit);
|
||||||
|
|
||||||
portLabel = new QLabel(tr("&Port:"));
|
portLabel = new QLabel(tr("&Port:"));
|
||||||
portEdit = new QLineEdit(servers.getPort("4747"));
|
portEdit = new QLineEdit(servers.getPort());
|
||||||
portLabel->setBuddy(portEdit);
|
portLabel->setBuddy(portEdit);
|
||||||
|
|
||||||
playernameLabel = new QLabel(tr("Player &name:"));
|
playernameLabel = new QLabel(tr("Player &name:"));
|
||||||
playernameEdit = new QLineEdit(servers.getPlayerName("Player"));
|
playernameEdit = new QLineEdit(servers.getPlayerName());
|
||||||
playernameLabel->setBuddy(playernameEdit);
|
playernameLabel->setBuddy(playernameEdit);
|
||||||
|
|
||||||
passwordLabel = new QLabel(tr("P&assword:"));
|
passwordLabel = new QLabel(tr("P&assword:"));
|
||||||
passwordEdit = new QLineEdit(servers.getPassword());
|
passwordEdit = new QLineEdit();
|
||||||
passwordLabel->setBuddy(passwordEdit);
|
passwordLabel->setBuddy(passwordEdit);
|
||||||
passwordEdit->setEchoMode(QLineEdit::Password);
|
passwordEdit->setEchoMode(QLineEdit::Password);
|
||||||
|
|
||||||
|
|
@ -307,24 +311,25 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
|
||||||
realnameLabel->setBuddy(realnameEdit);
|
realnameLabel->setBuddy(realnameEdit);
|
||||||
|
|
||||||
QGridLayout *grid = new QGridLayout;
|
QGridLayout *grid = new QGridLayout;
|
||||||
grid->addWidget(hostLabel, 0, 0);
|
grid->addWidget(infoLabel, 0, 0, 1, 2);
|
||||||
grid->addWidget(hostEdit, 0, 1);
|
grid->addWidget(hostLabel, 1, 0);
|
||||||
grid->addWidget(portLabel, 1, 0);
|
grid->addWidget(hostEdit, 1, 1);
|
||||||
grid->addWidget(portEdit, 1, 1);
|
grid->addWidget(portLabel, 2, 0);
|
||||||
grid->addWidget(playernameLabel, 2, 0);
|
grid->addWidget(portEdit, 2, 1);
|
||||||
grid->addWidget(playernameEdit, 2, 1);
|
grid->addWidget(playernameLabel, 3, 0);
|
||||||
grid->addWidget(passwordLabel, 3, 0);
|
grid->addWidget(playernameEdit, 3, 1);
|
||||||
grid->addWidget(passwordEdit, 3, 1);
|
grid->addWidget(passwordLabel, 4, 0);
|
||||||
grid->addWidget(passwordConfirmationLabel, 4, 0);
|
grid->addWidget(passwordEdit, 4, 1);
|
||||||
grid->addWidget(passwordConfirmationEdit, 4, 1);
|
grid->addWidget(passwordConfirmationLabel, 5, 0);
|
||||||
grid->addWidget(emailLabel, 5, 0);
|
grid->addWidget(passwordConfirmationEdit, 5, 1);
|
||||||
grid->addWidget(emailEdit, 5, 1);
|
grid->addWidget(emailLabel, 6, 0);
|
||||||
grid->addWidget(emailConfirmationLabel, 6, 0);
|
grid->addWidget(emailEdit, 6, 1);
|
||||||
grid->addWidget(emailConfirmationEdit, 6, 1);
|
grid->addWidget(emailConfirmationLabel, 7, 0);
|
||||||
grid->addWidget(countryLabel, 8, 0);
|
grid->addWidget(emailConfirmationEdit, 7, 1);
|
||||||
grid->addWidget(countryEdit, 8, 1);
|
grid->addWidget(countryLabel, 9, 0);
|
||||||
grid->addWidget(realnameLabel, 9, 0);
|
grid->addWidget(countryEdit, 9, 1);
|
||||||
grid->addWidget(realnameEdit, 9, 1);
|
grid->addWidget(realnameLabel, 10, 0);
|
||||||
|
grid->addWidget(realnameEdit, 10, 1);
|
||||||
|
|
||||||
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
connect(buttonBox, SIGNAL(accepted()), this, SLOT(actOk()));
|
||||||
|
|
@ -355,12 +360,5 @@ void DlgRegister::actOk()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServersSettings &servers = SettingsCache::instance().servers();
|
|
||||||
servers.setHostName(hostEdit->text());
|
|
||||||
servers.setPort(portEdit->text());
|
|
||||||
servers.setPlayerName(playernameEdit->text());
|
|
||||||
// always save the password so it will be picked up by the connect dialog
|
|
||||||
servers.setPassword(passwordEdit->text());
|
|
||||||
|
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,8 +50,8 @@ private slots:
|
||||||
void actOk();
|
void actOk();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel *hostLabel, *portLabel, *playernameLabel, *passwordLabel, *passwordConfirmationLabel, *emailLabel,
|
QLabel *infoLabel, *hostLabel, *portLabel, *playernameLabel, *passwordLabel, *passwordConfirmationLabel,
|
||||||
*emailConfirmationLabel, *countryLabel, *realnameLabel;
|
*emailLabel, *emailConfirmationLabel, *countryLabel, *realnameLabel;
|
||||||
QLineEdit *hostEdit, *portEdit, *playernameEdit, *passwordEdit, *passwordConfirmationEdit, *emailEdit,
|
QLineEdit *hostEdit, *portEdit, *playernameEdit, *passwordEdit, *passwordConfirmationEdit, *emailEdit,
|
||||||
*emailConfirmationEdit, *realnameEdit;
|
*emailConfirmationEdit, *realnameEdit;
|
||||||
QComboBox *countryEdit;
|
QComboBox *countryEdit;
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QDesktopServices>
|
||||||
#include <QDesktopWidget>
|
#include <QDesktopWidget>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
|
|
@ -291,10 +292,12 @@ AppearanceSettingsPage::AppearanceSettingsPage()
|
||||||
}
|
}
|
||||||
|
|
||||||
connect(&themeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(themeBoxChanged(int)));
|
connect(&themeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(themeBoxChanged(int)));
|
||||||
|
connect(&openThemeButton, SIGNAL(clicked()), this, SLOT(openThemeLocation()));
|
||||||
|
|
||||||
auto *themeGrid = new QGridLayout;
|
auto *themeGrid = new QGridLayout;
|
||||||
themeGrid->addWidget(&themeLabel, 0, 0);
|
themeGrid->addWidget(&themeLabel, 0, 0);
|
||||||
themeGrid->addWidget(&themeBox, 0, 1);
|
themeGrid->addWidget(&themeBox, 0, 1);
|
||||||
|
themeGrid->addWidget(&openThemeButton, 1, 1);
|
||||||
|
|
||||||
themeGroupBox = new QGroupBox;
|
themeGroupBox = new QGroupBox;
|
||||||
themeGroupBox->setLayout(themeGrid);
|
themeGroupBox->setLayout(themeGrid);
|
||||||
|
|
@ -370,10 +373,24 @@ void AppearanceSettingsPage::themeBoxChanged(int index)
|
||||||
SettingsCache::instance().setThemeName(themeDirs.at(index));
|
SettingsCache::instance().setThemeName(themeDirs.at(index));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AppearanceSettingsPage::openThemeLocation()
|
||||||
|
{
|
||||||
|
QString dir = SettingsCache::instance().getThemesPath();
|
||||||
|
QDir dirDir = dir;
|
||||||
|
dirDir.cdUp();
|
||||||
|
// open if dir exists, create if parent dir does exist
|
||||||
|
if (dirDir.exists() && dirDir.mkpath(dir)) {
|
||||||
|
QDesktopServices::openUrl(QUrl::fromLocalFile(dir));
|
||||||
|
} else {
|
||||||
|
QMessageBox::critical(this, tr("Error"), tr("Could not create themes directory at '%1'.").arg(dir));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void AppearanceSettingsPage::retranslateUi()
|
void AppearanceSettingsPage::retranslateUi()
|
||||||
{
|
{
|
||||||
themeGroupBox->setTitle(tr("Theme settings"));
|
themeGroupBox->setTitle(tr("Theme settings"));
|
||||||
themeLabel.setText(tr("Current theme:"));
|
themeLabel.setText(tr("Current theme:"));
|
||||||
|
openThemeButton.setText(tr("Open themes folder"));
|
||||||
|
|
||||||
cardsGroupBox->setTitle(tr("Card rendering"));
|
cardsGroupBox->setTitle(tr("Card rendering"));
|
||||||
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
|
displayCardNamesCheckBox.setText(tr("Display card names on cards having a picture"));
|
||||||
|
|
@ -394,7 +411,7 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
|
||||||
notificationsEnabledCheckBox.setChecked(SettingsCache::instance().getNotificationsEnabled());
|
notificationsEnabledCheckBox.setChecked(SettingsCache::instance().getNotificationsEnabled());
|
||||||
connect(¬ificationsEnabledCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(),
|
connect(¬ificationsEnabledCheckBox, SIGNAL(stateChanged(int)), &SettingsCache::instance(),
|
||||||
SLOT(setNotificationsEnabled(int)));
|
SLOT(setNotificationsEnabled(int)));
|
||||||
connect(¬ificationsEnabledCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setSpecNotificationEnabled(int)));
|
connect(¬ificationsEnabledCheckBox, SIGNAL(stateChanged(int)), this, SLOT(setNotificationEnabled(int)));
|
||||||
|
|
||||||
specNotificationsEnabledCheckBox.setChecked(SettingsCache::instance().getSpectatorNotificationsEnabled());
|
specNotificationsEnabledCheckBox.setChecked(SettingsCache::instance().getSpectatorNotificationsEnabled());
|
||||||
specNotificationsEnabledCheckBox.setEnabled(SettingsCache::instance().getNotificationsEnabled());
|
specNotificationsEnabledCheckBox.setEnabled(SettingsCache::instance().getNotificationsEnabled());
|
||||||
|
|
@ -456,9 +473,14 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserInterfaceSettingsPage::setSpecNotificationEnabled(int i)
|
void UserInterfaceSettingsPage::setNotificationEnabled(int i)
|
||||||
{
|
{
|
||||||
specNotificationsEnabledCheckBox.setEnabled(i != 0);
|
specNotificationsEnabledCheckBox.setEnabled(i != 0);
|
||||||
|
buddyConnectNotificationsEnabledCheckBox.setEnabled(i != 0);
|
||||||
|
if (i == 0) {
|
||||||
|
specNotificationsEnabledCheckBox.setChecked(false);
|
||||||
|
buddyConnectNotificationsEnabledCheckBox.setChecked(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UserInterfaceSettingsPage::retranslateUi()
|
void UserInterfaceSettingsPage::retranslateUi()
|
||||||
|
|
|
||||||
|
|
@ -79,10 +79,12 @@ class AppearanceSettingsPage : public AbstractSettingsPage
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private slots:
|
private slots:
|
||||||
void themeBoxChanged(int index);
|
void themeBoxChanged(int index);
|
||||||
|
void openThemeLocation();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QLabel themeLabel;
|
QLabel themeLabel;
|
||||||
QComboBox themeBox;
|
QComboBox themeBox;
|
||||||
|
QPushButton openThemeButton;
|
||||||
QLabel minPlayersForMultiColumnLayoutLabel;
|
QLabel minPlayersForMultiColumnLayoutLabel;
|
||||||
QLabel maxFontSizeForCardsLabel;
|
QLabel maxFontSizeForCardsLabel;
|
||||||
QCheckBox displayCardNamesCheckBox;
|
QCheckBox displayCardNamesCheckBox;
|
||||||
|
|
@ -106,7 +108,7 @@ class UserInterfaceSettingsPage : public AbstractSettingsPage
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
private slots:
|
private slots:
|
||||||
void setSpecNotificationEnabled(int);
|
void setNotificationEnabled(int);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QCheckBox notificationsEnabledCheckBox;
|
QCheckBox notificationsEnabledCheckBox;
|
||||||
|
|
|
||||||
|
|
@ -45,13 +45,17 @@ DlgUpdate::DlgUpdate(QWidget *parent) : QDialog(parent)
|
||||||
connect(stopDownload, SIGNAL(clicked()), this, SLOT(cancelDownload()));
|
connect(stopDownload, SIGNAL(clicked()), this, SLOT(cancelDownload()));
|
||||||
connect(ok, SIGNAL(clicked()), this, SLOT(closeDialog()));
|
connect(ok, SIGNAL(clicked()), this, SLOT(closeDialog()));
|
||||||
|
|
||||||
QVBoxLayout *parentLayout = new QVBoxLayout(this);
|
auto *parentLayout = new QVBoxLayout(this);
|
||||||
parentLayout->addWidget(descriptionLabel);
|
parentLayout->addWidget(descriptionLabel);
|
||||||
parentLayout->addWidget(statusLabel);
|
parentLayout->addWidget(statusLabel);
|
||||||
parentLayout->addWidget(progress);
|
parentLayout->addWidget(progress);
|
||||||
parentLayout->addWidget(buttonBox);
|
parentLayout->addWidget(buttonBox);
|
||||||
|
|
||||||
setLayout(parentLayout);
|
setLayout(parentLayout);
|
||||||
|
setWindowTitle(tr("Check for Client Updates"));
|
||||||
|
|
||||||
|
setFixedHeight(this->sizeHint().height());
|
||||||
|
setFixedWidth(this->sizeHint().width());
|
||||||
|
|
||||||
// Check for SSL (this probably isn't necessary)
|
// Check for SSL (this probably isn't necessary)
|
||||||
if (!QSslSocket::supportsSsl()) {
|
if (!QSslSocket::supportsSsl()) {
|
||||||
|
|
@ -140,7 +144,7 @@ void DlgUpdate::finishedUpdateCheck(bool needToUpdate, bool isCompatible, Releas
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
publishDate = release->getPublishDate().toString(Qt::DefaultLocaleLongDate);
|
publishDate = release->getPublishDate().toString(QLocale().dateFormat(QLocale::LongFormat));
|
||||||
if (isCompatible) {
|
if (isCompatible) {
|
||||||
int reply;
|
int reply;
|
||||||
reply = QMessageBox::question(
|
reply = QMessageBox::question(
|
||||||
|
|
@ -190,19 +194,19 @@ void DlgUpdate::enableOkButton(bool enable)
|
||||||
ok->setEnabled(enable);
|
ok->setEnabled(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgUpdate::setLabel(QString newText)
|
void DlgUpdate::setLabel(const QString &newText)
|
||||||
{
|
{
|
||||||
statusLabel->setText(newText);
|
statusLabel->setText(newText);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgUpdate::updateCheckError(QString errorString)
|
void DlgUpdate::updateCheckError(const QString &errorString)
|
||||||
{
|
{
|
||||||
setLabel(tr("Error"));
|
setLabel(tr("Error"));
|
||||||
QMessageBox::critical(this, tr("Update Error"),
|
QMessageBox::critical(this, tr("Update Error"),
|
||||||
tr("An error occurred while checking for updates:") + QString(" ") + errorString);
|
tr("An error occurred while checking for updates:") + QString(" ") + errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgUpdate::downloadError(QString errorString)
|
void DlgUpdate::downloadError(const QString &errorString)
|
||||||
{
|
{
|
||||||
setLabel(tr("Error"));
|
setLabel(tr("Error"));
|
||||||
enableUpdateButton(true);
|
enableUpdateButton(true);
|
||||||
|
|
@ -210,7 +214,7 @@ void DlgUpdate::downloadError(QString errorString)
|
||||||
tr("An error occurred while downloading an update:") + QString(" ") + errorString);
|
tr("An error occurred while downloading an update:") + QString(" ") + errorString);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgUpdate::downloadSuccessful(QUrl filepath)
|
void DlgUpdate::downloadSuccessful(const QUrl &filepath)
|
||||||
{
|
{
|
||||||
setLabel(tr("Installing..."));
|
setLabel(tr("Installing..."));
|
||||||
// Try to open the installer. If it opens, quit Cockatrice
|
// Try to open the installer. If it opens, quit Cockatrice
|
||||||
|
|
|
||||||
|
|
@ -19,10 +19,10 @@ private slots:
|
||||||
void gotoDownloadPage();
|
void gotoDownloadPage();
|
||||||
void downloadUpdate();
|
void downloadUpdate();
|
||||||
void cancelDownload();
|
void cancelDownload();
|
||||||
void updateCheckError(QString errorString);
|
void updateCheckError(const QString &errorString);
|
||||||
void downloadSuccessful(QUrl filepath);
|
void downloadSuccessful(const QUrl &filepath);
|
||||||
void downloadProgressMade(qint64 bytesRead, qint64 totalBytes);
|
void downloadProgressMade(qint64 bytesRead, qint64 totalBytes);
|
||||||
void downloadError(QString errorString);
|
void downloadError(const QString &errorString);
|
||||||
void closeDialog();
|
void closeDialog();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
@ -31,7 +31,7 @@ private:
|
||||||
void enableOkButton(bool enable);
|
void enableOkButton(bool enable);
|
||||||
void addStopDownloadAndRemoveOthers(bool enable);
|
void addStopDownloadAndRemoveOthers(bool enable);
|
||||||
void beginUpdateCheck();
|
void beginUpdateCheck();
|
||||||
void setLabel(QString text);
|
void setLabel(const QString &text);
|
||||||
QLabel *statusLabel, *descriptionLabel;
|
QLabel *statusLabel, *descriptionLabel;
|
||||||
QProgressBar *progress;
|
QProgressBar *progress;
|
||||||
QPushButton *manualDownload, *gotoDownload, *ok, *stopDownload;
|
QPushButton *manualDownload, *gotoDownload, *ok, *stopDownload;
|
||||||
|
|
|
||||||
|
|
@ -144,12 +144,10 @@ void GameScene::rearrange()
|
||||||
|
|
||||||
void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numberCards)
|
void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numberCards)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < zoneViews.size(); i++) {
|
for (auto &view : zoneViews) {
|
||||||
ZoneViewZone *temp = zoneViews[i]->getZone();
|
ZoneViewZone *temp = view->getZone();
|
||||||
if ((temp->getName() == zoneName) && (temp->getPlayer() == player)) { // view is already open
|
if (temp->getName() == zoneName && temp->getPlayer() == player && temp->getNumberCards() == numberCards) {
|
||||||
zoneViews[i]->close();
|
view->close();
|
||||||
if (temp->getNumberCards() == numberCards)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,12 +155,13 @@ void GameScene::toggleZoneView(Player *player, const QString &zoneName, int numb
|
||||||
zoneViews.append(item);
|
zoneViews.append(item);
|
||||||
connect(item, SIGNAL(closePressed(ZoneViewWidget *)), this, SLOT(removeZoneView(ZoneViewWidget *)));
|
connect(item, SIGNAL(closePressed(ZoneViewWidget *)), this, SLOT(removeZoneView(ZoneViewWidget *)));
|
||||||
addItem(item);
|
addItem(item);
|
||||||
if (zoneName == "grave")
|
if (zoneName == "grave") {
|
||||||
item->setPos(360, 100);
|
item->setPos(360, 100);
|
||||||
else if (zoneName == "rfg")
|
} else if (zoneName == "rfg") {
|
||||||
item->setPos(380, 120);
|
item->setPos(380, 120);
|
||||||
else
|
} else {
|
||||||
item->setPos(340, 80);
|
item->setPos(340, 80);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameScene::addRevealedZoneView(Player *player,
|
void GameScene::addRevealedZoneView(Player *player,
|
||||||
|
|
|
||||||
|
|
@ -8,9 +8,9 @@
|
||||||
#include "pb/room_commands.pb.h"
|
#include "pb/room_commands.pb.h"
|
||||||
#include "pb/serverinfo_game.pb.h"
|
#include "pb/serverinfo_game.pb.h"
|
||||||
#include "pending_command.h"
|
#include "pending_command.h"
|
||||||
|
#include "tab_account.h"
|
||||||
#include "tab_room.h"
|
#include "tab_room.h"
|
||||||
#include "tab_supervisor.h"
|
#include "tab_supervisor.h"
|
||||||
#include "tab_userlists.h"
|
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
|
|
@ -74,18 +74,16 @@ GameSelector::GameSelector(AbstractClient *_client,
|
||||||
connect(filterButton, SIGNAL(clicked()), this, SLOT(actSetFilter()));
|
connect(filterButton, SIGNAL(clicked()), this, SLOT(actSetFilter()));
|
||||||
clearFilterButton = new QPushButton;
|
clearFilterButton = new QPushButton;
|
||||||
clearFilterButton->setIcon(QPixmap("theme:icons/clearsearch"));
|
clearFilterButton->setIcon(QPixmap("theme:icons/clearsearch"));
|
||||||
if (showFilters && gameListProxyModel->areFilterParametersSetToDefaults()) {
|
bool filtersSetToDefault = showFilters && gameListProxyModel->areFilterParametersSetToDefaults();
|
||||||
clearFilterButton->setEnabled(false);
|
clearFilterButton->setEnabled(!filtersSetToDefault);
|
||||||
} else {
|
|
||||||
clearFilterButton->setEnabled(true);
|
|
||||||
}
|
|
||||||
connect(clearFilterButton, SIGNAL(clicked()), this, SLOT(actClearFilter()));
|
connect(clearFilterButton, SIGNAL(clicked()), this, SLOT(actClearFilter()));
|
||||||
|
|
||||||
if (room) {
|
if (room) {
|
||||||
createButton = new QPushButton;
|
createButton = new QPushButton;
|
||||||
connect(createButton, SIGNAL(clicked()), this, SLOT(actCreate()));
|
connect(createButton, SIGNAL(clicked()), this, SLOT(actCreate()));
|
||||||
} else
|
} else {
|
||||||
createButton = 0;
|
createButton = nullptr;
|
||||||
|
}
|
||||||
joinButton = new QPushButton;
|
joinButton = new QPushButton;
|
||||||
spectateButton = new QPushButton;
|
spectateButton = new QPushButton;
|
||||||
|
|
||||||
|
|
@ -154,13 +152,19 @@ void GameSelector::actSetFilter()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
gameListProxyModel->setShowBuddiesOnlyGames(dlg.getShowBuddiesOnlyGames());
|
gameListProxyModel->setShowBuddiesOnlyGames(dlg.getShowBuddiesOnlyGames());
|
||||||
gameListProxyModel->setUnavailableGamesVisible(dlg.getUnavailableGamesVisible());
|
gameListProxyModel->setShowFullGames(dlg.getShowFullGames());
|
||||||
|
gameListProxyModel->setShowGamesThatStarted(dlg.getShowGamesThatStarted());
|
||||||
gameListProxyModel->setShowPasswordProtectedGames(dlg.getShowPasswordProtectedGames());
|
gameListProxyModel->setShowPasswordProtectedGames(dlg.getShowPasswordProtectedGames());
|
||||||
gameListProxyModel->setHideIgnoredUserGames(dlg.getHideIgnoredUserGames());
|
gameListProxyModel->setHideIgnoredUserGames(dlg.getHideIgnoredUserGames());
|
||||||
gameListProxyModel->setGameNameFilter(dlg.getGameNameFilter());
|
gameListProxyModel->setGameNameFilter(dlg.getGameNameFilter());
|
||||||
gameListProxyModel->setCreatorNameFilter(dlg.getCreatorNameFilter());
|
gameListProxyModel->setCreatorNameFilter(dlg.getCreatorNameFilter());
|
||||||
gameListProxyModel->setGameTypeFilter(dlg.getGameTypeFilter());
|
gameListProxyModel->setGameTypeFilter(dlg.getGameTypeFilter());
|
||||||
gameListProxyModel->setMaxPlayersFilter(dlg.getMaxPlayersFilterMin(), dlg.getMaxPlayersFilterMax());
|
gameListProxyModel->setMaxPlayersFilter(dlg.getMaxPlayersFilterMin(), dlg.getMaxPlayersFilterMax());
|
||||||
|
gameListProxyModel->setMaxGameAge(dlg.getMaxGameAge());
|
||||||
|
gameListProxyModel->setShowOnlyIfSpectatorsCanWatch(dlg.getShowOnlyIfSpectatorsCanWatch());
|
||||||
|
gameListProxyModel->setShowSpectatorPasswordProtected(dlg.getShowSpectatorPasswordProtected());
|
||||||
|
gameListProxyModel->setShowOnlyIfSpectatorsCanChat(dlg.getShowOnlyIfSpectatorsCanChat());
|
||||||
|
gameListProxyModel->setShowOnlyIfSpectatorsCanSeeHands(dlg.getShowOnlyIfSpectatorsCanSeeHands());
|
||||||
gameListProxyModel->saveFilterParameters(gameTypeMap);
|
gameListProxyModel->saveFilterParameters(gameTypeMap);
|
||||||
|
|
||||||
clearFilterButton->setEnabled(!gameListProxyModel->areFilterParametersSetToDefaults());
|
clearFilterButton->setEnabled(!gameListProxyModel->areFilterParametersSetToDefaults());
|
||||||
|
|
|
||||||
|
|
@ -3,13 +3,14 @@
|
||||||
#include "pb/serverinfo_game.pb.h"
|
#include "pb/serverinfo_game.pb.h"
|
||||||
#include "pixmapgenerator.h"
|
#include "pixmapgenerator.h"
|
||||||
#include "settingscache.h"
|
#include "settingscache.h"
|
||||||
#include "tab_userlists.h"
|
#include "tab_account.h"
|
||||||
#include "userlist.h"
|
#include "userlist.h"
|
||||||
|
|
||||||
#include <QDateTime>
|
#include <QDateTime>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QIcon>
|
#include <QIcon>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QTime>
|
||||||
|
|
||||||
enum GameListColumn
|
enum GameListColumn
|
||||||
{
|
{
|
||||||
|
|
@ -23,25 +24,50 @@ enum GameListColumn
|
||||||
SPECTATORS
|
SPECTATORS
|
||||||
};
|
};
|
||||||
|
|
||||||
const QString GamesModel::getGameCreatedString(const int secs) const
|
const bool DEFAULT_SHOW_FULL_GAMES = false;
|
||||||
{
|
const bool DEFAULT_SHOW_GAMES_THAT_STARTED = false;
|
||||||
|
const bool DEFAULT_SHOW_PASSWORD_PROTECTED_GAMES = true;
|
||||||
|
const bool DEFAULT_SHOW_BUDDIES_ONLY_GAMES = true;
|
||||||
|
const bool DEFAULT_HIDE_IGNORED_USER_GAMES = false;
|
||||||
|
const bool DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_WATCH = false;
|
||||||
|
const bool DEFAULT_SHOW_SPECTATOR_PASSWORD_PROTECTED = true;
|
||||||
|
const bool DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_CHAT = false;
|
||||||
|
const bool DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_SEE_HANDS = false;
|
||||||
|
const int DEFAULT_MAX_PLAYERS_MIN = 1;
|
||||||
|
const int DEFAULT_MAX_PLAYERS_MAX = 99;
|
||||||
|
constexpr QTime DEFAULT_MAX_GAME_AGE = QTime();
|
||||||
|
|
||||||
QString ret;
|
const QString GamesModel::getGameCreatedString(const int secs)
|
||||||
if (secs < SECS_PER_MIN * 2) // for first min we display "New"
|
{
|
||||||
ret = tr("New");
|
static const QTime zeroTime{0, 0};
|
||||||
else if (secs < SECS_PER_MIN * 10) // from 2 - 10 mins we show the mins
|
static const int halfHourSecs = zeroTime.secsTo(QTime(1, 0)) / 2;
|
||||||
ret = QString("%1 min").arg(QString::number(secs / SECS_PER_MIN));
|
static const int halfMinSecs = zeroTime.secsTo(QTime(0, 1)) / 2;
|
||||||
else if (secs < SECS_PER_MIN * 60) { // from 10 mins to 1h we aggregate every 10 mins
|
static const int wrapSeconds = zeroTime.secsTo(zeroTime.addSecs(-halfHourSecs)); // round up
|
||||||
int unitOfTen = secs / SECS_PER_TEN_MIN;
|
|
||||||
QString str = "%1%2";
|
if (secs >= wrapSeconds) { // QTime wraps after a day
|
||||||
ret = str.arg(QString::number(unitOfTen), "0+ min");
|
return tr(">1 day");
|
||||||
} else { // from 1 hr onward we show hrs
|
|
||||||
int hours = secs / SECS_PER_HOUR;
|
|
||||||
if (secs % SECS_PER_HOUR >= SECS_PER_MIN * 30) // if the room is open for 1hr 30 mins, we round to 2hrs
|
|
||||||
++hours;
|
|
||||||
ret = QString("%1+ h").arg(QString::number(hours));
|
|
||||||
}
|
}
|
||||||
return ret;
|
|
||||||
|
QTime total = zeroTime.addSecs(secs);
|
||||||
|
QTime totalRounded = total.addSecs(halfMinSecs); // round up
|
||||||
|
QString form;
|
||||||
|
int amount;
|
||||||
|
if (totalRounded.hour()) {
|
||||||
|
amount = total.addSecs(halfHourSecs).hour(); // round up separately
|
||||||
|
form = tr("%1%2 hr", "short age in hours", amount);
|
||||||
|
} else if (total.minute() < 2) { // games are new during their first minute
|
||||||
|
return tr("new");
|
||||||
|
} else {
|
||||||
|
amount = totalRounded.minute();
|
||||||
|
form = tr("%1%2 min", "short age in minutes", amount);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int aggregate : {40, 20, 10, 5}) { // floor to values in this list
|
||||||
|
if (amount >= aggregate) {
|
||||||
|
return form.arg(">").arg(aggregate);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return form.arg("").arg(amount);
|
||||||
}
|
}
|
||||||
|
|
||||||
GamesModel::GamesModel(const QMap<int, QString> &_rooms, const QMap<int, GameTypeMap> &_gameTypes, QObject *parent)
|
GamesModel::GamesModel(const QMap<int, QString> &_rooms, const QMap<int, GameTypeMap> &_gameTypes, QObject *parent)
|
||||||
|
|
@ -60,20 +86,23 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
|
||||||
if ((index.row() >= gameList.size()) || (index.column() >= columnCount()))
|
if ((index.row() >= gameList.size()) || (index.column() >= columnCount()))
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
const ServerInfo_Game &g = gameList[index.row()];
|
const ServerInfo_Game &gameentry = gameList[index.row()];
|
||||||
switch (index.column()) {
|
switch (index.column()) {
|
||||||
case ROOM:
|
case ROOM:
|
||||||
return rooms.value(g.room_id());
|
return rooms.value(gameentry.room_id());
|
||||||
case CREATED: {
|
case CREATED: {
|
||||||
QDateTime then;
|
|
||||||
then.setTime_t(g.start_time());
|
|
||||||
int secs = then.secsTo(QDateTime::currentDateTime());
|
|
||||||
|
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case Qt::DisplayRole:
|
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);
|
return getGameCreatedString(secs);
|
||||||
|
}
|
||||||
case SORT_ROLE:
|
case SORT_ROLE:
|
||||||
return QVariant(secs);
|
return QVariant(-static_cast<qint64>(gameentry.start_time()));
|
||||||
case Qt::TextAlignmentRole:
|
case Qt::TextAlignmentRole:
|
||||||
return Qt::AlignCenter;
|
return Qt::AlignCenter;
|
||||||
default:
|
default:
|
||||||
|
|
@ -84,7 +113,7 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case SORT_ROLE:
|
case SORT_ROLE:
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
return QString::fromStdString(g.description());
|
return QString::fromStdString(gameentry.description());
|
||||||
case Qt::TextAlignmentRole:
|
case Qt::TextAlignmentRole:
|
||||||
return Qt::AlignLeft;
|
return Qt::AlignLeft;
|
||||||
default:
|
default:
|
||||||
|
|
@ -94,11 +123,11 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case SORT_ROLE:
|
case SORT_ROLE:
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
return QString::fromStdString(g.creator_info().name());
|
return QString::fromStdString(gameentry.creator_info().name());
|
||||||
case Qt::DecorationRole: {
|
case Qt::DecorationRole: {
|
||||||
QPixmap avatarPixmap = UserLevelPixmapGenerator::generatePixmap(
|
QPixmap avatarPixmap = UserLevelPixmapGenerator::generatePixmap(
|
||||||
13, (UserLevelFlags)g.creator_info().user_level(), false,
|
13, (UserLevelFlags)gameentry.creator_info().user_level(), false,
|
||||||
QString::fromStdString(g.creator_info().privlevel()));
|
QString::fromStdString(gameentry.creator_info().privlevel()));
|
||||||
return QIcon(avatarPixmap);
|
return QIcon(avatarPixmap);
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|
@ -110,9 +139,9 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
|
||||||
case SORT_ROLE:
|
case SORT_ROLE:
|
||||||
case Qt::DisplayRole: {
|
case Qt::DisplayRole: {
|
||||||
QStringList result;
|
QStringList result;
|
||||||
GameTypeMap gameTypeMap = gameTypes.value(g.room_id());
|
GameTypeMap gameTypeMap = gameTypes.value(gameentry.room_id());
|
||||||
for (int i = g.game_types_size() - 1; i >= 0; --i)
|
for (int i = gameentry.game_types_size() - 1; i >= 0; --i)
|
||||||
result.append(gameTypeMap.value(g.game_types(i)));
|
result.append(gameTypeMap.value(gameentry.game_types(i)));
|
||||||
return result.join(", ");
|
return result.join(", ");
|
||||||
}
|
}
|
||||||
case Qt::TextAlignmentRole:
|
case Qt::TextAlignmentRole:
|
||||||
|
|
@ -125,16 +154,16 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
|
||||||
case SORT_ROLE:
|
case SORT_ROLE:
|
||||||
case Qt::DisplayRole: {
|
case Qt::DisplayRole: {
|
||||||
QStringList result;
|
QStringList result;
|
||||||
if (g.with_password())
|
if (gameentry.with_password())
|
||||||
result.append(tr("password"));
|
result.append(tr("password"));
|
||||||
if (g.only_buddies())
|
if (gameentry.only_buddies())
|
||||||
result.append(tr("buddies only"));
|
result.append(tr("buddies only"));
|
||||||
if (g.only_registered())
|
if (gameentry.only_registered())
|
||||||
result.append(tr("reg. users only"));
|
result.append(tr("reg. users only"));
|
||||||
return result.join(", ");
|
return result.join(", ");
|
||||||
}
|
}
|
||||||
case Qt::DecorationRole: {
|
case Qt::DecorationRole: {
|
||||||
return g.with_password() ? QIcon(LockPixmapGenerator::generatePixmap(13)) : QVariant();
|
return gameentry.with_password() ? QIcon(LockPixmapGenerator::generatePixmap(13)) : QVariant();
|
||||||
case Qt::TextAlignmentRole:
|
case Qt::TextAlignmentRole:
|
||||||
return Qt::AlignLeft;
|
return Qt::AlignLeft;
|
||||||
default:
|
default:
|
||||||
|
|
@ -145,7 +174,7 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case SORT_ROLE:
|
case SORT_ROLE:
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
return QString("%1/%2").arg(g.player_count()).arg(g.max_players());
|
return QString("%1/%2").arg(gameentry.player_count()).arg(gameentry.max_players());
|
||||||
case Qt::TextAlignmentRole:
|
case Qt::TextAlignmentRole:
|
||||||
return Qt::AlignCenter;
|
return Qt::AlignCenter;
|
||||||
default:
|
default:
|
||||||
|
|
@ -156,19 +185,19 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
|
||||||
switch (role) {
|
switch (role) {
|
||||||
case SORT_ROLE:
|
case SORT_ROLE:
|
||||||
case Qt::DisplayRole: {
|
case Qt::DisplayRole: {
|
||||||
if (g.spectators_allowed()) {
|
if (gameentry.spectators_allowed()) {
|
||||||
QString result;
|
QString result;
|
||||||
result.append(QString::number(g.spectators_count()));
|
result.append(QString::number(gameentry.spectators_count()));
|
||||||
|
|
||||||
if (g.spectators_can_chat() && g.spectators_omniscient()) {
|
if (gameentry.spectators_can_chat() && gameentry.spectators_omniscient()) {
|
||||||
result.append(" (")
|
result.append(" (")
|
||||||
.append(tr("can chat"))
|
.append(tr("can chat"))
|
||||||
.append(" & ")
|
.append(" & ")
|
||||||
.append(tr("see hands"))
|
.append(tr("see hands"))
|
||||||
.append(")");
|
.append(")");
|
||||||
} else if (g.spectators_can_chat()) {
|
} else if (gameentry.spectators_can_chat()) {
|
||||||
result.append(" (").append(tr("can chat")).append(")");
|
result.append(" (").append(tr("can chat")).append(")");
|
||||||
} else if (g.spectators_omniscient()) {
|
} else if (gameentry.spectators_omniscient()) {
|
||||||
result.append(" (").append(tr("can see hands")).append(")");
|
result.append(" (").append(tr("can see hands")).append(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -249,8 +278,6 @@ void GamesModel::updateGameList(const ServerInfo_Game &game)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (game.player_count() <= 0)
|
|
||||||
return;
|
|
||||||
beginInsertRows(QModelIndex(), gameList.size(), gameList.size());
|
beginInsertRows(QModelIndex(), gameList.size(), gameList.size());
|
||||||
gameList.append(game);
|
gameList.append(game);
|
||||||
endInsertRows();
|
endInsertRows();
|
||||||
|
|
@ -277,9 +304,15 @@ void GamesProxyModel::setHideIgnoredUserGames(bool _hideIgnoredUserGames)
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GamesProxyModel::setUnavailableGamesVisible(bool _unavailableGamesVisible)
|
void GamesProxyModel::setShowFullGames(bool _showFullGames)
|
||||||
{
|
{
|
||||||
unavailableGamesVisible = _unavailableGamesVisible;
|
showFullGames = _showFullGames;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GamesProxyModel::setShowGamesThatStarted(bool _showGamesThatStarted)
|
||||||
|
{
|
||||||
|
showGamesThatStarted = _showGamesThatStarted;
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -314,6 +347,36 @@ void GamesProxyModel::setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlay
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GamesProxyModel::setMaxGameAge(const QTime &_maxGameAge)
|
||||||
|
{
|
||||||
|
maxGameAge = _maxGameAge;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GamesProxyModel::setShowOnlyIfSpectatorsCanWatch(bool _showOnlyIfSpectatorsCanWatch)
|
||||||
|
{
|
||||||
|
showOnlyIfSpectatorsCanWatch = _showOnlyIfSpectatorsCanWatch;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GamesProxyModel::setShowSpectatorPasswordProtected(bool _showSpectatorPasswordProtected)
|
||||||
|
{
|
||||||
|
showSpectatorPasswordProtected = _showSpectatorPasswordProtected;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GamesProxyModel::setShowOnlyIfSpectatorsCanChat(bool _showOnlyIfSpectatorsCanChat)
|
||||||
|
{
|
||||||
|
showOnlyIfSpectatorsCanChat = _showOnlyIfSpectatorsCanChat;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GamesProxyModel::setShowOnlyIfSpectatorsCanSeeHands(bool _showOnlyIfSpectatorsCanSeeHands)
|
||||||
|
{
|
||||||
|
showOnlyIfSpectatorsCanSeeHands = _showOnlyIfSpectatorsCanSeeHands;
|
||||||
|
invalidateFilter();
|
||||||
|
}
|
||||||
|
|
||||||
int GamesProxyModel::getNumFilteredGames() const
|
int GamesProxyModel::getNumFilteredGames() const
|
||||||
{
|
{
|
||||||
GamesModel *model = qobject_cast<GamesModel *>(sourceModel());
|
GamesModel *model = qobject_cast<GamesModel *>(sourceModel());
|
||||||
|
|
@ -331,7 +394,8 @@ int GamesProxyModel::getNumFilteredGames() const
|
||||||
|
|
||||||
void GamesProxyModel::resetFilterParameters()
|
void GamesProxyModel::resetFilterParameters()
|
||||||
{
|
{
|
||||||
unavailableGamesVisible = DEFAULT_UNAVAILABLE_GAMES_VISIBLE;
|
showFullGames = DEFAULT_SHOW_FULL_GAMES;
|
||||||
|
showGamesThatStarted = DEFAULT_SHOW_GAMES_THAT_STARTED;
|
||||||
showPasswordProtectedGames = DEFAULT_SHOW_PASSWORD_PROTECTED_GAMES;
|
showPasswordProtectedGames = DEFAULT_SHOW_PASSWORD_PROTECTED_GAMES;
|
||||||
showBuddiesOnlyGames = DEFAULT_SHOW_BUDDIES_ONLY_GAMES;
|
showBuddiesOnlyGames = DEFAULT_SHOW_BUDDIES_ONLY_GAMES;
|
||||||
hideIgnoredUserGames = DEFAULT_HIDE_IGNORED_USER_GAMES;
|
hideIgnoredUserGames = DEFAULT_HIDE_IGNORED_USER_GAMES;
|
||||||
|
|
@ -340,24 +404,34 @@ void GamesProxyModel::resetFilterParameters()
|
||||||
gameTypeFilter.clear();
|
gameTypeFilter.clear();
|
||||||
maxPlayersFilterMin = DEFAULT_MAX_PLAYERS_MIN;
|
maxPlayersFilterMin = DEFAULT_MAX_PLAYERS_MIN;
|
||||||
maxPlayersFilterMax = DEFAULT_MAX_PLAYERS_MAX;
|
maxPlayersFilterMax = DEFAULT_MAX_PLAYERS_MAX;
|
||||||
|
maxGameAge = DEFAULT_MAX_GAME_AGE;
|
||||||
|
showOnlyIfSpectatorsCanWatch = DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_WATCH;
|
||||||
|
showSpectatorPasswordProtected = DEFAULT_SHOW_SPECTATOR_PASSWORD_PROTECTED;
|
||||||
|
showOnlyIfSpectatorsCanChat = DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_CHAT;
|
||||||
|
showOnlyIfSpectatorsCanSeeHands = DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_SEE_HANDS;
|
||||||
|
|
||||||
invalidateFilter();
|
invalidateFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GamesProxyModel::areFilterParametersSetToDefaults() const
|
bool GamesProxyModel::areFilterParametersSetToDefaults() const
|
||||||
{
|
{
|
||||||
return unavailableGamesVisible == DEFAULT_UNAVAILABLE_GAMES_VISIBLE &&
|
return showFullGames == DEFAULT_SHOW_FULL_GAMES && showGamesThatStarted == DEFAULT_SHOW_GAMES_THAT_STARTED &&
|
||||||
showPasswordProtectedGames == DEFAULT_SHOW_PASSWORD_PROTECTED_GAMES &&
|
showPasswordProtectedGames == DEFAULT_SHOW_PASSWORD_PROTECTED_GAMES &&
|
||||||
showBuddiesOnlyGames == DEFAULT_SHOW_BUDDIES_ONLY_GAMES &&
|
showBuddiesOnlyGames == DEFAULT_SHOW_BUDDIES_ONLY_GAMES &&
|
||||||
hideIgnoredUserGames == DEFAULT_HIDE_IGNORED_USER_GAMES && gameNameFilter.isEmpty() &&
|
hideIgnoredUserGames == DEFAULT_HIDE_IGNORED_USER_GAMES && gameNameFilter.isEmpty() &&
|
||||||
creatorNameFilter.isEmpty() && gameTypeFilter.isEmpty() && maxPlayersFilterMin == DEFAULT_MAX_PLAYERS_MIN &&
|
creatorNameFilter.isEmpty() && gameTypeFilter.isEmpty() && maxPlayersFilterMin == DEFAULT_MAX_PLAYERS_MIN &&
|
||||||
maxPlayersFilterMax == DEFAULT_MAX_PLAYERS_MAX;
|
maxPlayersFilterMax == DEFAULT_MAX_PLAYERS_MAX && maxGameAge == DEFAULT_MAX_GAME_AGE &&
|
||||||
|
showOnlyIfSpectatorsCanWatch == DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_WATCH &&
|
||||||
|
showSpectatorPasswordProtected == DEFAULT_SHOW_SPECTATOR_PASSWORD_PROTECTED &&
|
||||||
|
showOnlyIfSpectatorsCanChat == DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_CHAT &&
|
||||||
|
showOnlyIfSpectatorsCanSeeHands == DEFAULT_SHOW_ONLY_IF_SPECTATORS_CAN_SEE_HANDS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void GamesProxyModel::loadFilterParameters(const QMap<int, QString> &allGameTypes)
|
void GamesProxyModel::loadFilterParameters(const QMap<int, QString> &allGameTypes)
|
||||||
{
|
{
|
||||||
GameFiltersSettings &gameFilters = SettingsCache::instance().gameFilters();
|
GameFiltersSettings &gameFilters = SettingsCache::instance().gameFilters();
|
||||||
unavailableGamesVisible = gameFilters.isUnavailableGamesVisible();
|
showFullGames = gameFilters.isShowFullGames();
|
||||||
|
showGamesThatStarted = gameFilters.isShowGamesThatStarted();
|
||||||
showPasswordProtectedGames = gameFilters.isShowPasswordProtectedGames();
|
showPasswordProtectedGames = gameFilters.isShowPasswordProtectedGames();
|
||||||
hideIgnoredUserGames = gameFilters.isHideIgnoredUserGames();
|
hideIgnoredUserGames = gameFilters.isHideIgnoredUserGames();
|
||||||
showBuddiesOnlyGames = gameFilters.isShowBuddiesOnlyGames();
|
showBuddiesOnlyGames = gameFilters.isShowBuddiesOnlyGames();
|
||||||
|
|
@ -365,6 +439,11 @@ void GamesProxyModel::loadFilterParameters(const QMap<int, QString> &allGameType
|
||||||
creatorNameFilter = gameFilters.getCreatorNameFilter();
|
creatorNameFilter = gameFilters.getCreatorNameFilter();
|
||||||
maxPlayersFilterMin = gameFilters.getMinPlayers();
|
maxPlayersFilterMin = gameFilters.getMinPlayers();
|
||||||
maxPlayersFilterMax = gameFilters.getMaxPlayers();
|
maxPlayersFilterMax = gameFilters.getMaxPlayers();
|
||||||
|
maxGameAge = gameFilters.getMaxGameAge();
|
||||||
|
showOnlyIfSpectatorsCanWatch = gameFilters.isShowOnlyIfSpectatorsCanWatch();
|
||||||
|
showSpectatorPasswordProtected = gameFilters.isShowSpectatorPasswordProtected();
|
||||||
|
showOnlyIfSpectatorsCanChat = gameFilters.isShowOnlyIfSpectatorsCanChat();
|
||||||
|
showOnlyIfSpectatorsCanSeeHands = gameFilters.isShowOnlyIfSpectatorsCanSeeHands();
|
||||||
|
|
||||||
QMapIterator<int, QString> gameTypesIterator(allGameTypes);
|
QMapIterator<int, QString> gameTypesIterator(allGameTypes);
|
||||||
while (gameTypesIterator.hasNext()) {
|
while (gameTypesIterator.hasNext()) {
|
||||||
|
|
@ -381,7 +460,8 @@ void GamesProxyModel::saveFilterParameters(const QMap<int, QString> &allGameType
|
||||||
{
|
{
|
||||||
GameFiltersSettings &gameFilters = SettingsCache::instance().gameFilters();
|
GameFiltersSettings &gameFilters = SettingsCache::instance().gameFilters();
|
||||||
gameFilters.setShowBuddiesOnlyGames(showBuddiesOnlyGames);
|
gameFilters.setShowBuddiesOnlyGames(showBuddiesOnlyGames);
|
||||||
gameFilters.setUnavailableGamesVisible(unavailableGamesVisible);
|
gameFilters.setShowFullGames(showFullGames);
|
||||||
|
gameFilters.setShowGamesThatStarted(showGamesThatStarted);
|
||||||
gameFilters.setShowPasswordProtectedGames(showPasswordProtectedGames);
|
gameFilters.setShowPasswordProtectedGames(showPasswordProtectedGames);
|
||||||
gameFilters.setHideIgnoredUserGames(hideIgnoredUserGames);
|
gameFilters.setHideIgnoredUserGames(hideIgnoredUserGames);
|
||||||
gameFilters.setGameNameFilter(gameNameFilter);
|
gameFilters.setGameNameFilter(gameNameFilter);
|
||||||
|
|
@ -396,6 +476,12 @@ void GamesProxyModel::saveFilterParameters(const QMap<int, QString> &allGameType
|
||||||
|
|
||||||
gameFilters.setMinPlayers(maxPlayersFilterMin);
|
gameFilters.setMinPlayers(maxPlayersFilterMin);
|
||||||
gameFilters.setMaxPlayers(maxPlayersFilterMax);
|
gameFilters.setMaxPlayers(maxPlayersFilterMax);
|
||||||
|
gameFilters.setMaxGameAge(maxGameAge);
|
||||||
|
|
||||||
|
gameFilters.setShowOnlyIfSpectatorsCanWatch(showOnlyIfSpectatorsCanWatch);
|
||||||
|
gameFilters.setShowSpectatorPasswordProtected(showSpectatorPasswordProtected);
|
||||||
|
gameFilters.setShowOnlyIfSpectatorsCanChat(showOnlyIfSpectatorsCanChat);
|
||||||
|
gameFilters.setShowOnlyIfSpectatorsCanSeeHands(showOnlyIfSpectatorsCanSeeHands);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex & /*sourceParent*/) const
|
bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex & /*sourceParent*/) const
|
||||||
|
|
@ -405,7 +491,12 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex & /*sour
|
||||||
|
|
||||||
bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
|
bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
|
||||||
{
|
{
|
||||||
GamesModel *model = qobject_cast<GamesModel *>(sourceModel());
|
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
|
||||||
|
static const QDate epochDate = QDateTime::fromSecsSinceEpoch(0, Qt::UTC).date();
|
||||||
|
#else
|
||||||
|
static const QDate epochDate = QDateTime::fromTime_t(0, Qt::UTC).date();
|
||||||
|
#endif
|
||||||
|
auto *model = qobject_cast<GamesModel *>(sourceModel());
|
||||||
if (!model)
|
if (!model)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -418,15 +509,13 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
|
||||||
QString::fromStdString(game.creator_info().name()))) {
|
QString::fromStdString(game.creator_info().name()))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!unavailableGamesVisible) {
|
if (!showFullGames && game.player_count() == game.max_players())
|
||||||
if (game.player_count() == game.max_players())
|
|
||||||
return false;
|
return false;
|
||||||
if (game.started())
|
if (!showGamesThatStarted && game.started())
|
||||||
return false;
|
return false;
|
||||||
if (!ownUserIsRegistered)
|
if (!ownUserIsRegistered)
|
||||||
if (game.only_registered())
|
if (game.only_registered())
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
if (!showPasswordProtectedGames && game.with_password())
|
if (!showPasswordProtectedGames && game.with_password())
|
||||||
return false;
|
return false;
|
||||||
if (!gameNameFilter.isEmpty())
|
if (!gameNameFilter.isEmpty())
|
||||||
|
|
@ -442,11 +531,32 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
|
||||||
if (!gameTypeFilter.isEmpty() && gameTypes.intersect(gameTypeFilter).isEmpty())
|
if (!gameTypeFilter.isEmpty() && gameTypes.intersect(gameTypeFilter).isEmpty())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if ((int)game.max_players() < maxPlayersFilterMin)
|
if (game.max_players() < maxPlayersFilterMin)
|
||||||
return false;
|
return false;
|
||||||
if ((int)game.max_players() > maxPlayersFilterMax)
|
if (game.max_players() > maxPlayersFilterMax)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (maxGameAge.isValid()) {
|
||||||
|
QDateTime now = QDateTime::currentDateTimeUtc();
|
||||||
|
qint64 signed_start_time = game.start_time(); // cast to 64 bit value to allow signed value
|
||||||
|
QDateTime total = now.addSecs(-signed_start_time); // a 32 bit value would wrap at 2038-1-19
|
||||||
|
// games shouldn't have negative ages but we'll not filter them
|
||||||
|
// because qtime wraps after a day we consider all games older than a day to be too old
|
||||||
|
if (total.isValid() && total.date() >= epochDate && (total.date() > epochDate || total.time() > maxGameAge)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showOnlyIfSpectatorsCanWatch) {
|
||||||
|
if (!game.spectators_allowed())
|
||||||
|
return false;
|
||||||
|
if (!showSpectatorPasswordProtected && game.spectators_need_password())
|
||||||
|
return false;
|
||||||
|
if (showOnlyIfSpectatorsCanChat && !game.spectators_can_chat())
|
||||||
|
return false;
|
||||||
|
if (showOnlyIfSpectatorsCanSeeHands && !game.spectators_omniscient())
|
||||||
|
return false;
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,8 @@
|
||||||
#include <QList>
|
#include <QList>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
#include <QStringList>
|
||||||
|
#include <QTime>
|
||||||
|
|
||||||
class GamesModel : public QAbstractTableModel
|
class GamesModel : public QAbstractTableModel
|
||||||
{
|
{
|
||||||
|
|
@ -19,9 +21,6 @@ private:
|
||||||
QMap<int, GameTypeMap> gameTypes;
|
QMap<int, GameTypeMap> gameTypes;
|
||||||
|
|
||||||
static const int NUM_COLS = 8;
|
static const int NUM_COLS = 8;
|
||||||
static const int SECS_PER_MIN = 60;
|
|
||||||
static const int SECS_PER_TEN_MIN = 600;
|
|
||||||
static const int SECS_PER_HOUR = 3600;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static const int SORT_ROLE = Qt::UserRole + 1;
|
static const int SORT_ROLE = Qt::UserRole + 1;
|
||||||
|
|
@ -37,7 +36,7 @@ public:
|
||||||
}
|
}
|
||||||
QVariant data(const QModelIndex &index, int role) const;
|
QVariant data(const QModelIndex &index, int role) const;
|
||||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||||
const QString getGameCreatedString(const int secs) const;
|
static const QString getGameCreatedString(const int secs);
|
||||||
const ServerInfo_Game &getGame(int row);
|
const ServerInfo_Game &getGame(int row);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -68,20 +67,25 @@ class GamesProxyModel : public QSortFilterProxyModel
|
||||||
private:
|
private:
|
||||||
bool ownUserIsRegistered;
|
bool ownUserIsRegistered;
|
||||||
const TabSupervisor *tabSupervisor;
|
const TabSupervisor *tabSupervisor;
|
||||||
|
|
||||||
|
// If adding any additional filters, make sure to update:
|
||||||
|
// - GamesProxyModel()
|
||||||
|
// - resetFilterParameters()
|
||||||
|
// - areFilterParametersSetToDefaults()
|
||||||
|
// - loadFilterParameters()
|
||||||
|
// - saveFilterParameters()
|
||||||
|
// - filterAcceptsRow()
|
||||||
bool showBuddiesOnlyGames;
|
bool showBuddiesOnlyGames;
|
||||||
bool hideIgnoredUserGames;
|
bool hideIgnoredUserGames;
|
||||||
bool unavailableGamesVisible;
|
bool showFullGames;
|
||||||
|
bool showGamesThatStarted;
|
||||||
bool showPasswordProtectedGames;
|
bool showPasswordProtectedGames;
|
||||||
QString gameNameFilter, creatorNameFilter;
|
QString gameNameFilter, creatorNameFilter;
|
||||||
QSet<int> gameTypeFilter;
|
QSet<int> gameTypeFilter;
|
||||||
int maxPlayersFilterMin, maxPlayersFilterMax;
|
quint32 maxPlayersFilterMin, maxPlayersFilterMax;
|
||||||
|
QTime maxGameAge;
|
||||||
static const bool DEFAULT_UNAVAILABLE_GAMES_VISIBLE = false;
|
bool showOnlyIfSpectatorsCanWatch, showSpectatorPasswordProtected, showOnlyIfSpectatorsCanChat,
|
||||||
static const bool DEFAULT_SHOW_PASSWORD_PROTECTED_GAMES = true;
|
showOnlyIfSpectatorsCanSeeHands;
|
||||||
static const bool DEFAULT_SHOW_BUDDIES_ONLY_GAMES = true;
|
|
||||||
static const bool DEFAULT_HIDE_IGNORED_USER_GAMES = false;
|
|
||||||
static const int DEFAULT_MAX_PLAYERS_MIN = 1;
|
|
||||||
static const int DEFAULT_MAX_PLAYERS_MAX = 99;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GamesProxyModel(QObject *parent = nullptr, const TabSupervisor *_tabSupervisor = nullptr);
|
GamesProxyModel(QObject *parent = nullptr, const TabSupervisor *_tabSupervisor = nullptr);
|
||||||
|
|
@ -96,11 +100,16 @@ public:
|
||||||
return hideIgnoredUserGames;
|
return hideIgnoredUserGames;
|
||||||
}
|
}
|
||||||
void setHideIgnoredUserGames(bool _hideIgnoredUserGames);
|
void setHideIgnoredUserGames(bool _hideIgnoredUserGames);
|
||||||
bool getUnavailableGamesVisible() const
|
bool getShowFullGames() const
|
||||||
{
|
{
|
||||||
return unavailableGamesVisible;
|
return showFullGames;
|
||||||
}
|
}
|
||||||
void setUnavailableGamesVisible(bool _unavailableGamesVisible);
|
void setShowFullGames(bool _showFullGames);
|
||||||
|
bool getShowGamesThatStarted() const
|
||||||
|
{
|
||||||
|
return showGamesThatStarted;
|
||||||
|
}
|
||||||
|
void setShowGamesThatStarted(bool _showGamesThatStarted);
|
||||||
bool getShowPasswordProtectedGames() const
|
bool getShowPasswordProtectedGames() const
|
||||||
{
|
{
|
||||||
return showPasswordProtectedGames;
|
return showPasswordProtectedGames;
|
||||||
|
|
@ -130,6 +139,32 @@ public:
|
||||||
return maxPlayersFilterMax;
|
return maxPlayersFilterMax;
|
||||||
}
|
}
|
||||||
void setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax);
|
void setMaxPlayersFilter(int _maxPlayersFilterMin, int _maxPlayersFilterMax);
|
||||||
|
const QTime &getMaxGameAge() const
|
||||||
|
{
|
||||||
|
return maxGameAge;
|
||||||
|
}
|
||||||
|
void setMaxGameAge(const QTime &_maxGameAge);
|
||||||
|
bool getShowOnlyIfSpectatorsCanWatch() const
|
||||||
|
{
|
||||||
|
return showOnlyIfSpectatorsCanWatch;
|
||||||
|
}
|
||||||
|
void setShowOnlyIfSpectatorsCanWatch(bool _showOnlyIfSpectatorsCanWatch);
|
||||||
|
bool getShowSpectatorPasswordProtected() const
|
||||||
|
{
|
||||||
|
return showSpectatorPasswordProtected;
|
||||||
|
}
|
||||||
|
void setShowSpectatorPasswordProtected(bool _showSpectatorPasswordProtected);
|
||||||
|
bool getShowOnlyIfSpectatorsCanChat() const
|
||||||
|
{
|
||||||
|
return showOnlyIfSpectatorsCanChat;
|
||||||
|
}
|
||||||
|
void setShowOnlyIfSpectatorsCanChat(bool _showOnlyIfSpectatorsCanChat);
|
||||||
|
bool getShowOnlyIfSpectatorsCanSeeHands() const
|
||||||
|
{
|
||||||
|
return showOnlyIfSpectatorsCanSeeHands;
|
||||||
|
}
|
||||||
|
void setShowOnlyIfSpectatorsCanSeeHands(bool _showOnlyIfSpectatorsCanSeeHands);
|
||||||
|
|
||||||
int getNumFilteredGames() const;
|
int getNumFilteredGames() const;
|
||||||
void resetFilterParameters();
|
void resetFilterParameters();
|
||||||
bool areFilterParametersSetToDefaults() const;
|
bool areFilterParametersSetToDefaults() const;
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,13 @@ QRectF HandZone::boundingRect() const
|
||||||
|
|
||||||
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void HandZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
{
|
{
|
||||||
painter->fillRect(boundingRect(), themeManager->getHandBgBrush());
|
QBrush brush = themeManager->getHandBgBrush();
|
||||||
|
|
||||||
|
if (player->getZoneId() > 0) {
|
||||||
|
// If the extra image is not found, load the default one
|
||||||
|
brush = themeManager->getExtraHandBgBrush(QString::number(player->getZoneId()), brush);
|
||||||
|
}
|
||||||
|
painter->fillRect(boundingRect(), brush);
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandZone::reorganizeCards()
|
void HandZone::reorganizeCards()
|
||||||
|
|
|
||||||
|
|
@ -151,6 +151,10 @@ int main(int argc, char *argv[])
|
||||||
qDebug("main(): MainWindow constructor finished");
|
qDebug("main(): MainWindow constructor finished");
|
||||||
|
|
||||||
ui.setWindowIcon(QPixmap("theme:cockatrice"));
|
ui.setWindowIcon(QPixmap("theme:cockatrice"));
|
||||||
|
#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("cockatrice");
|
||||||
|
#endif
|
||||||
|
|
||||||
SettingsCache::instance().setClientID(generateClientID());
|
SettingsCache::instance().setClientID(generateClientID());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,14 @@ void MessageLogWidget::logAlwaysRevealTopCard(Player *player, CardZone *zone, bo
|
||||||
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
|
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MessageLogWidget::logAlwaysLookAtTopCard(Player *player, CardZone *zone, bool reveal)
|
||||||
|
{
|
||||||
|
appendHtmlServerMessage((reveal ? tr("%1 can now look at top card %2 at any time.")
|
||||||
|
: tr("%1 no longer can look at top card %2 at any time."))
|
||||||
|
.arg(sanitizeHtml(player->getName()))
|
||||||
|
.arg(zone->getTranslatedName(true, CaseTopCardsOfZone)));
|
||||||
|
}
|
||||||
|
|
||||||
void MessageLogWidget::logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName)
|
void MessageLogWidget::logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName)
|
||||||
{
|
{
|
||||||
appendHtmlServerMessage(tr("%1 attaches %2 to %3's %4.")
|
appendHtmlServerMessage(tr("%1 attaches %2 to %3's %4.")
|
||||||
|
|
@ -316,7 +324,11 @@ void MessageLogWidget::logMoveCard(Player *player,
|
||||||
bool usesNewX = false;
|
bool usesNewX = false;
|
||||||
if (targetZoneName == tableConstant()) {
|
if (targetZoneName == tableConstant()) {
|
||||||
soundEngine->playSound("play_card");
|
soundEngine->playSound("play_card");
|
||||||
|
if (card->getFaceDown()) {
|
||||||
|
finalStr = tr("%1 puts %2 into play%3 face down.");
|
||||||
|
} else {
|
||||||
finalStr = tr("%1 puts %2 into play%3.");
|
finalStr = tr("%1 puts %2 into play%3.");
|
||||||
|
}
|
||||||
} else if (targetZoneName == graveyardConstant()) {
|
} else if (targetZoneName == graveyardConstant()) {
|
||||||
finalStr = tr("%1 puts %2%3 into their graveyard.");
|
finalStr = tr("%1 puts %2%3 into their graveyard.");
|
||||||
} else if (targetZoneName == exileConstant()) {
|
} else if (targetZoneName == exileConstant()) {
|
||||||
|
|
@ -380,9 +392,11 @@ void MessageLogWidget::logDumpZone(Player *player, CardZone *zone, int numberCar
|
||||||
void MessageLogWidget::logFlipCard(Player *player, QString cardName, bool faceDown)
|
void MessageLogWidget::logFlipCard(Player *player, QString cardName, bool faceDown)
|
||||||
{
|
{
|
||||||
if (faceDown) {
|
if (faceDown) {
|
||||||
appendHtmlServerMessage(tr("%1 turns %2 face-down.").arg(sanitizeHtml(player->getName())).arg(cardName));
|
appendHtmlServerMessage(
|
||||||
|
tr("%1 turns %2 face-down.").arg(sanitizeHtml(player->getName())).arg(cardLink(cardName)));
|
||||||
} else {
|
} else {
|
||||||
appendHtmlServerMessage(tr("%1 turns %2 face-up.").arg(sanitizeHtml(player->getName())).arg(cardName));
|
appendHtmlServerMessage(
|
||||||
|
tr("%1 turns %2 face-up.").arg(sanitizeHtml(player->getName())).arg(cardLink(cardName)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -743,13 +757,6 @@ void MessageLogWidget::logSpectatorSay(QString spectatorName,
|
||||||
appendMessage(std::move(message), {}, spectatorName, spectatorUserLevel, userPrivLevel, false);
|
appendMessage(std::move(message), {}, spectatorName, spectatorUserLevel, userPrivLevel, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MessageLogWidget::logStopDumpZone(Player *player, CardZone *zone)
|
|
||||||
{
|
|
||||||
appendHtmlServerMessage(tr("%1 stops looking at %2.")
|
|
||||||
.arg(sanitizeHtml(player->getName()))
|
|
||||||
.arg(zone->getTranslatedName(zone->getPlayer() == player, CaseLookAtZone)));
|
|
||||||
}
|
|
||||||
|
|
||||||
void MessageLogWidget::logUnattachCard(Player *player, QString cardName)
|
void MessageLogWidget::logUnattachCard(Player *player, QString cardName)
|
||||||
{
|
{
|
||||||
appendHtmlServerMessage(
|
appendHtmlServerMessage(
|
||||||
|
|
@ -810,13 +817,14 @@ void MessageLogWidget::connectToPlayer(Player *player)
|
||||||
SLOT(logAttachCard(Player *, QString, Player *, QString)));
|
SLOT(logAttachCard(Player *, QString, Player *, QString)));
|
||||||
connect(player, SIGNAL(logUnattachCard(Player *, QString)), this, SLOT(logUnattachCard(Player *, QString)));
|
connect(player, SIGNAL(logUnattachCard(Player *, QString)), this, SLOT(logUnattachCard(Player *, QString)));
|
||||||
connect(player, SIGNAL(logDumpZone(Player *, CardZone *, int)), this, SLOT(logDumpZone(Player *, CardZone *, int)));
|
connect(player, SIGNAL(logDumpZone(Player *, CardZone *, int)), this, SLOT(logDumpZone(Player *, CardZone *, int)));
|
||||||
connect(player, SIGNAL(logStopDumpZone(Player *, CardZone *)), this, SLOT(logStopDumpZone(Player *, CardZone *)));
|
|
||||||
connect(player, SIGNAL(logDrawCards(Player *, int)), this, SLOT(logDrawCards(Player *, int)));
|
connect(player, SIGNAL(logDrawCards(Player *, int)), this, SLOT(logDrawCards(Player *, int)));
|
||||||
connect(player, SIGNAL(logUndoDraw(Player *, QString)), this, SLOT(logUndoDraw(Player *, QString)));
|
connect(player, SIGNAL(logUndoDraw(Player *, QString)), this, SLOT(logUndoDraw(Player *, QString)));
|
||||||
connect(player, SIGNAL(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int)), this,
|
connect(player, SIGNAL(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int)), this,
|
||||||
SLOT(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int)));
|
SLOT(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int)));
|
||||||
connect(player, SIGNAL(logAlwaysRevealTopCard(Player *, CardZone *, bool)), this,
|
connect(player, SIGNAL(logAlwaysRevealTopCard(Player *, CardZone *, bool)), this,
|
||||||
SLOT(logAlwaysRevealTopCard(Player *, CardZone *, bool)));
|
SLOT(logAlwaysRevealTopCard(Player *, CardZone *, bool)));
|
||||||
|
connect(player, SIGNAL(logAlwaysLookAtTopCard(Player *, CardZone *, bool)), this,
|
||||||
|
SLOT(logAlwaysLookAtTopCard(Player *, CardZone *, bool)));
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageLogWidget::MessageLogWidget(const TabSupervisor *_tabSupervisor,
|
MessageLogWidget::MessageLogWidget(const TabSupervisor *_tabSupervisor,
|
||||||
|
|
|
||||||
|
|
@ -42,6 +42,7 @@ public slots:
|
||||||
void containerProcessingDone();
|
void containerProcessingDone();
|
||||||
void containerProcessingStarted(const GameEventContext &context);
|
void containerProcessingStarted(const GameEventContext &context);
|
||||||
void logAlwaysRevealTopCard(Player *player, CardZone *zone, bool reveal);
|
void logAlwaysRevealTopCard(Player *player, CardZone *zone, bool reveal);
|
||||||
|
void logAlwaysLookAtTopCard(Player *player, CardZone *zone, bool reveal);
|
||||||
void logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName);
|
void logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName);
|
||||||
void logConcede(Player *player);
|
void logConcede(Player *player);
|
||||||
void logUnconcede(Player *player);
|
void logUnconcede(Player *player);
|
||||||
|
|
@ -92,7 +93,6 @@ public slots:
|
||||||
void logShuffle(Player *player, CardZone *zone, int start, int end);
|
void logShuffle(Player *player, CardZone *zone, int start, int end);
|
||||||
void
|
void
|
||||||
logSpectatorSay(QString spectatorName, UserLevelFlags spectatorUserLevel, QString userPrivLevel, QString message);
|
logSpectatorSay(QString spectatorName, UserLevelFlags spectatorUserLevel, QString userPrivLevel, QString message);
|
||||||
void logStopDumpZone(Player *player, CardZone *zone);
|
|
||||||
void logUnattachCard(Player *player, QString cardName);
|
void logUnattachCard(Player *player, QString cardName);
|
||||||
void logUndoDraw(Player *player, QString cardName);
|
void logUndoDraw(Player *player, QString cardName);
|
||||||
void setContextJudgeName(QString player);
|
void setContextJudgeName(QString player);
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
#include <QNetworkRequest>
|
#include <QNetworkRequest>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QSet>
|
#include <QSet>
|
||||||
#include <QSvgRenderer>
|
#include <QSvgRenderer>
|
||||||
#include <QThread>
|
#include <QThread>
|
||||||
|
|
@ -195,9 +196,12 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
|
||||||
QString thisPath(it.next());
|
QString thisPath(it.next());
|
||||||
QFileInfo thisFileInfo(thisPath);
|
QFileInfo thisFileInfo(thisPath);
|
||||||
|
|
||||||
if (thisFileInfo.isFile() && thisFileInfo.baseName() == correctedCardname)
|
if (thisFileInfo.isFile() &&
|
||||||
|
(thisFileInfo.fileName() == correctedCardname || thisFileInfo.completeBaseName() == correctedCardname ||
|
||||||
|
thisFileInfo.baseName() == correctedCardname)) {
|
||||||
picsPaths << thisPath; // Card found in the CUSTOM directory, somewhere
|
picsPaths << thisPath; // Card found in the CUSTOM directory, somewhere
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!setName.isEmpty()) {
|
if (!setName.isEmpty()) {
|
||||||
picsPaths << picsPath + "/" + setName + "/" + correctedCardname
|
picsPaths << picsPath + "/" + setName + "/" + correctedCardname
|
||||||
|
|
@ -241,6 +245,10 @@ QString PictureToLoad::transformUrl(const QString &urlTemplate) const
|
||||||
for downloading images. If information is requested by the template that is
|
for downloading images. If information is requested by the template that is
|
||||||
not populated for this specific card/set combination, an empty string is returned.*/
|
not populated for this specific card/set combination, an empty string is returned.*/
|
||||||
|
|
||||||
|
static const QRegularExpression rxCardProp("!prop:([^!]+)!");
|
||||||
|
static const QRegularExpression rxFillWith("^(.+)_fill_with_(.+)$");
|
||||||
|
static const QRegularExpression rxSetProp("!set:([^!]+)!");
|
||||||
|
|
||||||
QString transformedUrl = urlTemplate;
|
QString transformedUrl = urlTemplate;
|
||||||
CardSetPtr set = getCurrentSet();
|
CardSetPtr set = getCurrentSet();
|
||||||
|
|
||||||
|
|
@ -252,18 +260,39 @@ QString PictureToLoad::transformUrl(const QString &urlTemplate) const
|
||||||
transformMap["!corrected_name_lower!"] = card->getCorrectedName().toLower();
|
transformMap["!corrected_name_lower!"] = card->getCorrectedName().toLower();
|
||||||
|
|
||||||
// card properties
|
// card properties
|
||||||
QRegExp rxCardProp("!prop:([^!]+)!");
|
auto matches = rxCardProp.globalMatch(transformedUrl);
|
||||||
int pos = 0;
|
while (matches.hasNext()) {
|
||||||
while ((pos = rxCardProp.indexIn(transformedUrl, pos)) != -1) {
|
auto match = matches.next();
|
||||||
QString propertyName = rxCardProp.cap(1);
|
QString propertyName = match.captured(1);
|
||||||
pos += rxCardProp.matchedLength();
|
auto fillMatch = rxFillWith.match(propertyName);
|
||||||
QString propertyValue = card->getProperty(propertyName);
|
QString fillPropertyName;
|
||||||
|
QString fillWith;
|
||||||
|
if (fillMatch.hasMatch()) {
|
||||||
|
fillPropertyName = fillMatch.captured(1);
|
||||||
|
fillWith = fillMatch.captured(2);
|
||||||
|
} else {
|
||||||
|
fillPropertyName = propertyName;
|
||||||
|
fillWith = QString();
|
||||||
|
}
|
||||||
|
QString propertyValue = card->getProperty(fillPropertyName);
|
||||||
if (propertyValue.isEmpty()) {
|
if (propertyValue.isEmpty()) {
|
||||||
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
|
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
|
||||||
<< "]: Requested property (" << propertyName << ") for Url template (" << urlTemplate
|
<< "]: Requested property (" << fillPropertyName << ") for Url template (" << urlTemplate
|
||||||
<< ") is not available";
|
<< ") is not available";
|
||||||
return QString();
|
return QString();
|
||||||
} else {
|
} else {
|
||||||
|
if (!fillWith.isEmpty()) {
|
||||||
|
int fillLength = fillWith.length();
|
||||||
|
int propLength = propertyValue.length();
|
||||||
|
if (fillLength < propLength) {
|
||||||
|
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
|
||||||
|
<< "]: Requested property (" << fillPropertyName << ") for Url template (" << urlTemplate
|
||||||
|
<< ") is longer than fill specification (" << fillWith << ")";
|
||||||
|
return QString();
|
||||||
|
} else {
|
||||||
|
propertyValue = fillWith.left(fillLength - propLength) + propertyValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
transformMap["!prop:" + propertyName + "!"] = propertyValue;
|
transformMap["!prop:" + propertyName + "!"] = propertyValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -274,18 +303,39 @@ QString PictureToLoad::transformUrl(const QString &urlTemplate) const
|
||||||
transformMap["!setname!"] = set->getLongName();
|
transformMap["!setname!"] = set->getLongName();
|
||||||
transformMap["!setname_lower!"] = set->getLongName().toLower();
|
transformMap["!setname_lower!"] = set->getLongName().toLower();
|
||||||
|
|
||||||
QRegExp rxSetProp("!set:([^!]+)!");
|
auto matches = rxSetProp.globalMatch(transformedUrl);
|
||||||
pos = 0; // Defined above
|
while (matches.hasNext()) {
|
||||||
while ((pos = rxSetProp.indexIn(transformedUrl, pos)) != -1) {
|
auto match = matches.next();
|
||||||
QString propertyName = rxSetProp.cap(1);
|
QString propertyName = match.captured(1);
|
||||||
pos += rxSetProp.matchedLength();
|
auto fillMatch = rxFillWith.match(propertyName);
|
||||||
QString propertyValue = card->getSetProperty(set->getShortName(), propertyName);
|
QString fillPropertyName;
|
||||||
|
QString fillWith;
|
||||||
|
if (fillMatch.hasMatch()) {
|
||||||
|
fillPropertyName = fillMatch.captured(1);
|
||||||
|
fillWith = fillMatch.captured(2);
|
||||||
|
} else {
|
||||||
|
fillPropertyName = propertyName;
|
||||||
|
fillWith = QString();
|
||||||
|
}
|
||||||
|
QString propertyValue = card->getSetProperty(set->getShortName(), fillPropertyName);
|
||||||
if (propertyValue.isEmpty()) {
|
if (propertyValue.isEmpty()) {
|
||||||
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
|
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
|
||||||
<< "]: Requested set property (" << propertyName << ") for Url template (" << urlTemplate
|
<< "]: Requested set property (" << fillPropertyName << ") for Url template (" << urlTemplate
|
||||||
<< ") is not available";
|
<< ") is not available";
|
||||||
return QString();
|
return QString();
|
||||||
} else {
|
} else {
|
||||||
|
if (!fillWith.isEmpty()) {
|
||||||
|
int fillLength = fillWith.length();
|
||||||
|
int propLength = propertyValue.length();
|
||||||
|
if (fillLength < propLength) {
|
||||||
|
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
|
||||||
|
<< "]: Requested set property (" << fillPropertyName << ") for Url template ("
|
||||||
|
<< urlTemplate << ") is longer than fill specification (" << fillWith << ")";
|
||||||
|
return QString();
|
||||||
|
} else {
|
||||||
|
propertyValue = fillWith.left(fillLength - propLength) + propertyValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
transformMap["!set:" + propertyName + "!"] = propertyValue;
|
transformMap["!set:" + propertyName + "!"] = propertyValue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -405,10 +455,9 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
|
||||||
QImageReader imgReader;
|
QImageReader imgReader;
|
||||||
imgReader.setDecideFormatFromContent(true);
|
imgReader.setDecideFormatFromContent(true);
|
||||||
imgReader.setDevice(reply);
|
imgReader.setDevice(reply);
|
||||||
QString extension = "." + imgReader.format(); // the format is determined
|
// the format is determined prior to reading the QImageReader data into a QImage object, as that wipes the
|
||||||
// prior to reading the
|
// QImageReader buffer
|
||||||
// QImageReader data
|
QString extension = "." + imgReader.format();
|
||||||
// into a QImage object, as that wipes the QImageReader buffer
|
|
||||||
if (extension == ".jpeg") {
|
if (extension == ".jpeg") {
|
||||||
extension = ".jpg";
|
extension = ".jpg";
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -49,7 +49,6 @@
|
||||||
#include "pb/event_set_card_counter.pb.h"
|
#include "pb/event_set_card_counter.pb.h"
|
||||||
#include "pb/event_set_counter.pb.h"
|
#include "pb/event_set_counter.pb.h"
|
||||||
#include "pb/event_shuffle.pb.h"
|
#include "pb/event_shuffle.pb.h"
|
||||||
#include "pb/event_stop_dump_zone.pb.h"
|
|
||||||
#include "pb/serverinfo_player.pb.h"
|
#include "pb/serverinfo_player.pb.h"
|
||||||
#include "pb/serverinfo_user.pb.h"
|
#include "pb/serverinfo_user.pb.h"
|
||||||
#include "pb/serverinfo_zone.pb.h"
|
#include "pb/serverinfo_zone.pb.h"
|
||||||
|
|
@ -83,7 +82,13 @@ void PlayerArea::updateBg()
|
||||||
|
|
||||||
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void PlayerArea::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
{
|
{
|
||||||
painter->fillRect(bRect, themeManager->getPlayerBgBrush());
|
QBrush brush = themeManager->getPlayerBgBrush();
|
||||||
|
|
||||||
|
if (playerZoneId > 0) {
|
||||||
|
// If the extra image is not found, load the default one
|
||||||
|
brush = themeManager->getExtraPlayerBgBrush(QString::number(playerZoneId), brush);
|
||||||
|
}
|
||||||
|
painter->fillRect(boundingRect(), brush);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerArea::setSize(qreal width, qreal height)
|
void PlayerArea::setSize(qreal width, qreal height)
|
||||||
|
|
@ -92,10 +97,14 @@ void PlayerArea::setSize(qreal width, qreal height)
|
||||||
bRect = QRectF(0, 0, width, height);
|
bRect = QRectF(0, 0, width, height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PlayerArea::setPlayerZoneId(int _playerZoneId)
|
||||||
|
{
|
||||||
|
playerZoneId = _playerZoneId;
|
||||||
|
}
|
||||||
|
|
||||||
Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, TabGame *_parent)
|
Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, TabGame *_parent)
|
||||||
: QObject(_parent), game(_parent), shortcutsActive(false), defaultNumberTopCards(1),
|
: QObject(_parent), game(_parent), shortcutsActive(false), lastTokenDestroy(true), lastTokenTableRow(0), id(_id),
|
||||||
defaultNumberTopCardsToPlaceBelow(1), lastTokenDestroy(true), lastTokenTableRow(0), id(_id), active(false),
|
active(false), local(_local), judge(_judge), mirrored(false), handVisible(false), conceded(false), zoneId(0),
|
||||||
local(_local), judge(_judge), mirrored(false), handVisible(false), conceded(false), zoneId(0),
|
|
||||||
dialogSemaphore(false), deck(nullptr)
|
dialogSemaphore(false), deck(nullptr)
|
||||||
{
|
{
|
||||||
userInfo = new ServerInfo_User;
|
userInfo = new ServerInfo_User;
|
||||||
|
|
@ -200,6 +209,9 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
|
||||||
aAlwaysRevealTopCard = new QAction(this);
|
aAlwaysRevealTopCard = new QAction(this);
|
||||||
aAlwaysRevealTopCard->setCheckable(true);
|
aAlwaysRevealTopCard->setCheckable(true);
|
||||||
connect(aAlwaysRevealTopCard, SIGNAL(triggered()), this, SLOT(actAlwaysRevealTopCard()));
|
connect(aAlwaysRevealTopCard, SIGNAL(triggered()), this, SLOT(actAlwaysRevealTopCard()));
|
||||||
|
aAlwaysLookAtTopCard = new QAction(this);
|
||||||
|
aAlwaysLookAtTopCard->setCheckable(true);
|
||||||
|
connect(aAlwaysLookAtTopCard, SIGNAL(triggered()), this, SLOT(actAlwaysLookAtTopCard()));
|
||||||
aOpenDeckInDeckEditor = new QAction(this);
|
aOpenDeckInDeckEditor = new QAction(this);
|
||||||
aOpenDeckInDeckEditor->setEnabled(false);
|
aOpenDeckInDeckEditor->setEnabled(false);
|
||||||
connect(aOpenDeckInDeckEditor, SIGNAL(triggered()), this, SLOT(actOpenDeckInDeckEditor()));
|
connect(aOpenDeckInDeckEditor, SIGNAL(triggered()), this, SLOT(actOpenDeckInDeckEditor()));
|
||||||
|
|
@ -225,6 +237,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
|
||||||
connect(aShuffle, SIGNAL(triggered()), this, SLOT(actShuffle()));
|
connect(aShuffle, SIGNAL(triggered()), this, SLOT(actShuffle()));
|
||||||
aMulligan = new QAction(this);
|
aMulligan = new QAction(this);
|
||||||
connect(aMulligan, SIGNAL(triggered()), this, SLOT(actMulligan()));
|
connect(aMulligan, SIGNAL(triggered()), this, SLOT(actMulligan()));
|
||||||
|
|
||||||
aMoveTopToPlay = new QAction(this);
|
aMoveTopToPlay = new QAction(this);
|
||||||
connect(aMoveTopToPlay, SIGNAL(triggered()), this, SLOT(actMoveTopCardToPlay()));
|
connect(aMoveTopToPlay, SIGNAL(triggered()), this, SLOT(actMoveTopCardToPlay()));
|
||||||
aMoveTopToPlayFaceDown = new QAction(this);
|
aMoveTopToPlayFaceDown = new QAction(this);
|
||||||
|
|
@ -239,8 +252,25 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
|
||||||
connect(aMoveTopCardsToExile, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToExile()));
|
connect(aMoveTopCardsToExile, SIGNAL(triggered()), this, SLOT(actMoveTopCardsToExile()));
|
||||||
aMoveTopCardToBottom = new QAction(this);
|
aMoveTopCardToBottom = new QAction(this);
|
||||||
connect(aMoveTopCardToBottom, SIGNAL(triggered()), this, SLOT(actMoveTopCardToBottom()));
|
connect(aMoveTopCardToBottom, SIGNAL(triggered()), this, SLOT(actMoveTopCardToBottom()));
|
||||||
aMoveBottomCardToGrave = new QAction(this);
|
|
||||||
connect(aMoveBottomCardToGrave, SIGNAL(triggered()), this, SLOT(actMoveBottomCardToGrave()));
|
aDrawBottomCard = new QAction(this);
|
||||||
|
connect(aDrawBottomCard, SIGNAL(triggered()), this, SLOT(actDrawBottomCard()));
|
||||||
|
aDrawBottomCards = new QAction(this);
|
||||||
|
connect(aDrawBottomCards, SIGNAL(triggered()), this, SLOT(actDrawBottomCards()));
|
||||||
|
aMoveBottomToPlay = new QAction(this);
|
||||||
|
connect(aMoveBottomToPlay, SIGNAL(triggered()), this, SLOT(actMoveBottomCardToPlay()));
|
||||||
|
aMoveBottomToPlayFaceDown = new QAction(this);
|
||||||
|
connect(aMoveBottomToPlayFaceDown, SIGNAL(triggered()), this, SLOT(actMoveBottomCardToPlayFaceDown()));
|
||||||
|
aMoveBottomCardToGraveyard = new QAction(this);
|
||||||
|
connect(aMoveBottomCardToGraveyard, SIGNAL(triggered()), this, SLOT(actMoveBottomCardToGrave()));
|
||||||
|
aMoveBottomCardToExile = new QAction(this);
|
||||||
|
connect(aMoveBottomCardToExile, SIGNAL(triggered()), this, SLOT(actMoveBottomCardToExile()));
|
||||||
|
aMoveBottomCardsToGraveyard = new QAction(this);
|
||||||
|
connect(aMoveBottomCardsToGraveyard, SIGNAL(triggered()), this, SLOT(actMoveBottomCardsToGrave()));
|
||||||
|
aMoveBottomCardsToExile = new QAction(this);
|
||||||
|
connect(aMoveBottomCardsToExile, SIGNAL(triggered()), this, SLOT(actMoveBottomCardsToExile()));
|
||||||
|
aMoveBottomCardToTop = new QAction(this);
|
||||||
|
connect(aMoveBottomCardToTop, SIGNAL(triggered()), this, SLOT(actMoveBottomCardToTop()));
|
||||||
}
|
}
|
||||||
|
|
||||||
playerMenu = new TearOffMenu();
|
playerMenu = new TearOffMenu();
|
||||||
|
|
@ -276,22 +306,34 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
|
||||||
playerLists.append(mRevealLibrary = libraryMenu->addMenu(QString()));
|
playerLists.append(mRevealLibrary = libraryMenu->addMenu(QString()));
|
||||||
playerLists.append(mRevealTopCard = libraryMenu->addMenu(QString()));
|
playerLists.append(mRevealTopCard = libraryMenu->addMenu(QString()));
|
||||||
libraryMenu->addAction(aAlwaysRevealTopCard);
|
libraryMenu->addAction(aAlwaysRevealTopCard);
|
||||||
|
libraryMenu->addAction(aAlwaysLookAtTopCard);
|
||||||
libraryMenu->addSeparator();
|
libraryMenu->addSeparator();
|
||||||
libraryMenu->addAction(aMoveTopToPlay);
|
topLibraryMenu = libraryMenu->addTearOffMenu(QString());
|
||||||
libraryMenu->addAction(aMoveTopToPlayFaceDown);
|
bottomLibraryMenu = libraryMenu->addTearOffMenu(QString());
|
||||||
libraryMenu->addAction(aMoveTopCardToBottom);
|
|
||||||
libraryMenu->addAction(aMoveBottomCardToGrave);
|
|
||||||
libraryMenu->addSeparator();
|
|
||||||
libraryMenu->addAction(aMoveTopCardToGraveyard);
|
|
||||||
libraryMenu->addAction(aMoveTopCardToExile);
|
|
||||||
libraryMenu->addAction(aMoveTopCardsToGraveyard);
|
|
||||||
libraryMenu->addAction(aMoveTopCardsToExile);
|
|
||||||
libraryMenu->addSeparator();
|
libraryMenu->addSeparator();
|
||||||
libraryMenu->addAction(aOpenDeckInDeckEditor);
|
libraryMenu->addAction(aOpenDeckInDeckEditor);
|
||||||
deck->setMenu(libraryMenu, aDrawCard);
|
deck->setMenu(libraryMenu, aDrawCard);
|
||||||
} else {
|
|
||||||
handMenu = nullptr;
|
topLibraryMenu->addAction(aMoveTopToPlay);
|
||||||
libraryMenu = nullptr;
|
topLibraryMenu->addAction(aMoveTopToPlayFaceDown);
|
||||||
|
topLibraryMenu->addAction(aMoveTopCardToBottom);
|
||||||
|
topLibraryMenu->addSeparator();
|
||||||
|
topLibraryMenu->addAction(aMoveTopCardToGraveyard);
|
||||||
|
topLibraryMenu->addAction(aMoveTopCardsToGraveyard);
|
||||||
|
topLibraryMenu->addAction(aMoveTopCardToExile);
|
||||||
|
topLibraryMenu->addAction(aMoveTopCardsToExile);
|
||||||
|
|
||||||
|
bottomLibraryMenu->addAction(aDrawBottomCard);
|
||||||
|
bottomLibraryMenu->addAction(aDrawBottomCards);
|
||||||
|
bottomLibraryMenu->addSeparator();
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomToPlay);
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomToPlayFaceDown);
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomCardToTop);
|
||||||
|
bottomLibraryMenu->addSeparator();
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomCardToGraveyard);
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomCardsToGraveyard);
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomCardToExile);
|
||||||
|
bottomLibraryMenu->addAction(aMoveBottomCardsToExile);
|
||||||
}
|
}
|
||||||
|
|
||||||
graveMenu = playerMenu->addTearOffMenu(QString());
|
graveMenu = playerMenu->addTearOffMenu(QString());
|
||||||
|
|
@ -348,6 +390,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
|
||||||
aCreateAnotherToken->setEnabled(false);
|
aCreateAnotherToken->setEnabled(false);
|
||||||
|
|
||||||
createPredefinedTokenMenu = new QMenu(QString());
|
createPredefinedTokenMenu = new QMenu(QString());
|
||||||
|
createPredefinedTokenMenu->setEnabled(false);
|
||||||
|
|
||||||
playerMenu->addSeparator();
|
playerMenu->addSeparator();
|
||||||
countersMenu = playerMenu->addMenu(QString());
|
countersMenu = playerMenu->addMenu(QString());
|
||||||
|
|
@ -369,6 +412,7 @@ Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, T
|
||||||
|
|
||||||
if (local || judge) {
|
if (local || judge) {
|
||||||
aCardMenu = new QAction(this);
|
aCardMenu = new QAction(this);
|
||||||
|
aCardMenu->setEnabled(false);
|
||||||
playerMenu->addSeparator();
|
playerMenu->addSeparator();
|
||||||
playerMenu->addAction(aCardMenu);
|
playerMenu->addAction(aCardMenu);
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -558,11 +602,11 @@ void Player::playerListActionTriggered()
|
||||||
if (menu == mRevealLibrary) {
|
if (menu == mRevealLibrary) {
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name("deck");
|
||||||
} else if (menu == mRevealTopCard) {
|
} else if (menu == mRevealTopCard) {
|
||||||
int decksize = zones.value("deck")->getCards().size();
|
int deckSize = zones.value("deck")->getCards().size();
|
||||||
bool ok;
|
bool ok;
|
||||||
int number = QInputDialog::getInt(game, tr("Reveal top cards of library"),
|
int number = QInputDialog::getInt(game, tr("Reveal top cards of library"),
|
||||||
tr("Number of cards: (max. %1)").arg(decksize), defaultNumberTopCards, 1,
|
tr("Number of cards: (max. %1)").arg(deckSize), defaultNumberTopCards, 1,
|
||||||
decksize, 1, &ok);
|
deckSize, 1, &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
cmd.set_zone_name("deck");
|
cmd.set_zone_name("deck");
|
||||||
cmd.set_top_cards(number);
|
cmd.set_top_cards(number);
|
||||||
|
|
@ -682,23 +726,36 @@ void Player::retranslateUi()
|
||||||
aViewHand->setText(tr("&View hand"));
|
aViewHand->setText(tr("&View hand"));
|
||||||
aViewTopCards->setText(tr("View &top cards of library..."));
|
aViewTopCards->setText(tr("View &top cards of library..."));
|
||||||
mRevealLibrary->setTitle(tr("Reveal &library to..."));
|
mRevealLibrary->setTitle(tr("Reveal &library to..."));
|
||||||
mRevealTopCard->setTitle(tr("Reveal t&op cards to..."));
|
mRevealTopCard->setTitle(tr("Reveal &top cards to..."));
|
||||||
|
topLibraryMenu->setTitle(tr("&Top of library..."));
|
||||||
|
bottomLibraryMenu->setTitle(tr("&Bottom of library..."));
|
||||||
aAlwaysRevealTopCard->setText(tr("&Always reveal top card"));
|
aAlwaysRevealTopCard->setText(tr("&Always reveal top card"));
|
||||||
aOpenDeckInDeckEditor->setText(tr("O&pen deck in deck editor"));
|
aAlwaysLookAtTopCard->setText(tr("&Always look at top card"));
|
||||||
|
aOpenDeckInDeckEditor->setText(tr("&Open deck in deck editor"));
|
||||||
aViewSideboard->setText(tr("&View sideboard"));
|
aViewSideboard->setText(tr("&View sideboard"));
|
||||||
aDrawCard->setText(tr("&Draw card"));
|
aDrawCard->setText(tr("&Draw card"));
|
||||||
aDrawCards->setText(tr("D&raw cards..."));
|
aDrawCards->setText(tr("D&raw cards..."));
|
||||||
aUndoDraw->setText(tr("&Undo last draw"));
|
aUndoDraw->setText(tr("&Undo last draw"));
|
||||||
aMulligan->setText(tr("Take &mulligan"));
|
aMulligan->setText(tr("Take &mulligan"));
|
||||||
aShuffle->setText(tr("&Shuffle"));
|
aShuffle->setText(tr("&Shuffle"));
|
||||||
aMoveTopToPlay->setText(tr("Play top card"));
|
|
||||||
|
aMoveTopToPlay->setText(tr("&Play top card"));
|
||||||
aMoveTopToPlayFaceDown->setText(tr("Play top card &face down"));
|
aMoveTopToPlayFaceDown->setText(tr("Play top card &face down"));
|
||||||
aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard"));
|
aMoveTopCardToGraveyard->setText(tr("Move top card to grave&yard"));
|
||||||
aMoveTopCardToExile->setText(tr("Move top card to e&xile"));
|
aMoveTopCardToExile->setText(tr("Move top card to e&xile"));
|
||||||
aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard..."));
|
aMoveTopCardsToGraveyard->setText(tr("Move top cards to &graveyard..."));
|
||||||
aMoveTopCardsToExile->setText(tr("Move top cards to &exile..."));
|
aMoveTopCardsToExile->setText(tr("Move top cards to &exile..."));
|
||||||
aMoveTopCardToBottom->setText(tr("Put top card on &bottom"));
|
aMoveTopCardToBottom->setText(tr("Put top card on &bottom"));
|
||||||
aMoveBottomCardToGrave->setText(tr("Put bottom card &in graveyard"));
|
|
||||||
|
aDrawBottomCard->setText(tr("&Draw bottom card"));
|
||||||
|
aDrawBottomCards->setText(tr("D&raw bottom cards..."));
|
||||||
|
aMoveBottomToPlay->setText(tr("&Play bottom card"));
|
||||||
|
aMoveBottomToPlayFaceDown->setText(tr("Play bottom card &face down"));
|
||||||
|
aMoveBottomCardToGraveyard->setText(tr("Move bottom card to grave&yard"));
|
||||||
|
aMoveBottomCardToExile->setText(tr("Move bottom card to e&xile"));
|
||||||
|
aMoveBottomCardsToGraveyard->setText(tr("Move bottom cards to &graveyard..."));
|
||||||
|
aMoveBottomCardsToExile->setText(tr("Move bottom cards to &exile..."));
|
||||||
|
aMoveBottomCardToTop->setText(tr("Put bottom card on &top"));
|
||||||
|
|
||||||
handMenu->setTitle(tr("&Hand"));
|
handMenu->setTitle(tr("&Hand"));
|
||||||
mRevealHand->setTitle(tr("&Reveal hand to..."));
|
mRevealHand->setTitle(tr("&Reveal hand to..."));
|
||||||
|
|
@ -719,7 +776,7 @@ void Player::retranslateUi()
|
||||||
counterIterator.next().value()->retranslateUi();
|
counterIterator.next().value()->retranslateUi();
|
||||||
}
|
}
|
||||||
|
|
||||||
aCardMenu->setText(tr("C&ard"));
|
aCardMenu->setText(tr("Selec&ted cards"));
|
||||||
|
|
||||||
for (auto &allPlayersAction : allPlayersActions) {
|
for (auto &allPlayersAction : allPlayersActions) {
|
||||||
allPlayersAction->setText(tr("&All players"));
|
allPlayersAction->setText(tr("&All players"));
|
||||||
|
|
@ -861,6 +918,7 @@ void Player::setShortcutsActive()
|
||||||
aCreateToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateToken"));
|
aCreateToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateToken"));
|
||||||
aCreateAnotherToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateAnotherToken"));
|
aCreateAnotherToken->setShortcut(shortcuts.getSingleShortcut("Player/aCreateAnotherToken"));
|
||||||
aAlwaysRevealTopCard->setShortcut(shortcuts.getSingleShortcut("Player/aAlwaysRevealTopCard"));
|
aAlwaysRevealTopCard->setShortcut(shortcuts.getSingleShortcut("Player/aAlwaysRevealTopCard"));
|
||||||
|
aAlwaysLookAtTopCard->setShortcut(shortcuts.getSingleShortcut("Player/aAlwaysLookAtTopCard"));
|
||||||
aMoveTopToPlay->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlay"));
|
aMoveTopToPlay->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlay"));
|
||||||
aMoveTopToPlayFaceDown->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlayFaceDown"));
|
aMoveTopToPlayFaceDown->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopToPlayFaceDown"));
|
||||||
aMoveTopCardToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToGraveyard"));
|
aMoveTopCardToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToGraveyard"));
|
||||||
|
|
@ -868,7 +926,15 @@ void Player::setShortcutsActive()
|
||||||
aMoveTopCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToExile"));
|
aMoveTopCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToExile"));
|
||||||
aMoveTopCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToExile"));
|
aMoveTopCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardsToExile"));
|
||||||
aMoveTopCardToBottom->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToBottom"));
|
aMoveTopCardToBottom->setShortcut(shortcuts.getSingleShortcut("Player/aMoveTopCardToBottom"));
|
||||||
aMoveBottomCardToGrave->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToGrave"));
|
aDrawBottomCard->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCard"));
|
||||||
|
aDrawBottomCards->setShortcut(shortcuts.getSingleShortcut("Player/aDrawBottomCards"));
|
||||||
|
aMoveBottomToPlay->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomToPlay"));
|
||||||
|
aMoveBottomToPlayFaceDown->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomToPlayFaceDown"));
|
||||||
|
aMoveBottomCardToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToGrave"));
|
||||||
|
aMoveBottomCardsToGraveyard->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardsToGrave"));
|
||||||
|
aMoveBottomCardToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToExile"));
|
||||||
|
aMoveBottomCardsToExile->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardsToExile"));
|
||||||
|
aMoveBottomCardToTop->setShortcut(shortcuts.getSingleShortcut("Player/aMoveBottomCardToTop"));
|
||||||
aPlayFacedown->setShortcut(shortcuts.getSingleShortcut("Player/aPlayFacedown"));
|
aPlayFacedown->setShortcut(shortcuts.getSingleShortcut("Player/aPlayFacedown"));
|
||||||
aPlay->setShortcut(shortcuts.getSingleShortcut("Player/aPlay"));
|
aPlay->setShortcut(shortcuts.getSingleShortcut("Player/aPlay"));
|
||||||
}
|
}
|
||||||
|
|
@ -892,12 +958,21 @@ void Player::setShortcutsInactive()
|
||||||
aCreateToken->setShortcut(QKeySequence());
|
aCreateToken->setShortcut(QKeySequence());
|
||||||
aCreateAnotherToken->setShortcut(QKeySequence());
|
aCreateAnotherToken->setShortcut(QKeySequence());
|
||||||
aAlwaysRevealTopCard->setShortcut(QKeySequence());
|
aAlwaysRevealTopCard->setShortcut(QKeySequence());
|
||||||
|
aAlwaysLookAtTopCard->setShortcut(QKeySequence());
|
||||||
aMoveTopToPlay->setShortcut(QKeySequence());
|
aMoveTopToPlay->setShortcut(QKeySequence());
|
||||||
aMoveTopToPlayFaceDown->setShortcut(QKeySequence());
|
aMoveTopToPlayFaceDown->setShortcut(QKeySequence());
|
||||||
aMoveTopCardToGraveyard->setShortcut(QKeySequence());
|
aMoveTopCardToGraveyard->setShortcut(QKeySequence());
|
||||||
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
|
aMoveTopCardsToGraveyard->setShortcut(QKeySequence());
|
||||||
aMoveTopCardToExile->setShortcut(QKeySequence());
|
aMoveTopCardToExile->setShortcut(QKeySequence());
|
||||||
aMoveTopCardsToExile->setShortcut(QKeySequence());
|
aMoveTopCardsToExile->setShortcut(QKeySequence());
|
||||||
|
aDrawBottomCard->setShortcut(QKeySequence());
|
||||||
|
aDrawBottomCards->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomToPlay->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomToPlayFaceDown->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomCardToGraveyard->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomCardsToGraveyard->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomCardToExile->setShortcut(QKeySequence());
|
||||||
|
aMoveBottomCardsToExile->setShortcut(QKeySequence());
|
||||||
|
|
||||||
QMapIterator<int, AbstractCounter *> counterIterator(counters);
|
QMapIterator<int, AbstractCounter *> counterIterator(counters);
|
||||||
while (counterIterator.hasNext()) {
|
while (counterIterator.hasNext()) {
|
||||||
|
|
@ -910,6 +985,7 @@ void Player::initSayMenu()
|
||||||
sayMenu->clear();
|
sayMenu->clear();
|
||||||
|
|
||||||
int count = SettingsCache::instance().messages().getCount();
|
int count = SettingsCache::instance().messages().getCount();
|
||||||
|
sayMenu->setEnabled(count > 0);
|
||||||
|
|
||||||
for (int i = 0; i < count; ++i) {
|
for (int i = 0; i < count; ++i) {
|
||||||
auto *newAction = new QAction(SettingsCache::instance().messages().getMessageAt(i), this);
|
auto *newAction = new QAction(SettingsCache::instance().messages().getMessageAt(i), this);
|
||||||
|
|
@ -927,10 +1003,14 @@ void Player::setDeck(const DeckLoader &_deck)
|
||||||
aOpenDeckInDeckEditor->setEnabled(deck);
|
aOpenDeckInDeckEditor->setEnabled(deck);
|
||||||
|
|
||||||
createPredefinedTokenMenu->clear();
|
createPredefinedTokenMenu->clear();
|
||||||
|
createPredefinedTokenMenu->setEnabled(false);
|
||||||
predefinedTokens.clear();
|
predefinedTokens.clear();
|
||||||
InnerDecklistNode *tokenZone = dynamic_cast<InnerDecklistNode *>(deck->getRoot()->findChild(DECK_ZONE_TOKENS));
|
InnerDecklistNode *tokenZone = dynamic_cast<InnerDecklistNode *>(deck->getRoot()->findChild(DECK_ZONE_TOKENS));
|
||||||
|
|
||||||
if (tokenZone)
|
if (tokenZone) {
|
||||||
|
if (tokenZone->size() > 0)
|
||||||
|
createPredefinedTokenMenu->setEnabled(true);
|
||||||
|
|
||||||
for (int i = 0; i < tokenZone->size(); ++i) {
|
for (int i = 0; i < tokenZone->size(); ++i) {
|
||||||
const QString tokenName = tokenZone->at(i)->getName();
|
const QString tokenName = tokenZone->at(i)->getName();
|
||||||
predefinedTokens.append(tokenName);
|
predefinedTokens.append(tokenName);
|
||||||
|
|
@ -940,6 +1020,7 @@ void Player::setDeck(const DeckLoader &_deck)
|
||||||
}
|
}
|
||||||
connect(a, SIGNAL(triggered()), this, SLOT(actCreatePredefinedToken()));
|
connect(a, SIGNAL(triggered()), this, SLOT(actCreatePredefinedToken()));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::actViewLibrary()
|
void Player::actViewLibrary()
|
||||||
|
|
@ -954,9 +1035,11 @@ void Player::actViewHand()
|
||||||
|
|
||||||
void Player::actViewTopCards()
|
void Player::actViewTopCards()
|
||||||
{
|
{
|
||||||
|
int deckSize = zones.value("deck")->getCards().size();
|
||||||
bool ok;
|
bool ok;
|
||||||
int number = QInputDialog::getInt(game, tr("View top cards of library"), tr("Number of cards:"),
|
int number =
|
||||||
defaultNumberTopCards, 1, 2000000000, 1, &ok);
|
QInputDialog::getInt(game, tr("View top cards of library"), tr("Number of cards: (max. %1)").arg(deckSize),
|
||||||
|
defaultNumberTopCards, 1, deckSize, 1, &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
defaultNumberTopCards = number;
|
defaultNumberTopCards = number;
|
||||||
static_cast<GameScene *>(scene())->toggleZoneView(this, "deck", number);
|
static_cast<GameScene *>(scene())->toggleZoneView(this, "deck", number);
|
||||||
|
|
@ -972,6 +1055,15 @@ void Player::actAlwaysRevealTopCard()
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::actAlwaysLookAtTopCard()
|
||||||
|
{
|
||||||
|
Command_ChangeZoneProperties cmd;
|
||||||
|
cmd.set_zone_name("deck");
|
||||||
|
cmd.set_always_look_at_top_card(aAlwaysLookAtTopCard->isChecked());
|
||||||
|
|
||||||
|
sendGameCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
void Player::actOpenDeckInDeckEditor()
|
void Player::actOpenDeckInDeckEditor()
|
||||||
{
|
{
|
||||||
emit openDeckEditor(deck);
|
emit openDeckEditor(deck);
|
||||||
|
|
@ -1021,10 +1113,11 @@ void Player::actMulligan()
|
||||||
{
|
{
|
||||||
int startSize = SettingsCache::instance().getStartingHandSize();
|
int startSize = SettingsCache::instance().getStartingHandSize();
|
||||||
int handSize = zones.value("hand")->getCards().size();
|
int handSize = zones.value("hand")->getCards().size();
|
||||||
int deckSize = zones.value("deck")->getCards().size() + handSize;
|
int deckSize = zones.value("deck")->getCards().size() + handSize; // hand is shuffled back into the deck
|
||||||
bool ok;
|
bool ok;
|
||||||
int number = QInputDialog::getInt(
|
int number = QInputDialog::getInt(game, tr("Draw hand"),
|
||||||
game, tr("Draw hand"), tr("Number of cards:") + '\n' + tr("0 and lower are in comparison to current hand size"),
|
tr("Number of cards: (max. %1)").arg(deckSize) + '\n' +
|
||||||
|
tr("0 and lower are in comparison to current hand size"),
|
||||||
startSize, -handSize, deckSize, 1, &ok);
|
startSize, -handSize, deckSize, 1, &ok);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -1046,8 +1139,12 @@ void Player::actMulligan()
|
||||||
|
|
||||||
void Player::actDrawCards()
|
void Player::actDrawCards()
|
||||||
{
|
{
|
||||||
int number = QInputDialog::getInt(game, tr("Draw cards"), tr("Number:"));
|
int deckSize = zones.value("deck")->getCards().size();
|
||||||
if (number) {
|
bool ok;
|
||||||
|
int number = QInputDialog::getInt(game, tr("Draw cards"), tr("Number of cards: (max. %1)").arg(deckSize),
|
||||||
|
defaultNumberTopCards, 1, deckSize, 1, &ok);
|
||||||
|
if (ok) {
|
||||||
|
defaultNumberTopCards = number;
|
||||||
Command_DrawCards cmd;
|
Command_DrawCards cmd;
|
||||||
cmd.set_number(static_cast<google::protobuf::uint32>(number));
|
cmd.set_number(static_cast<google::protobuf::uint32>(number));
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -1059,6 +1156,24 @@ void Player::actUndoDraw()
|
||||||
sendGameCommand(Command_UndoDraw());
|
sendGameCommand(Command_UndoDraw());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Player::cmdSetTopCard(Command_MoveCard &cmd)
|
||||||
|
{
|
||||||
|
cmd.set_start_zone("deck");
|
||||||
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
cardToMove->set_card_id(0);
|
||||||
|
cmd.set_target_player_id(getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::cmdSetBottomCard(Command_MoveCard &cmd)
|
||||||
|
{
|
||||||
|
CardZone *zone = zones.value("deck");
|
||||||
|
int lastCard = zone->getCards().size() - 1;
|
||||||
|
cmd.set_start_zone("deck");
|
||||||
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
cardToMove->set_card_id(lastCard);
|
||||||
|
cmd.set_target_player_id(getId());
|
||||||
|
}
|
||||||
|
|
||||||
void Player::actMoveTopCardToGrave()
|
void Player::actMoveTopCardToGrave()
|
||||||
{
|
{
|
||||||
if (zones.value("deck")->getCards().empty()) {
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
|
@ -1066,9 +1181,7 @@ void Player::actMoveTopCardToGrave()
|
||||||
}
|
}
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmdSetTopCard(cmd);
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(0);
|
|
||||||
cmd.set_target_player_id(getId());
|
|
||||||
cmd.set_target_zone("grave");
|
cmd.set_target_zone("grave");
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
@ -1083,9 +1196,7 @@ void Player::actMoveTopCardToExile()
|
||||||
}
|
}
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmdSetTopCard(cmd);
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(0);
|
|
||||||
cmd.set_target_player_id(getId());
|
|
||||||
cmd.set_target_zone("rfg");
|
cmd.set_target_zone("rfg");
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
@ -1095,15 +1206,21 @@ void Player::actMoveTopCardToExile()
|
||||||
|
|
||||||
void Player::actMoveTopCardsToGrave()
|
void Player::actMoveTopCardsToGrave()
|
||||||
{
|
{
|
||||||
int number = QInputDialog::getInt(game, tr("Move top cards to grave"), tr("Number:"));
|
const int maxCards = zones.value("deck")->getCards().size();
|
||||||
if (!number) {
|
if (maxCards == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int maxCards = zones.value("deck")->getCards().size();
|
bool ok;
|
||||||
if (number > maxCards) {
|
int number =
|
||||||
|
QInputDialog::getInt(game, tr("Move top cards to grave"), tr("Number of cards: (max. %1)").arg(maxCards),
|
||||||
|
defaultNumberTopCards, 1, maxCards, 1, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
} else if (number > maxCards) {
|
||||||
number = maxCards;
|
number = maxCards;
|
||||||
}
|
}
|
||||||
|
defaultNumberTopCards = number;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone("deck");
|
||||||
|
|
@ -1121,15 +1238,21 @@ void Player::actMoveTopCardsToGrave()
|
||||||
|
|
||||||
void Player::actMoveTopCardsToExile()
|
void Player::actMoveTopCardsToExile()
|
||||||
{
|
{
|
||||||
int number = QInputDialog::getInt(game, tr("Move top cards to exile"), tr("Number:"));
|
const int maxCards = zones.value("deck")->getCards().size();
|
||||||
if (!number) {
|
if (maxCards == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int maxCards = zones.value("deck")->getCards().size();
|
bool ok;
|
||||||
if (number > maxCards) {
|
int number =
|
||||||
|
QInputDialog::getInt(game, tr("Move top cards to exile"), tr("Number of cards: (max. %1)").arg(maxCards),
|
||||||
|
defaultNumberTopCards, 1, maxCards, 1, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
} else if (number > maxCards) {
|
||||||
number = maxCards;
|
number = maxCards;
|
||||||
}
|
}
|
||||||
|
defaultNumberTopCards = number;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone("deck");
|
||||||
|
|
@ -1147,12 +1270,14 @@ void Player::actMoveTopCardsToExile()
|
||||||
|
|
||||||
void Player::actMoveTopCardToBottom()
|
void Player::actMoveTopCardToBottom()
|
||||||
{
|
{
|
||||||
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmdSetTopCard(cmd);
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(0);
|
|
||||||
cmd.set_target_player_id(getId());
|
|
||||||
cmd.set_target_zone("deck");
|
cmd.set_target_zone("deck");
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1); // bottom of deck
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -1160,11 +1285,12 @@ void Player::actMoveTopCardToBottom()
|
||||||
|
|
||||||
void Player::actMoveTopCardToPlay()
|
void Player::actMoveTopCardToPlay()
|
||||||
{
|
{
|
||||||
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmdSetTopCard(cmd);
|
||||||
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
|
||||||
cardToMove->set_card_id(0);
|
|
||||||
cmd.set_target_player_id(getId());
|
|
||||||
cmd.set_target_zone("stack");
|
cmd.set_target_zone("stack");
|
||||||
cmd.set_x(-1);
|
cmd.set_x(-1);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
@ -1174,6 +1300,10 @@ void Player::actMoveTopCardToPlay()
|
||||||
|
|
||||||
void Player::actMoveTopCardToPlayFaceDown()
|
void Player::actMoveTopCardToPlayFaceDown()
|
||||||
{
|
{
|
||||||
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone("deck");
|
||||||
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
CardToMove *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
|
@ -1189,15 +1319,194 @@ void Player::actMoveTopCardToPlayFaceDown()
|
||||||
|
|
||||||
void Player::actMoveBottomCardToGrave()
|
void Player::actMoveBottomCardToGrave()
|
||||||
{
|
{
|
||||||
CardZone *zone = zones.value("deck");
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command_MoveCard cmd;
|
||||||
|
cmdSetBottomCard(cmd);
|
||||||
|
cmd.set_target_zone("grave");
|
||||||
|
cmd.set_x(0);
|
||||||
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
sendGameCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::actMoveBottomCardToExile()
|
||||||
|
{
|
||||||
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command_MoveCard cmd;
|
||||||
|
cmdSetBottomCard(cmd);
|
||||||
|
cmd.set_target_zone("rfg");
|
||||||
|
cmd.set_x(0);
|
||||||
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
sendGameCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::actMoveBottomCardsToGrave()
|
||||||
|
{
|
||||||
|
const int maxCards = zones.value("deck")->getCards().size();
|
||||||
|
if (maxCards == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
int number =
|
||||||
|
QInputDialog::getInt(game, tr("Move bottom cards to grave"), tr("Number of cards: (max. %1)").arg(maxCards),
|
||||||
|
defaultNumberBottomCards, 1, maxCards, 1, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
} else if (number > maxCards) {
|
||||||
|
number = maxCards;
|
||||||
|
}
|
||||||
|
defaultNumberBottomCards = number;
|
||||||
|
|
||||||
Command_MoveCard cmd;
|
Command_MoveCard cmd;
|
||||||
cmd.set_start_zone("deck");
|
cmd.set_start_zone("deck");
|
||||||
cmd.mutable_cards_to_move()->add_card()->set_card_id(zone->getCards().size() - 1);
|
|
||||||
cmd.set_target_player_id(getId());
|
cmd.set_target_player_id(getId());
|
||||||
cmd.set_target_zone("grave");
|
cmd.set_target_zone("grave");
|
||||||
cmd.set_x(0);
|
cmd.set_x(0);
|
||||||
cmd.set_y(0);
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
for (int i = maxCards - number; i < maxCards; ++i) {
|
||||||
|
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendGameCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::actMoveBottomCardsToExile()
|
||||||
|
{
|
||||||
|
const int maxCards = zones.value("deck")->getCards().size();
|
||||||
|
if (maxCards == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
int number =
|
||||||
|
QInputDialog::getInt(game, tr("Move bottom cards to exile"), tr("Number of cards: (max. %1)").arg(maxCards),
|
||||||
|
defaultNumberBottomCards, 1, maxCards, 1, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
} else if (number > maxCards) {
|
||||||
|
number = maxCards;
|
||||||
|
}
|
||||||
|
defaultNumberBottomCards = number;
|
||||||
|
|
||||||
|
Command_MoveCard cmd;
|
||||||
|
cmd.set_start_zone("deck");
|
||||||
|
cmd.set_target_player_id(getId());
|
||||||
|
cmd.set_target_zone("rfg");
|
||||||
|
cmd.set_x(0);
|
||||||
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
for (int i = maxCards - number; i < maxCards; ++i) {
|
||||||
|
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendGameCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::actMoveBottomCardToTop()
|
||||||
|
{
|
||||||
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command_MoveCard cmd;
|
||||||
|
cmdSetBottomCard(cmd);
|
||||||
|
cmd.set_target_zone("deck");
|
||||||
|
cmd.set_x(0); // top of deck
|
||||||
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
sendGameCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::actDrawBottomCard()
|
||||||
|
{
|
||||||
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command_MoveCard cmd;
|
||||||
|
cmdSetBottomCard(cmd);
|
||||||
|
cmd.set_target_zone("hand");
|
||||||
|
cmd.set_x(0);
|
||||||
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
sendGameCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::actDrawBottomCards()
|
||||||
|
{
|
||||||
|
const int maxCards = zones.value("deck")->getCards().size();
|
||||||
|
if (maxCards == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ok;
|
||||||
|
int number = QInputDialog::getInt(game, tr("Draw bottom cards"), tr("Number of cards: (max. %1)").arg(maxCards),
|
||||||
|
defaultNumberBottomCards, 1, maxCards, 1, &ok);
|
||||||
|
if (!ok) {
|
||||||
|
return;
|
||||||
|
} else if (number > maxCards) {
|
||||||
|
number = maxCards;
|
||||||
|
}
|
||||||
|
defaultNumberBottomCards = number;
|
||||||
|
|
||||||
|
Command_MoveCard cmd;
|
||||||
|
cmd.set_start_zone("deck");
|
||||||
|
cmd.set_target_player_id(getId());
|
||||||
|
cmd.set_target_zone("hand");
|
||||||
|
cmd.set_x(0);
|
||||||
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
for (int i = maxCards - number; i < maxCards; ++i) {
|
||||||
|
cmd.mutable_cards_to_move()->add_card()->set_card_id(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
sendGameCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::actMoveBottomCardToPlay()
|
||||||
|
{
|
||||||
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Command_MoveCard cmd;
|
||||||
|
cmdSetBottomCard(cmd);
|
||||||
|
cmd.set_target_zone("stack");
|
||||||
|
cmd.set_x(-1);
|
||||||
|
cmd.set_y(0);
|
||||||
|
|
||||||
|
sendGameCommand(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Player::actMoveBottomCardToPlayFaceDown()
|
||||||
|
{
|
||||||
|
if (zones.value("deck")->getCards().empty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CardZone *zone = zones.value("deck");
|
||||||
|
int lastCard = zone->getCards().size() - 1;
|
||||||
|
|
||||||
|
Command_MoveCard cmd;
|
||||||
|
cmd.set_start_zone("deck");
|
||||||
|
auto *cardToMove = cmd.mutable_cards_to_move()->add_card();
|
||||||
|
cardToMove->set_card_id(lastCard);
|
||||||
|
cardToMove->set_face_down(true);
|
||||||
|
|
||||||
|
cmd.set_target_player_id(getId());
|
||||||
|
cmd.set_target_zone("table");
|
||||||
|
cmd.set_x(-1);
|
||||||
|
cmd.set_y(0);
|
||||||
|
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1214,8 +1523,10 @@ void Player::actUntapAll()
|
||||||
void Player::actRollDie()
|
void Player::actRollDie()
|
||||||
{
|
{
|
||||||
bool ok;
|
bool ok;
|
||||||
int sides = QInputDialog::getInt(game, tr("Roll die"), tr("Number of sides:"), 20, 2, 1000, 1, &ok);
|
int sides = QInputDialog::getInt(game, tr("Roll die"), tr("Number of sides:"), defaultNumberDieRoll, minDieRoll,
|
||||||
|
maxDieRoll, 1, &ok);
|
||||||
if (ok) {
|
if (ok) {
|
||||||
|
defaultNumberDieRoll = sides;
|
||||||
Command_RollDie cmd;
|
Command_RollDie cmd;
|
||||||
cmd.set_sides(static_cast<google::protobuf::uint32>(sides));
|
cmd.set_sides(static_cast<google::protobuf::uint32>(sides));
|
||||||
sendGameCommand(cmd);
|
sendGameCommand(cmd);
|
||||||
|
|
@ -1231,7 +1542,7 @@ void Player::actCreateToken()
|
||||||
|
|
||||||
lastTokenName = dlg.getName();
|
lastTokenName = dlg.getName();
|
||||||
lastTokenPT = dlg.getPT();
|
lastTokenPT = dlg.getPT();
|
||||||
CardInfoPtr correctedCard = db->getCardBySimpleName(lastTokenName);
|
CardInfoPtr correctedCard = db->guessCard(lastTokenName);
|
||||||
if (correctedCard) {
|
if (correctedCard) {
|
||||||
lastTokenName = correctedCard->getName();
|
lastTokenName = correctedCard->getName();
|
||||||
lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard->getTableRow());
|
lastTokenTableRow = TableZone::clampValidTableRow(2 - correctedCard->getTableRow());
|
||||||
|
|
@ -1533,8 +1844,10 @@ void Player::eventShuffle(const Event_Shuffle &event)
|
||||||
if (!zone) {
|
if (!zone) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (zone->getView() && zone->getView()->getRevealZone()) {
|
for (auto *view : zone->getViews()) {
|
||||||
zone->getView()->setWriteableRevealZone(false);
|
if (view != nullptr) {
|
||||||
|
emit view->beingDeleted();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
emit logShuffle(this, zone, event.start(), event.end());
|
emit logShuffle(this, zone, event.start(), event.end());
|
||||||
}
|
}
|
||||||
|
|
@ -1670,19 +1983,6 @@ void Player::eventDumpZone(const Event_DumpZone &event)
|
||||||
emit logDumpZone(this, zone, event.number_cards());
|
emit logDumpZone(this, zone, event.number_cards());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::eventStopDumpZone(const Event_StopDumpZone &event)
|
|
||||||
{
|
|
||||||
Player *zoneOwner = game->getPlayers().value(event.zone_owner_id(), 0);
|
|
||||||
if (!zoneOwner) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
CardZone *zone = zoneOwner->getZones().value(QString::fromStdString(event.zone_name()), 0);
|
|
||||||
if (!zone) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
emit logStopDumpZone(this, zone);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext &context)
|
void Player::eventMoveCard(const Event_MoveCard &event, const GameEventContext &context)
|
||||||
{
|
{
|
||||||
Player *startPlayer = game->getPlayers().value(event.start_player_id());
|
Player *startPlayer = game->getPlayers().value(event.start_player_id());
|
||||||
|
|
@ -1955,6 +2255,10 @@ void Player::eventChangeZoneProperties(const Event_ChangeZoneProperties &event)
|
||||||
zone->setAlwaysRevealTopCard(event.always_reveal_top_card());
|
zone->setAlwaysRevealTopCard(event.always_reveal_top_card());
|
||||||
emit logAlwaysRevealTopCard(this, zone, event.always_reveal_top_card());
|
emit logAlwaysRevealTopCard(this, zone, event.always_reveal_top_card());
|
||||||
}
|
}
|
||||||
|
if (event.has_always_look_at_top_card()) {
|
||||||
|
zone->setAlwaysRevealTopCard(event.always_look_at_top_card());
|
||||||
|
emit logAlwaysLookAtTopCard(this, zone, event.always_look_at_top_card());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::processGameEvent(GameEvent::GameEventType type, const GameEvent &event, const GameEventContext &context)
|
void Player::processGameEvent(GameEvent::GameEventType type, const GameEvent &event, const GameEventContext &context)
|
||||||
|
|
@ -1996,9 +2300,6 @@ void Player::processGameEvent(GameEvent::GameEventType type, const GameEvent &ev
|
||||||
case GameEvent::DUMP_ZONE:
|
case GameEvent::DUMP_ZONE:
|
||||||
eventDumpZone(event.GetExtension(Event_DumpZone::ext));
|
eventDumpZone(event.GetExtension(Event_DumpZone::ext));
|
||||||
break;
|
break;
|
||||||
case GameEvent::STOP_DUMP_ZONE:
|
|
||||||
eventStopDumpZone(event.GetExtension(Event_StopDumpZone::ext));
|
|
||||||
break;
|
|
||||||
case GameEvent::MOVE_CARD:
|
case GameEvent::MOVE_CARD:
|
||||||
eventMoveCard(event.GetExtension(Event_MoveCard::ext), context);
|
eventMoveCard(event.GetExtension(Event_MoveCard::ext), context);
|
||||||
break;
|
break;
|
||||||
|
|
@ -2404,11 +2705,13 @@ bool Player::clearCardsToDelete()
|
||||||
|
|
||||||
void Player::actMoveCardXCardsFromTop()
|
void Player::actMoveCardXCardsFromTop()
|
||||||
{
|
{
|
||||||
|
int deckSize = zones.value("deck")->getCards().size() + 1; // add the card to move to the deck
|
||||||
bool ok;
|
bool ok;
|
||||||
int number = QInputDialog::getInt(game, tr("Place card X cards from top of library"),
|
int number =
|
||||||
tr("How many cards from the top of the deck should this card be placed:"),
|
QInputDialog::getInt(game, tr("Place card X cards from top of library"),
|
||||||
defaultNumberTopCardsToPlaceBelow, 1, 2000000000, 1, &ok);
|
tr("Which position should this card be placed:") + "\n" + tr("(max. %1)").arg(deckSize),
|
||||||
number--;
|
defaultNumberTopCardsToPlaceBelow, 1, deckSize, 1, &ok);
|
||||||
|
number -= 1; // indexes start at 0
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -3219,6 +3522,7 @@ void Player::addRelatedCardActions(const CardItem *card, QMenu *cardMenu)
|
||||||
void Player::setCardMenu(QMenu *menu)
|
void Player::setCardMenu(QMenu *menu)
|
||||||
{
|
{
|
||||||
if (aCardMenu) {
|
if (aCardMenu) {
|
||||||
|
aCardMenu->setEnabled(menu != nullptr);
|
||||||
aCardMenu->setMenu(menu);
|
aCardMenu->setMenu(menu);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -3249,6 +3553,7 @@ void Player::setGameStarted()
|
||||||
{
|
{
|
||||||
if (local) {
|
if (local) {
|
||||||
aAlwaysRevealTopCard->setChecked(false);
|
aAlwaysRevealTopCard->setChecked(false);
|
||||||
|
aAlwaysLookAtTopCard->setChecked(false);
|
||||||
}
|
}
|
||||||
setConceded(false);
|
setConceded(false);
|
||||||
}
|
}
|
||||||
|
|
@ -3266,6 +3571,7 @@ void Player::setConceded(bool _conceded)
|
||||||
void Player::setZoneId(int _zoneId)
|
void Player::setZoneId(int _zoneId)
|
||||||
{
|
{
|
||||||
zoneId = _zoneId;
|
zoneId = _zoneId;
|
||||||
|
playerArea->setPlayerZoneId(_zoneId);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Player::setMirrored(bool _mirrored)
|
void Player::setMirrored(bool _mirrored)
|
||||||
|
|
|
||||||
|
|
@ -18,52 +18,51 @@ namespace protobuf
|
||||||
class Message;
|
class Message;
|
||||||
}
|
}
|
||||||
} // namespace google
|
} // namespace google
|
||||||
class CardDatabase;
|
|
||||||
class DeckLoader;
|
|
||||||
class QMenu;
|
|
||||||
class QAction;
|
|
||||||
class ZoneViewZone;
|
|
||||||
class TabGame;
|
|
||||||
class AbstractCounter;
|
|
||||||
class AbstractCardItem;
|
class AbstractCardItem;
|
||||||
class CardItem;
|
class AbstractCounter;
|
||||||
class ArrowTarget;
|
|
||||||
class ArrowItem;
|
class ArrowItem;
|
||||||
|
class ArrowTarget;
|
||||||
|
class CardDatabase;
|
||||||
|
class CardItem;
|
||||||
class CardZone;
|
class CardZone;
|
||||||
class StackZone;
|
|
||||||
class TableZone;
|
|
||||||
class HandZone;
|
|
||||||
class PlayerTarget;
|
|
||||||
class ServerInfo_User;
|
|
||||||
class ServerInfo_Player;
|
|
||||||
class ServerInfo_Arrow;
|
|
||||||
class ServerInfo_Counter;
|
|
||||||
class CommandContainer;
|
class CommandContainer;
|
||||||
|
class Command_MoveCard;
|
||||||
|
class DeckLoader;
|
||||||
|
class Event_AttachCard;
|
||||||
|
class Event_ChangeZoneProperties;
|
||||||
|
class Event_CreateArrow;
|
||||||
|
class Event_CreateCounter;
|
||||||
|
class Event_CreateToken;
|
||||||
|
class Event_DelCounter;
|
||||||
|
class Event_DeleteArrow;
|
||||||
|
class Event_DestroyCard;
|
||||||
|
class Event_DrawCards;
|
||||||
|
class Event_DumpZone;
|
||||||
|
class Event_FlipCard;
|
||||||
|
class Event_GameSay;
|
||||||
|
class Event_MoveCard;
|
||||||
|
class Event_RevealCards;
|
||||||
|
class Event_RollDie;
|
||||||
|
class Event_SetCardAttr;
|
||||||
|
class Event_SetCardCounter;
|
||||||
|
class Event_SetCounter;
|
||||||
|
class Event_Shuffle;
|
||||||
class GameCommand;
|
class GameCommand;
|
||||||
class GameEvent;
|
class GameEvent;
|
||||||
class GameEventContext;
|
class GameEventContext;
|
||||||
// class Event_ConnectionStateChanged;
|
class HandZone;
|
||||||
class Event_GameSay;
|
|
||||||
class Event_Shuffle;
|
|
||||||
class Event_RollDie;
|
|
||||||
class Event_CreateArrow;
|
|
||||||
class Event_DeleteArrow;
|
|
||||||
class Event_CreateToken;
|
|
||||||
class Event_SetCardAttr;
|
|
||||||
class Event_SetCardCounter;
|
|
||||||
class Event_CreateCounter;
|
|
||||||
class Event_SetCounter;
|
|
||||||
class Event_DelCounter;
|
|
||||||
class Event_DumpZone;
|
|
||||||
class Event_StopDumpZone;
|
|
||||||
class Event_MoveCard;
|
|
||||||
class Event_FlipCard;
|
|
||||||
class Event_DestroyCard;
|
|
||||||
class Event_AttachCard;
|
|
||||||
class Event_DrawCards;
|
|
||||||
class Event_RevealCards;
|
|
||||||
class Event_ChangeZoneProperties;
|
|
||||||
class PendingCommand;
|
class PendingCommand;
|
||||||
|
class PlayerTarget;
|
||||||
|
class QAction;
|
||||||
|
class QMenu;
|
||||||
|
class ServerInfo_Arrow;
|
||||||
|
class ServerInfo_Counter;
|
||||||
|
class ServerInfo_Player;
|
||||||
|
class ServerInfo_User;
|
||||||
|
class StackZone;
|
||||||
|
class TabGame;
|
||||||
|
class TableZone;
|
||||||
|
class ZoneViewZone;
|
||||||
|
|
||||||
const int MAX_TOKENS_PER_DIALOG = 99;
|
const int MAX_TOKENS_PER_DIALOG = 99;
|
||||||
|
|
||||||
|
|
@ -73,6 +72,7 @@ class PlayerArea : public QObject, public QGraphicsItem
|
||||||
Q_INTERFACES(QGraphicsItem)
|
Q_INTERFACES(QGraphicsItem)
|
||||||
private:
|
private:
|
||||||
QRectF bRect;
|
QRectF bRect;
|
||||||
|
int playerZoneId;
|
||||||
private slots:
|
private slots:
|
||||||
void updateBg();
|
void updateBg();
|
||||||
|
|
||||||
|
|
@ -94,6 +94,12 @@ public:
|
||||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||||
|
|
||||||
void setSize(qreal width, qreal height);
|
void setSize(qreal width, qreal height);
|
||||||
|
|
||||||
|
void setPlayerZoneId(int _playerZoneId);
|
||||||
|
int getPlayerZoneId() const
|
||||||
|
{
|
||||||
|
return playerZoneId;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Player : public QObject, public QGraphicsItem
|
class Player : public QObject, public QGraphicsItem
|
||||||
|
|
@ -128,7 +134,6 @@ signals:
|
||||||
void logSetPT(Player *player, CardItem *card, QString newPT);
|
void logSetPT(Player *player, CardItem *card, QString newPT);
|
||||||
void logSetAnnotation(Player *player, CardItem *card, QString newAnnotation);
|
void logSetAnnotation(Player *player, CardItem *card, QString newAnnotation);
|
||||||
void logDumpZone(Player *player, CardZone *zone, int numberCards);
|
void logDumpZone(Player *player, CardZone *zone, int numberCards);
|
||||||
void logStopDumpZone(Player *player, CardZone *zone);
|
|
||||||
void logRevealCards(Player *player,
|
void logRevealCards(Player *player,
|
||||||
CardZone *zone,
|
CardZone *zone,
|
||||||
int cardId,
|
int cardId,
|
||||||
|
|
@ -137,6 +142,7 @@ signals:
|
||||||
bool faceDown,
|
bool faceDown,
|
||||||
int amount);
|
int amount);
|
||||||
void logAlwaysRevealTopCard(Player *player, CardZone *zone, bool reveal);
|
void logAlwaysRevealTopCard(Player *player, CardZone *zone, bool reveal);
|
||||||
|
void logAlwaysLookAtTopCard(Player *player, CardZone *zone, bool reveal);
|
||||||
|
|
||||||
void sizeChanged();
|
void sizeChanged();
|
||||||
void playerCountChanged();
|
void playerCountChanged();
|
||||||
|
|
@ -157,12 +163,21 @@ public slots:
|
||||||
void actMoveTopCardsToGrave();
|
void actMoveTopCardsToGrave();
|
||||||
void actMoveTopCardsToExile();
|
void actMoveTopCardsToExile();
|
||||||
void actMoveTopCardToBottom();
|
void actMoveTopCardToBottom();
|
||||||
|
void actDrawBottomCard();
|
||||||
|
void actDrawBottomCards();
|
||||||
|
void actMoveBottomCardToPlay();
|
||||||
|
void actMoveBottomCardToPlayFaceDown();
|
||||||
void actMoveBottomCardToGrave();
|
void actMoveBottomCardToGrave();
|
||||||
|
void actMoveBottomCardToExile();
|
||||||
|
void actMoveBottomCardsToGrave();
|
||||||
|
void actMoveBottomCardsToExile();
|
||||||
|
void actMoveBottomCardToTop();
|
||||||
|
|
||||||
void actViewLibrary();
|
void actViewLibrary();
|
||||||
void actViewHand();
|
void actViewHand();
|
||||||
void actViewTopCards();
|
void actViewTopCards();
|
||||||
void actAlwaysRevealTopCard();
|
void actAlwaysRevealTopCard();
|
||||||
|
void actAlwaysLookAtTopCard();
|
||||||
void actViewGraveyard();
|
void actViewGraveyard();
|
||||||
void actRevealRandomGraveyardCard();
|
void actRevealRandomGraveyardCard();
|
||||||
void actViewRfg();
|
void actViewRfg();
|
||||||
|
|
@ -208,17 +223,20 @@ private:
|
||||||
TabGame *game;
|
TabGame *game;
|
||||||
QMenu *sbMenu, *countersMenu, *sayMenu, *createPredefinedTokenMenu, *mRevealLibrary, *mRevealTopCard, *mRevealHand,
|
QMenu *sbMenu, *countersMenu, *sayMenu, *createPredefinedTokenMenu, *mRevealLibrary, *mRevealTopCard, *mRevealHand,
|
||||||
*mRevealRandomHandCard, *mRevealRandomGraveyardCard;
|
*mRevealRandomHandCard, *mRevealRandomGraveyardCard;
|
||||||
TearOffMenu *moveGraveMenu, *moveRfgMenu, *graveMenu, *moveHandMenu, *handMenu, *libraryMenu, *rfgMenu, *playerMenu;
|
TearOffMenu *moveGraveMenu, *moveRfgMenu, *graveMenu, *moveHandMenu, *handMenu, *libraryMenu, *topLibraryMenu,
|
||||||
|
*bottomLibraryMenu, *rfgMenu, *playerMenu;
|
||||||
QList<QMenu *> playerLists;
|
QList<QMenu *> playerLists;
|
||||||
QList<QAction *> allPlayersActions;
|
QList<QAction *> allPlayersActions;
|
||||||
QAction *aMoveHandToTopLibrary, *aMoveHandToBottomLibrary, *aMoveHandToGrave, *aMoveHandToRfg,
|
QAction *aMoveHandToTopLibrary, *aMoveHandToBottomLibrary, *aMoveHandToGrave, *aMoveHandToRfg,
|
||||||
*aMoveGraveToTopLibrary, *aMoveGraveToBottomLibrary, *aMoveGraveToHand, *aMoveGraveToRfg, *aMoveRfgToTopLibrary,
|
*aMoveGraveToTopLibrary, *aMoveGraveToBottomLibrary, *aMoveGraveToHand, *aMoveGraveToRfg, *aMoveRfgToTopLibrary,
|
||||||
*aMoveRfgToBottomLibrary, *aMoveRfgToHand, *aMoveRfgToGrave, *aViewHand, *aViewLibrary, *aViewTopCards,
|
*aMoveRfgToBottomLibrary, *aMoveRfgToHand, *aMoveRfgToGrave, *aViewHand, *aViewLibrary, *aViewTopCards,
|
||||||
*aAlwaysRevealTopCard, *aOpenDeckInDeckEditor, *aMoveTopCardToGraveyard, *aMoveTopCardToExile,
|
*aAlwaysRevealTopCard, *aAlwaysLookAtTopCard, *aOpenDeckInDeckEditor, *aMoveTopCardToGraveyard,
|
||||||
*aMoveTopCardsToGraveyard, *aMoveTopCardsToExile, *aMoveTopCardToBottom, *aViewGraveyard, *aViewRfg,
|
*aMoveTopCardToExile, *aMoveTopCardsToGraveyard, *aMoveTopCardsToExile, *aMoveTopCardToBottom, *aViewGraveyard,
|
||||||
*aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw, *aMulligan, *aShuffle, *aMoveTopToPlay,
|
*aViewRfg, *aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw, *aMulligan, *aShuffle, *aMoveTopToPlay,
|
||||||
*aMoveTopToPlayFaceDown, *aUntapAll, *aRollDie, *aCreateToken, *aCreateAnotherToken, *aCardMenu,
|
*aMoveTopToPlayFaceDown, *aUntapAll, *aRollDie, *aCreateToken, *aCreateAnotherToken, *aCardMenu,
|
||||||
*aMoveBottomCardToGrave;
|
*aMoveBottomToPlay, *aMoveBottomToPlayFaceDown, *aMoveBottomCardToTop, *aMoveBottomCardToGraveyard,
|
||||||
|
*aMoveBottomCardToExile, *aMoveBottomCardsToGraveyard, *aMoveBottomCardsToExile, *aDrawBottomCard,
|
||||||
|
*aDrawBottomCards;
|
||||||
|
|
||||||
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
|
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
|
||||||
QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT,
|
QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT,
|
||||||
|
|
@ -227,8 +245,12 @@ private:
|
||||||
*aMoveToXfromTopOfLibrary;
|
*aMoveToXfromTopOfLibrary;
|
||||||
|
|
||||||
bool shortcutsActive;
|
bool shortcutsActive;
|
||||||
int defaultNumberTopCards;
|
int defaultNumberTopCards = 1;
|
||||||
int defaultNumberTopCardsToPlaceBelow;
|
int defaultNumberTopCardsToPlaceBelow = 1;
|
||||||
|
int defaultNumberBottomCards = 1;
|
||||||
|
int defaultNumberDieRoll = 20;
|
||||||
|
static constexpr int minDieRoll = 2;
|
||||||
|
static constexpr int maxDieRoll = 1000000;
|
||||||
QString lastTokenName, lastTokenColor, lastTokenPT, lastTokenAnnotation;
|
QString lastTokenName, lastTokenColor, lastTokenPT, lastTokenAnnotation;
|
||||||
bool lastTokenDestroy;
|
bool lastTokenDestroy;
|
||||||
int lastTokenTableRow;
|
int lastTokenTableRow;
|
||||||
|
|
@ -288,7 +310,6 @@ private:
|
||||||
void eventSetCounter(const Event_SetCounter &event);
|
void eventSetCounter(const Event_SetCounter &event);
|
||||||
void eventDelCounter(const Event_DelCounter &event);
|
void eventDelCounter(const Event_DelCounter &event);
|
||||||
void eventDumpZone(const Event_DumpZone &event);
|
void eventDumpZone(const Event_DumpZone &event);
|
||||||
void eventStopDumpZone(const Event_StopDumpZone &event);
|
|
||||||
void eventMoveCard(const Event_MoveCard &event, const GameEventContext &context);
|
void eventMoveCard(const Event_MoveCard &event, const GameEventContext &context);
|
||||||
void eventFlipCard(const Event_FlipCard &event);
|
void eventFlipCard(const Event_FlipCard &event);
|
||||||
void eventDestroyCard(const Event_DestroyCard &event);
|
void eventDestroyCard(const Event_DestroyCard &event);
|
||||||
|
|
@ -296,6 +317,8 @@ private:
|
||||||
void eventDrawCards(const Event_DrawCards &event);
|
void eventDrawCards(const Event_DrawCards &event);
|
||||||
void eventRevealCards(const Event_RevealCards &event);
|
void eventRevealCards(const Event_RevealCards &event);
|
||||||
void eventChangeZoneProperties(const Event_ChangeZoneProperties &event);
|
void eventChangeZoneProperties(const Event_ChangeZoneProperties &event);
|
||||||
|
void cmdSetTopCard(Command_MoveCard &cmd);
|
||||||
|
void cmdSetBottomCard(Command_MoveCard &cmd);
|
||||||
|
|
||||||
QVariantList parsePT(const QString &pt);
|
QVariantList parsePT(const QString &pt);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
#include "pb/serverinfo_playerproperties.pb.h"
|
#include "pb/serverinfo_playerproperties.pb.h"
|
||||||
#include "pb/session_commands.pb.h"
|
#include "pb/session_commands.pb.h"
|
||||||
#include "pixmapgenerator.h"
|
#include "pixmapgenerator.h"
|
||||||
|
#include "tab_account.h"
|
||||||
#include "tab_game.h"
|
#include "tab_game.h"
|
||||||
#include "tab_supervisor.h"
|
#include "tab_supervisor.h"
|
||||||
#include "tab_userlists.h"
|
|
||||||
#include "user_context_menu.h"
|
#include "user_context_menu.h"
|
||||||
#include "userlist.h"
|
#include "userlist.h"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,7 @@ PlayerCounter::PlayerCounter(Player *_player,
|
||||||
|
|
||||||
QRectF PlayerCounter::boundingRect() const
|
QRectF PlayerCounter::boundingRect() const
|
||||||
{
|
{
|
||||||
return QRectF(0, 0, 50, 30);
|
return {0, 0, 50, 30};
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
|
|
@ -56,13 +56,14 @@ void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerTarget::PlayerTarget(Player *_owner, QGraphicsItem *parentItem, QWidget *_game)
|
PlayerTarget::PlayerTarget(Player *_owner, QGraphicsItem *parentItem, QWidget *_game)
|
||||||
: ArrowTarget(_owner, parentItem), playerCounter(0), game(_game)
|
: ArrowTarget(_owner, parentItem), playerCounter(nullptr), game(_game)
|
||||||
{
|
{
|
||||||
setCacheMode(DeviceCoordinateCache);
|
setCacheMode(DeviceCoordinateCache);
|
||||||
|
|
||||||
const std::string &bmp = _owner->getUserInfo()->avatar_bmp();
|
const std::string &bmp = _owner->getUserInfo()->avatar_bmp();
|
||||||
if (!fullPixmap.loadFromData((const uchar *)bmp.data(), bmp.size()))
|
if (!fullPixmap.loadFromData((const uchar *)bmp.data(), static_cast<uint>(bmp.size()))) {
|
||||||
fullPixmap = QPixmap();
|
fullPixmap = QPixmap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PlayerTarget::~PlayerTarget()
|
PlayerTarget::~PlayerTarget()
|
||||||
|
|
@ -74,7 +75,7 @@ PlayerTarget::~PlayerTarget()
|
||||||
|
|
||||||
QRectF PlayerTarget::boundingRect() const
|
QRectF PlayerTarget::boundingRect() const
|
||||||
{
|
{
|
||||||
return QRectF(0, 0, 160, 64);
|
return {0, 0, 160, 64};
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
|
|
@ -153,7 +154,7 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o
|
||||||
AbstractCounter *PlayerTarget::addCounter(int _counterId, const QString &_name, int _value)
|
AbstractCounter *PlayerTarget::addCounter(int _counterId, const QString &_name, int _value)
|
||||||
{
|
{
|
||||||
if (playerCounter) {
|
if (playerCounter) {
|
||||||
disconnect(playerCounter, 0, this, 0);
|
disconnect(playerCounter, nullptr, this, nullptr);
|
||||||
playerCounter->delCounter();
|
playerCounter->delCounter();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,5 +168,5 @@ AbstractCounter *PlayerTarget::addCounter(int _counterId, const QString &_name,
|
||||||
|
|
||||||
void PlayerTarget::counterDeleted()
|
void PlayerTarget::counterDeleted()
|
||||||
{
|
{
|
||||||
playerCounter = 0;
|
playerCounter = nullptr;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@
|
||||||
#include <QJsonObject>
|
#include <QJsonObject>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QNetworkReply>
|
#include <QNetworkReply>
|
||||||
|
#include <QRegularExpression>
|
||||||
#include <QSysInfo>
|
#include <QSysInfo>
|
||||||
#include <QtGlobal>
|
#include <QtGlobal>
|
||||||
|
|
||||||
|
|
@ -45,24 +46,19 @@ void ReleaseChannel::checkForUpdates()
|
||||||
#if defined(Q_OS_OSX)
|
#if defined(Q_OS_OSX)
|
||||||
bool ReleaseChannel::downloadMatchesCurrentOS(const QString &fileName)
|
bool ReleaseChannel::downloadMatchesCurrentOS(const QString &fileName)
|
||||||
{
|
{
|
||||||
const int mac_os_version = QSysInfo::productVersion().split(".")[1].toInt();
|
static QRegularExpression version_regex("macOS-(\\d+)\\.(\\d+)");
|
||||||
|
auto match = version_regex.match(fileName);
|
||||||
// TODO: If we change macOS builds, this must be updated
|
if (!match.hasMatch()) {
|
||||||
if (mac_os_version <= 12) {
|
|
||||||
// We no longer compile files for macOS 10.12 Sierra or older
|
|
||||||
return false;
|
return false;
|
||||||
} else if (mac_os_version == 13) {
|
|
||||||
// We support 10.13 High Sierra
|
|
||||||
return fileName.contains("macos10.13");
|
|
||||||
} else if (14 <= mac_os_version && mac_os_version <= 15) {
|
|
||||||
// We support 10.14 Mojave, and 10.15 Catalina
|
|
||||||
return fileName.contains("macos10.14");
|
|
||||||
} else {
|
|
||||||
// Future Mac releases we haven't heard of or accounted for yet
|
|
||||||
return (!fileName.contains("macos10.13") && !fileName.contains("macos10.14") && fileName.contains("macos"));
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
// older(smaller) releases are compatible with a newer or the same system version
|
||||||
|
int sys_maj = QSysInfo::productVersion().split(".")[0].toInt();
|
||||||
|
int sys_min = QSysInfo::productVersion().split(".")[1].toInt();
|
||||||
|
int rel_maj = match.captured(1).toInt();
|
||||||
|
int rel_min = match.captured(2).toInt();
|
||||||
|
return rel_maj < sys_maj || (rel_maj == sys_maj && rel_min <= sys_min);
|
||||||
|
}
|
||||||
#elif defined(Q_OS_WIN)
|
#elif defined(Q_OS_WIN)
|
||||||
bool ReleaseChannel::downloadMatchesCurrentOS(const QString &fileName)
|
bool ReleaseChannel::downloadMatchesCurrentOS(const QString &fileName)
|
||||||
{
|
{
|
||||||
|
|
@ -283,19 +279,22 @@ void BetaReleaseChannel::fileListFinished()
|
||||||
bool needToUpdate = (QString::compare(shortHash, myHash, Qt::CaseInsensitive) != 0);
|
bool needToUpdate = (QString::compare(shortHash, myHash, Qt::CaseInsensitive) != 0);
|
||||||
bool compatibleVersion = false;
|
bool compatibleVersion = false;
|
||||||
|
|
||||||
foreach (QVariant file, resultList) {
|
QStringList resultUrlList{};
|
||||||
|
for (QVariant file : resultList) {
|
||||||
QVariantMap map = file.toMap();
|
QVariantMap map = file.toMap();
|
||||||
|
resultUrlList << map["browser_download_url"].toString();
|
||||||
|
}
|
||||||
|
|
||||||
QString url = map["browser_download_url"].toString();
|
resultUrlList.sort();
|
||||||
|
// iterate in reverse so the first item is the latest os version
|
||||||
if (!downloadMatchesCurrentOS(url))
|
for (auto url = resultUrlList.rbegin(); url < resultUrlList.rend(); ++url) {
|
||||||
continue;
|
if (downloadMatchesCurrentOS(*url)) {
|
||||||
|
|
||||||
compatibleVersion = true;
|
compatibleVersion = true;
|
||||||
lastRelease->setDownloadUrl(url);
|
lastRelease->setDownloadUrl(*url);
|
||||||
qDebug() << "Found compatible version url=" << url;
|
qDebug() << "Found compatible version url=" << *url;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
emit finishedCheck(needToUpdate, compatibleVersion, lastRelease);
|
emit finishedCheck(needToUpdate, compatibleVersion, lastRelease);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -337,9 +337,9 @@ void RemoteClient::websocketMessageReceived(const QByteArray &message)
|
||||||
void RemoteClient::sendCommandContainer(const CommandContainer &cont)
|
void RemoteClient::sendCommandContainer(const CommandContainer &cont)
|
||||||
{
|
{
|
||||||
#if GOOGLE_PROTOBUF_VERSION > 3001000
|
#if GOOGLE_PROTOBUF_VERSION > 3001000
|
||||||
unsigned int size = cont.ByteSizeLong();
|
auto size = static_cast<unsigned int>(cont.ByteSizeLong());
|
||||||
#else
|
#else
|
||||||
unsigned int size = cont.ByteSize();
|
auto size = static_cast<unsigned int>(cont.ByteSize());
|
||||||
#endif
|
#endif
|
||||||
#ifdef QT_DEBUG
|
#ifdef QT_DEBUG
|
||||||
qDebug() << "OUT" << size << QString::fromStdString(cont.ShortDebugString());
|
qDebug() << "OUT" << size << QString::fromStdString(cont.ShortDebugString());
|
||||||
|
|
@ -419,7 +419,7 @@ void RemoteClient::doActivateToServer(const QString &_token)
|
||||||
|
|
||||||
token = _token.trimmed();
|
token = _token.trimmed();
|
||||||
|
|
||||||
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
|
connectToHost(lastHostname, lastPort);
|
||||||
setStatus(StatusActivating);
|
setStatus(StatusActivating);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -502,7 +502,7 @@ void RemoteClient::disconnectFromServer()
|
||||||
emit sigDisconnectFromServer();
|
emit sigDisconnectFromServer();
|
||||||
}
|
}
|
||||||
|
|
||||||
QString RemoteClient::getSrvClientID(const QString _hostname)
|
QString RemoteClient::getSrvClientID(const QString &_hostname)
|
||||||
{
|
{
|
||||||
QString srvClientID = SettingsCache::instance().getClientID();
|
QString srvClientID = SettingsCache::instance().getClientID();
|
||||||
QHostInfo hostInfo = QHostInfo::fromName(_hostname);
|
QHostInfo hostInfo = QHostInfo::fromName(_hostname);
|
||||||
|
|
@ -518,11 +518,11 @@ QString RemoteClient::getSrvClientID(const QString _hostname)
|
||||||
return uniqueServerClientID;
|
return uniqueServerClientID;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RemoteClient::newMissingFeatureFound(QString _serversMissingFeatures)
|
bool RemoteClient::newMissingFeatureFound(const QString &_serversMissingFeatures)
|
||||||
{
|
{
|
||||||
bool newMissingFeature = false;
|
bool newMissingFeature = false;
|
||||||
QStringList serversMissingFeaturesList = _serversMissingFeatures.split(",");
|
QStringList serversMissingFeaturesList = _serversMissingFeatures.split(",");
|
||||||
foreach (const QString &feature, serversMissingFeaturesList) {
|
for (const QString &feature : serversMissingFeaturesList) {
|
||||||
if (!feature.isEmpty()) {
|
if (!feature.isEmpty()) {
|
||||||
if (!SettingsCache::instance().getKnownMissingFeatures().contains(feature))
|
if (!SettingsCache::instance().getKnownMissingFeatures().contains(feature))
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -535,7 +535,7 @@ void RemoteClient::clearNewClientFeatures()
|
||||||
{
|
{
|
||||||
QString newKnownMissingFeatures;
|
QString newKnownMissingFeatures;
|
||||||
QStringList existingKnownMissingFeatures = SettingsCache::instance().getKnownMissingFeatures().split(",");
|
QStringList existingKnownMissingFeatures = SettingsCache::instance().getKnownMissingFeatures().split(",");
|
||||||
foreach (const QString &existingKnownFeature, existingKnownMissingFeatures) {
|
for (const QString &existingKnownFeature : existingKnownMissingFeatures) {
|
||||||
if (!existingKnownFeature.isEmpty()) {
|
if (!existingKnownFeature.isEmpty()) {
|
||||||
if (!clientFeatures.contains(existingKnownFeature))
|
if (!clientFeatures.contains(existingKnownFeature))
|
||||||
newKnownMissingFeatures.append("," + existingKnownFeature);
|
newKnownMissingFeatures.append("," + existingKnownFeature);
|
||||||
|
|
@ -566,7 +566,7 @@ void RemoteClient::doRequestForgotPasswordToServer(const QString &hostname, unsi
|
||||||
lastHostname = hostname;
|
lastHostname = hostname;
|
||||||
lastPort = port;
|
lastPort = port;
|
||||||
|
|
||||||
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
|
connectToHost(lastHostname, lastPort);
|
||||||
setStatus(StatusRequestingForgotPassword);
|
setStatus(StatusRequestingForgotPassword);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -598,7 +598,7 @@ void RemoteClient::doSubmitForgotPasswordResetToServer(const QString &hostname,
|
||||||
token = _token.trimmed();
|
token = _token.trimmed();
|
||||||
password = _newpassword;
|
password = _newpassword;
|
||||||
|
|
||||||
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
|
connectToHost(lastHostname, lastPort);
|
||||||
setStatus(StatusSubmitForgotPasswordReset);
|
setStatus(StatusSubmitForgotPasswordReset);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -632,7 +632,7 @@ void RemoteClient::doSubmitForgotPasswordChallengeToServer(const QString &hostna
|
||||||
lastPort = port;
|
lastPort = port;
|
||||||
email = _email;
|
email = _email;
|
||||||
|
|
||||||
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
|
connectToHost(lastHostname, lastPort);
|
||||||
setStatus(StatusSubmitForgotPasswordChallenge);
|
setStatus(StatusSubmitForgotPasswordChallenge);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,10 +97,10 @@ private:
|
||||||
QTcpSocket *socket;
|
QTcpSocket *socket;
|
||||||
QWebSocket *websocket;
|
QWebSocket *websocket;
|
||||||
QString lastHostname;
|
QString lastHostname;
|
||||||
int lastPort;
|
unsigned int lastPort;
|
||||||
|
|
||||||
QString getSrvClientID(QString _hostname);
|
QString getSrvClientID(const QString &_hostname);
|
||||||
bool newMissingFeatureFound(QString _serversMissingFeatures);
|
bool newMissingFeatureFound(const QString &_serversMissingFeatures);
|
||||||
void clearNewClientFeatures();
|
void clearNewClientFeatures();
|
||||||
void connectToHost(const QString &hostname, unsigned int port);
|
void connectToHost(const QString &hostname, unsigned int port);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "gamefilterssettings.h"
|
#include "gamefilterssettings.h"
|
||||||
|
|
||||||
#include <QCryptographicHash>
|
#include <QCryptographicHash>
|
||||||
|
#include <QTime>
|
||||||
|
|
||||||
GameFiltersSettings::GameFiltersSettings(QString settingPath, QObject *parent)
|
GameFiltersSettings::GameFiltersSettings(QString settingPath, QObject *parent)
|
||||||
: SettingsManager(settingPath + "gamefilters.ini", parent)
|
: SettingsManager(settingPath + "gamefilters.ini", parent)
|
||||||
|
|
@ -27,14 +28,25 @@ bool GameFiltersSettings::isShowBuddiesOnlyGames()
|
||||||
return previous == QVariant() ? true : previous.toBool();
|
return previous == QVariant() ? true : previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setUnavailableGamesVisible(bool enabled)
|
void GameFiltersSettings::setShowFullGames(bool show)
|
||||||
{
|
{
|
||||||
setValue(enabled, "unavailable_games_visible", "filter_games");
|
setValue(show, "show_full_games", "filter_games");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool GameFiltersSettings::isUnavailableGamesVisible()
|
bool GameFiltersSettings::isShowFullGames()
|
||||||
{
|
{
|
||||||
QVariant previous = getValue("unavailable_games_visible", "filter_games");
|
QVariant previous = getValue("show_full_games", "filter_games");
|
||||||
|
return previous == QVariant() ? false : previous.toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameFiltersSettings::setShowGamesThatStarted(bool show)
|
||||||
|
{
|
||||||
|
setValue(show, "show_games_that_started", "filter_games");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameFiltersSettings::isShowGamesThatStarted()
|
||||||
|
{
|
||||||
|
QVariant previous = getValue("show_games_that_started", "filter_games");
|
||||||
return previous == QVariant() ? false : previous.toBool();
|
return previous == QVariant() ? false : previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -102,6 +114,17 @@ int GameFiltersSettings::getMaxPlayers()
|
||||||
return previous == QVariant() ? 99 : previous.toInt();
|
return previous == QVariant() ? 99 : previous.toInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameFiltersSettings::setMaxGameAge(const QTime &maxGameAge)
|
||||||
|
{
|
||||||
|
setValue(maxGameAge, "max_game_age_time", "filter_games");
|
||||||
|
}
|
||||||
|
|
||||||
|
QTime GameFiltersSettings::getMaxGameAge()
|
||||||
|
{
|
||||||
|
QVariant previous = getValue("max_game_age_time", "filter_games");
|
||||||
|
return previous.toTime();
|
||||||
|
}
|
||||||
|
|
||||||
void GameFiltersSettings::setGameTypeEnabled(QString gametype, bool enabled)
|
void GameFiltersSettings::setGameTypeEnabled(QString gametype, bool enabled)
|
||||||
{
|
{
|
||||||
setValue(enabled, "game_type/" + hashGameType(gametype), "filter_games");
|
setValue(enabled, "game_type/" + hashGameType(gametype), "filter_games");
|
||||||
|
|
@ -117,3 +140,47 @@ bool GameFiltersSettings::isGameTypeEnabled(QString gametype)
|
||||||
QVariant previous = getValue("game_type/" + hashGameType(gametype), "filter_games");
|
QVariant previous = getValue("game_type/" + hashGameType(gametype), "filter_games");
|
||||||
return previous == QVariant() ? false : previous.toBool();
|
return previous == QVariant() ? false : previous.toBool();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void GameFiltersSettings::setShowOnlyIfSpectatorsCanWatch(bool show)
|
||||||
|
{
|
||||||
|
setValue(show, "show_only_if_spectators_can_watch", "filter_games");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameFiltersSettings::isShowOnlyIfSpectatorsCanWatch()
|
||||||
|
{
|
||||||
|
QVariant previous = getValue("show_only_if_spectators_can_watch", "filter_games");
|
||||||
|
return previous == QVariant() ? false : previous.toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameFiltersSettings::setShowSpectatorPasswordProtected(bool show)
|
||||||
|
{
|
||||||
|
setValue(show, "show_spectator_password_protected", "filter_games");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameFiltersSettings::isShowSpectatorPasswordProtected()
|
||||||
|
{
|
||||||
|
QVariant previous = getValue("show_spectator_password_protected", "filter_games");
|
||||||
|
return previous == QVariant() ? true : previous.toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameFiltersSettings::setShowOnlyIfSpectatorsCanChat(bool show)
|
||||||
|
{
|
||||||
|
setValue(show, "show_only_if_spectators_can_chat", "filter_games");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameFiltersSettings::isShowOnlyIfSpectatorsCanChat()
|
||||||
|
{
|
||||||
|
QVariant previous = getValue("show_only_if_spectators_can_chat", "filter_games");
|
||||||
|
return previous == QVariant() ? true : previous.toBool();
|
||||||
|
}
|
||||||
|
|
||||||
|
void GameFiltersSettings::setShowOnlyIfSpectatorsCanSeeHands(bool show)
|
||||||
|
{
|
||||||
|
setValue(show, "show_only_if_spectators_can_see_hands", "filter_games");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool GameFiltersSettings::isShowOnlyIfSpectatorsCanSeeHands()
|
||||||
|
{
|
||||||
|
QVariant previous = getValue("show_only_if_spectators_can_see_hands", "filter_games");
|
||||||
|
return previous == QVariant() ? true : previous.toBool();
|
||||||
|
}
|
||||||
|
|
@ -10,25 +10,37 @@ class GameFiltersSettings : public SettingsManager
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool isShowBuddiesOnlyGames();
|
bool isShowBuddiesOnlyGames();
|
||||||
bool isUnavailableGamesVisible();
|
bool isShowFullGames();
|
||||||
|
bool isShowGamesThatStarted();
|
||||||
bool isShowPasswordProtectedGames();
|
bool isShowPasswordProtectedGames();
|
||||||
bool isHideIgnoredUserGames();
|
bool isHideIgnoredUserGames();
|
||||||
QString getGameNameFilter();
|
QString getGameNameFilter();
|
||||||
QString getCreatorNameFilter();
|
QString getCreatorNameFilter();
|
||||||
int getMinPlayers();
|
int getMinPlayers();
|
||||||
int getMaxPlayers();
|
int getMaxPlayers();
|
||||||
|
QTime getMaxGameAge();
|
||||||
bool isGameTypeEnabled(QString gametype);
|
bool isGameTypeEnabled(QString gametype);
|
||||||
|
bool isShowOnlyIfSpectatorsCanWatch();
|
||||||
|
bool isShowSpectatorPasswordProtected();
|
||||||
|
bool isShowOnlyIfSpectatorsCanChat();
|
||||||
|
bool isShowOnlyIfSpectatorsCanSeeHands();
|
||||||
|
|
||||||
void setShowBuddiesOnlyGames(bool show);
|
void setShowBuddiesOnlyGames(bool show);
|
||||||
void setHideIgnoredUserGames(bool hide);
|
void setHideIgnoredUserGames(bool hide);
|
||||||
void setUnavailableGamesVisible(bool enabled);
|
void setShowFullGames(bool show);
|
||||||
|
void setShowGamesThatStarted(bool show);
|
||||||
void setShowPasswordProtectedGames(bool show);
|
void setShowPasswordProtectedGames(bool show);
|
||||||
void setGameNameFilter(QString gameName);
|
void setGameNameFilter(QString gameName);
|
||||||
void setCreatorNameFilter(QString creatorName);
|
void setCreatorNameFilter(QString creatorName);
|
||||||
void setMinPlayers(int min);
|
void setMinPlayers(int min);
|
||||||
void setMaxPlayers(int max);
|
void setMaxPlayers(int max);
|
||||||
|
void setMaxGameAge(const QTime &maxGameAge);
|
||||||
void setGameTypeEnabled(QString gametype, bool enabled);
|
void setGameTypeEnabled(QString gametype, bool enabled);
|
||||||
void setGameHashedTypeEnabled(QString gametypeHASHED, bool enabled);
|
void setGameHashedTypeEnabled(QString gametypeHASHED, bool enabled);
|
||||||
|
void setShowOnlyIfSpectatorsCanWatch(bool show);
|
||||||
|
void setShowSpectatorPasswordProtected(bool show);
|
||||||
|
void setShowOnlyIfSpectatorsCanChat(bool show);
|
||||||
|
void setShowOnlyIfSpectatorsCanSeeHands(bool show);
|
||||||
signals:
|
signals:
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
|
||||||
|
|
@ -50,25 +50,21 @@ QString ServersSettings::getSite(QString defaultSite)
|
||||||
|
|
||||||
QString ServersSettings::getPrevioushostName()
|
QString ServersSettings::getPrevioushostName()
|
||||||
{
|
{
|
||||||
return getValue("previoushostName", "server").toString();
|
QVariant value = getValue("previoushostName", "server");
|
||||||
|
return value == QVariant() ? "Rooster Ranges" : value.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
int ServersSettings::getPrevioushostindex(const QString &saveName)
|
int ServersSettings::getPrevioushostindex(const QString &saveName)
|
||||||
{
|
{
|
||||||
int size = getValue("totalServers", "server", "server_details").toInt() + 1;
|
int size = getValue("totalServers", "server", "server_details").toInt();
|
||||||
|
|
||||||
for (int i = 0; i < size; i++)
|
for (int i = 0; i <= size; ++i)
|
||||||
if (saveName == getValue(QString("saveName%1").arg(i), "server", "server_details").toString())
|
if (saveName == getValue(QString("saveName%1").arg(i), "server", "server_details").toString())
|
||||||
return i;
|
return i;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setHostName(QString hostname)
|
|
||||||
{
|
|
||||||
setValue(hostname, "hostname", "server");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ServersSettings::getHostname(QString defaultHost)
|
QString ServersSettings::getHostname(QString defaultHost)
|
||||||
{
|
{
|
||||||
int index = getPrevioushostindex(getPrevioushostName());
|
int index = getPrevioushostindex(getPrevioushostName());
|
||||||
|
|
@ -76,11 +72,6 @@ QString ServersSettings::getHostname(QString defaultHost)
|
||||||
return hostname == QVariant() ? std::move(defaultHost) : hostname.toString();
|
return hostname == QVariant() ? std::move(defaultHost) : hostname.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setPort(QString port)
|
|
||||||
{
|
|
||||||
setValue(port, "port", "server");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ServersSettings::getPort(QString defaultPort)
|
QString ServersSettings::getPort(QString defaultPort)
|
||||||
{
|
{
|
||||||
int index = getPrevioushostindex(getPrevioushostName());
|
int index = getPrevioushostindex(getPrevioushostName());
|
||||||
|
|
@ -89,11 +80,6 @@ QString ServersSettings::getPort(QString defaultPort)
|
||||||
return port == QVariant() ? std::move(defaultPort) : port.toString();
|
return port == QVariant() ? std::move(defaultPort) : port.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setPlayerName(QString playerName)
|
|
||||||
{
|
|
||||||
setValue(playerName, "playername", "server");
|
|
||||||
}
|
|
||||||
|
|
||||||
QString ServersSettings::getPlayerName(QString defaultName)
|
QString ServersSettings::getPlayerName(QString defaultName)
|
||||||
{
|
{
|
||||||
int index = getPrevioushostindex(getPrevioushostName());
|
int index = getPrevioushostindex(getPrevioushostName());
|
||||||
|
|
@ -119,16 +105,6 @@ bool ServersSettings::getSavePassword()
|
||||||
return save;
|
return save;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServersSettings::setPassword(QString password)
|
|
||||||
{
|
|
||||||
setValue(password, "password", "server");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServersSettings::setSavePassword(int save)
|
|
||||||
{
|
|
||||||
setValue(save, "save_password", "server");
|
|
||||||
}
|
|
||||||
|
|
||||||
void ServersSettings::setAutoConnect(int autoconnect)
|
void ServersSettings::setAutoConnect(int autoconnect)
|
||||||
{
|
{
|
||||||
setValue(autoconnect, "auto_connect", "server");
|
setValue(autoconnect, "auto_connect", "server");
|
||||||
|
|
@ -209,19 +185,47 @@ void ServersSettings::addNewServer(const QString &saveName,
|
||||||
|
|
||||||
void ServersSettings::removeServer(QString servAddr)
|
void ServersSettings::removeServer(QString servAddr)
|
||||||
{
|
{
|
||||||
int size = getValue("totalServers", "server", "server_details").toInt() + 1;
|
int size = getValue("totalServers", "server", "server_details").toInt();
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
bool found = false;
|
||||||
|
for (int i = 0; i <= size; ++i) {
|
||||||
|
if (!found) {
|
||||||
|
// find entry and overwrite it
|
||||||
if (servAddr == getValue(QString("server%1").arg(i), "server", "server_details").toString()) {
|
if (servAddr == getValue(QString("server%1").arg(i), "server", "server_details").toString()) {
|
||||||
deleteValue(QString("server%1").arg(i), "server", "server_details");
|
found = true;
|
||||||
deleteValue(QString("port%1").arg(i), "server", "server_details");
|
|
||||||
deleteValue(QString("username%1").arg(i), "server", "server_details");
|
|
||||||
deleteValue(QString("savePassword%1").arg(i), "server", "server_details");
|
|
||||||
deleteValue(QString("password%1").arg(i), "server", "server_details");
|
|
||||||
deleteValue(QString("saveName%1").arg(i), "server", "server_details");
|
|
||||||
deleteValue(QString("site%1").arg(i), "server", "server_details");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// move all other entries after it one back, overwriting the previous one
|
||||||
|
int previous = i - 1; // we delete only one entry
|
||||||
|
setValue(getValue(QString("server%1").arg(i), "server", "server_details"),
|
||||||
|
QString("server%1").arg(previous), "server", "server_details");
|
||||||
|
setValue(getValue(QString("port%1").arg(i), "server", "server_details"), QString("port%1").arg(previous),
|
||||||
|
"server", "server_details");
|
||||||
|
setValue(getValue(QString("username%1").arg(i), "server", "server_details"),
|
||||||
|
QString("username%1").arg(previous), "server", "server_details");
|
||||||
|
setValue(getValue(QString("savePassword%1").arg(i), "server", "server_details"),
|
||||||
|
QString("savePassword%1").arg(previous), "server", "server_details");
|
||||||
|
setValue(getValue(QString("password%1").arg(i), "server", "server_details"),
|
||||||
|
QString("password%1").arg(previous), "server", "server_details");
|
||||||
|
setValue(getValue(QString("saveName%1").arg(i), "server", "server_details"),
|
||||||
|
QString("saveName%1").arg(previous), "server", "server_details");
|
||||||
|
setValue(getValue(QString("site%1").arg(i), "server", "server_details"), QString("site%1").arg(previous),
|
||||||
|
"server", "server_details");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we have deleted an entry, adjust the total
|
||||||
|
if (found) {
|
||||||
|
setValue(size - 1, "totalServers", "server", "server_details");
|
||||||
|
|
||||||
|
// delete last value
|
||||||
|
deleteValue(QString("server%1").arg(size), "server", "server_details");
|
||||||
|
deleteValue(QString("port%1").arg(size), "server", "server_details");
|
||||||
|
deleteValue(QString("username%1").arg(size), "server", "server_details");
|
||||||
|
deleteValue(QString("savePassword%1").arg(size), "server", "server_details");
|
||||||
|
deleteValue(QString("password%1").arg(size), "server", "server_details");
|
||||||
|
deleteValue(QString("saveName%1").arg(size), "server", "server_details");
|
||||||
|
deleteValue(QString("site%1").arg(size), "server", "server_details");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -230,9 +234,9 @@ void ServersSettings::removeServer(QString servAddr)
|
||||||
*/
|
*/
|
||||||
bool ServersSettings::updateExistingServerWithoutLoss(QString saveName, QString serv, QString port, QString site)
|
bool ServersSettings::updateExistingServerWithoutLoss(QString saveName, QString serv, QString port, QString site)
|
||||||
{
|
{
|
||||||
int size = getValue("totalServers", "server", "server_details").toInt() + 1;
|
int size = getValue("totalServers", "server", "server_details").toInt();
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i <= size; ++i) {
|
||||||
if (serv == getValue(QString("server%1").arg(i), "server", "server_details").toString()) {
|
if (serv == getValue(QString("server%1").arg(i), "server", "server_details").toString()) {
|
||||||
if (!port.isEmpty()) {
|
if (!port.isEmpty()) {
|
||||||
setValue(port, QString("port%1").arg(i), "server", "server_details");
|
setValue(port, QString("port%1").arg(i), "server", "server_details");
|
||||||
|
|
@ -258,9 +262,9 @@ bool ServersSettings::updateExistingServer(QString saveName,
|
||||||
bool savePassword,
|
bool savePassword,
|
||||||
QString site)
|
QString site)
|
||||||
{
|
{
|
||||||
int size = getValue("totalServers", "server", "server_details").toInt() + 1;
|
int size = getValue("totalServers", "server", "server_details").toInt();
|
||||||
|
|
||||||
for (int i = 0; i < size; i++) {
|
for (int i = 0; i <= size; ++i) {
|
||||||
if (serv == getValue(QString("server%1").arg(i), "server", "server_details").toString()) {
|
if (serv == getValue(QString("server%1").arg(i), "server", "server_details").toString()) {
|
||||||
setValue(port, QString("port%1").arg(i), "server", "server_details");
|
setValue(port, QString("port%1").arg(i), "server", "server_details");
|
||||||
if (!username.isEmpty()) {
|
if (!username.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,8 @@
|
||||||
#include "settingsmanager.h"
|
#include "settingsmanager.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
#define SERVERSETTINGS_DEFAULT_HOST "server.cockatrice.us"
|
||||||
|
#define SERVERSETTINGS_DEFAULT_PORT "4748"
|
||||||
|
|
||||||
class ServersSettings : public SettingsManager
|
class ServersSettings : public SettingsManager
|
||||||
{
|
{
|
||||||
|
|
@ -15,11 +17,11 @@ public:
|
||||||
int getPrevioushostindex(const QString &);
|
int getPrevioushostindex(const QString &);
|
||||||
QStringList getPreviousHostList();
|
QStringList getPreviousHostList();
|
||||||
QString getPrevioushostName();
|
QString getPrevioushostName();
|
||||||
QString getHostname(QString defaultHost = "");
|
QString getHostname(QString defaultHost = SERVERSETTINGS_DEFAULT_HOST);
|
||||||
QString getPort(QString defaultPort = "");
|
QString getPort(QString defaultPort = SERVERSETTINGS_DEFAULT_PORT);
|
||||||
QString getPlayerName(QString defaultName = "");
|
QString getPlayerName(QString defaultName = "");
|
||||||
QString getFPHostname(QString defaultHost = "");
|
QString getFPHostname(QString defaultHost = SERVERSETTINGS_DEFAULT_HOST);
|
||||||
QString getFPPort(QString defaultPort = "");
|
QString getFPPort(QString defaultPort = SERVERSETTINGS_DEFAULT_PORT);
|
||||||
QString getFPPlayerName(QString defaultName = "");
|
QString getFPPlayerName(QString defaultName = "");
|
||||||
QString getPassword();
|
QString getPassword();
|
||||||
QString getSaveName(QString defaultname = "");
|
QString getSaveName(QString defaultname = "");
|
||||||
|
|
@ -30,15 +32,10 @@ public:
|
||||||
void setPreviousHostLogin(int previous);
|
void setPreviousHostLogin(int previous);
|
||||||
void setPrevioushostName(const QString &);
|
void setPrevioushostName(const QString &);
|
||||||
void setPreviousHostList(QStringList list);
|
void setPreviousHostList(QStringList list);
|
||||||
void setHostName(QString hostname);
|
|
||||||
void setPort(QString port);
|
|
||||||
void setPlayerName(QString playerName);
|
|
||||||
void setAutoConnect(int autoconnect);
|
void setAutoConnect(int autoconnect);
|
||||||
void setSite(QString site);
|
void setSite(QString site);
|
||||||
void setFPHostName(QString hostname);
|
void setFPHostName(QString hostname);
|
||||||
void setPassword(QString password);
|
|
||||||
void setFPPort(QString port);
|
void setFPPort(QString port);
|
||||||
void setSavePassword(int save);
|
|
||||||
void setFPPlayerName(QString playerName);
|
void setFPPlayerName(QString playerName);
|
||||||
void addNewServer(const QString &saveName,
|
void addNewServer(const QString &saveName,
|
||||||
const QString &serv,
|
const QString &serv,
|
||||||
|
|
|
||||||
|
|
@ -60,11 +60,6 @@ void SettingsCache::translateLegacySettings()
|
||||||
legacySetting.beginGroup("server");
|
legacySetting.beginGroup("server");
|
||||||
servers().setPreviousHostLogin(legacySetting.value("previoushostlogin").toInt());
|
servers().setPreviousHostLogin(legacySetting.value("previoushostlogin").toInt());
|
||||||
servers().setPreviousHostList(legacySetting.value("previoushosts").toStringList());
|
servers().setPreviousHostList(legacySetting.value("previoushosts").toStringList());
|
||||||
servers().setHostName(legacySetting.value("hostname").toString());
|
|
||||||
servers().setPort(legacySetting.value("port").toString());
|
|
||||||
servers().setPlayerName(legacySetting.value("playername").toString());
|
|
||||||
servers().setPassword(legacySetting.value("password").toString());
|
|
||||||
servers().setSavePassword(legacySetting.value("save_password").toInt());
|
|
||||||
servers().setAutoConnect(legacySetting.value("auto_connect").toInt());
|
servers().setAutoConnect(legacySetting.value("auto_connect").toInt());
|
||||||
servers().setFPHostName(legacySetting.value("fphostname").toString());
|
servers().setFPHostName(legacySetting.value("fphostname").toString());
|
||||||
servers().setFPPort(legacySetting.value("fpport").toString());
|
servers().setFPPort(legacySetting.value("fpport").toString());
|
||||||
|
|
@ -95,7 +90,8 @@ void SettingsCache::translateLegacySettings()
|
||||||
|
|
||||||
// Game filters
|
// Game filters
|
||||||
legacySetting.beginGroup("filter_games");
|
legacySetting.beginGroup("filter_games");
|
||||||
gameFilters().setUnavailableGamesVisible(legacySetting.value("unavailable_games_visible").toBool());
|
gameFilters().setShowFullGames(legacySetting.value("unavailable_games_visible").toBool());
|
||||||
|
gameFilters().setShowGamesThatStarted(legacySetting.value("unavailable_games_visible").toBool());
|
||||||
gameFilters().setShowPasswordProtectedGames(legacySetting.value("show_password_protected_games").toBool());
|
gameFilters().setShowPasswordProtectedGames(legacySetting.value("show_password_protected_games").toBool());
|
||||||
gameFilters().setGameNameFilter(legacySetting.value("game_name_filter").toString());
|
gameFilters().setGameNameFilter(legacySetting.value("game_name_filter").toString());
|
||||||
gameFilters().setShowBuddiesOnlyGames(legacySetting.value("show_buddies_only_games").toBool());
|
gameFilters().setShowBuddiesOnlyGames(legacySetting.value("show_buddies_only_games").toBool());
|
||||||
|
|
@ -196,6 +192,7 @@ SettingsCache::SettingsCache()
|
||||||
|
|
||||||
deckPath = getSafeConfigPath("paths/decks", dataPath + "/decks/");
|
deckPath = getSafeConfigPath("paths/decks", dataPath + "/decks/");
|
||||||
replaysPath = getSafeConfigPath("paths/replays", dataPath + "/replays/");
|
replaysPath = getSafeConfigPath("paths/replays", dataPath + "/replays/");
|
||||||
|
themesPath = getSafeConfigPath("paths/themes", dataPath + "/themes/");
|
||||||
picsPath = getSafeConfigPath("paths/pics", dataPath + "/pics/");
|
picsPath = getSafeConfigPath("paths/pics", dataPath + "/pics/");
|
||||||
// this has never been exposed as an user-configurable setting
|
// this has never been exposed as an user-configurable setting
|
||||||
if (picsPath.endsWith("/")) {
|
if (picsPath.endsWith("/")) {
|
||||||
|
|
@ -283,6 +280,7 @@ SettingsCache::SettingsCache()
|
||||||
spectatorsNeedPassword = settings->value("game/spectatorsneedpassword", false).toBool();
|
spectatorsNeedPassword = settings->value("game/spectatorsneedpassword", false).toBool();
|
||||||
spectatorsCanTalk = settings->value("game/spectatorscantalk", false).toBool();
|
spectatorsCanTalk = settings->value("game/spectatorscantalk", false).toBool();
|
||||||
spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool();
|
spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool();
|
||||||
|
createGameAsSpectator = settings->value("game/creategameasspectator", false).toBool();
|
||||||
rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
|
rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
|
||||||
clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString();
|
clientID = settings->value("personal/clientid", CLIENT_INFO_NOT_SET).toString();
|
||||||
clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString();
|
clientVersion = settings->value("personal/clientversion", CLIENT_INFO_NOT_SET).toString();
|
||||||
|
|
@ -386,6 +384,13 @@ void SettingsCache::setReplaysPath(const QString &_replaysPath)
|
||||||
settings->setValue("paths/replays", replaysPath);
|
settings->setValue("paths/replays", replaysPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setThemesPath(const QString &_themesPath)
|
||||||
|
{
|
||||||
|
themesPath = _themesPath;
|
||||||
|
settings->setValue("paths/themes", themesPath);
|
||||||
|
emit themeChanged();
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setCustomCardDatabasePath(const QString &_customCardDatabasePath)
|
void SettingsCache::setCustomCardDatabasePath(const QString &_customCardDatabasePath)
|
||||||
{
|
{
|
||||||
customCardDatabasePath = _customCardDatabasePath;
|
customCardDatabasePath = _customCardDatabasePath;
|
||||||
|
|
@ -939,6 +944,12 @@ void SettingsCache::setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEv
|
||||||
settings->setValue("game/spectatorscanseeeverything", spectatorsCanSeeEverything);
|
settings->setValue("game/spectatorscanseeeverything", spectatorsCanSeeEverything);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SettingsCache::setCreateGameAsSpectator(const bool _createGameAsSpectator)
|
||||||
|
{
|
||||||
|
createGameAsSpectator = _createGameAsSpectator;
|
||||||
|
settings->setValue("game/creategameasspectator", createGameAsSpectator);
|
||||||
|
}
|
||||||
|
|
||||||
void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings)
|
void SettingsCache::setRememberGameSettings(const bool _rememberGameSettings)
|
||||||
{
|
{
|
||||||
rememberGameSettings = _rememberGameSettings;
|
rememberGameSettings = _rememberGameSettings;
|
||||||
|
|
|
||||||
|
|
@ -66,7 +66,7 @@ private:
|
||||||
QByteArray mainWindowGeometry;
|
QByteArray mainWindowGeometry;
|
||||||
QByteArray tokenDialogGeometry;
|
QByteArray tokenDialogGeometry;
|
||||||
QString lang;
|
QString lang;
|
||||||
QString deckPath, replaysPath, picsPath, customPicsPath, cardDatabasePath, customCardDatabasePath,
|
QString deckPath, replaysPath, picsPath, customPicsPath, cardDatabasePath, customCardDatabasePath, themesPath,
|
||||||
spoilerDatabasePath, tokenDatabasePath, themeName;
|
spoilerDatabasePath, tokenDatabasePath, themeName;
|
||||||
bool notifyAboutUpdates;
|
bool notifyAboutUpdates;
|
||||||
bool notifyAboutNewVersion;
|
bool notifyAboutNewVersion;
|
||||||
|
|
@ -124,6 +124,7 @@ private:
|
||||||
bool spectatorsNeedPassword;
|
bool spectatorsNeedPassword;
|
||||||
bool spectatorsCanTalk;
|
bool spectatorsCanTalk;
|
||||||
bool spectatorsCanSeeEverything;
|
bool spectatorsCanSeeEverything;
|
||||||
|
bool createGameAsSpectator;
|
||||||
int keepalive;
|
int keepalive;
|
||||||
void translateLegacySettings();
|
void translateLegacySettings();
|
||||||
QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
|
QString getSafeConfigPath(QString configEntry, QString defaultPath) const;
|
||||||
|
|
@ -156,6 +157,10 @@ public:
|
||||||
{
|
{
|
||||||
return replaysPath;
|
return replaysPath;
|
||||||
}
|
}
|
||||||
|
QString getThemesPath() const
|
||||||
|
{
|
||||||
|
return themesPath;
|
||||||
|
}
|
||||||
QString getPicsPath() const
|
QString getPicsPath() const
|
||||||
{
|
{
|
||||||
return picsPath;
|
return picsPath;
|
||||||
|
|
@ -394,6 +399,10 @@ public:
|
||||||
{
|
{
|
||||||
return spectatorsCanSeeEverything;
|
return spectatorsCanSeeEverything;
|
||||||
}
|
}
|
||||||
|
bool getCreateGameAsSpectator() const
|
||||||
|
{
|
||||||
|
return createGameAsSpectator;
|
||||||
|
}
|
||||||
bool getRememberGameSettings() const
|
bool getRememberGameSettings() const
|
||||||
{
|
{
|
||||||
return rememberGameSettings;
|
return rememberGameSettings;
|
||||||
|
|
@ -474,6 +483,7 @@ public slots:
|
||||||
void setSeenTips(const QList<int> &_seenTips);
|
void setSeenTips(const QList<int> &_seenTips);
|
||||||
void setDeckPath(const QString &_deckPath);
|
void setDeckPath(const QString &_deckPath);
|
||||||
void setReplaysPath(const QString &_replaysPath);
|
void setReplaysPath(const QString &_replaysPath);
|
||||||
|
void setThemesPath(const QString &_themesPath);
|
||||||
void setCustomCardDatabasePath(const QString &_customCardDatabasePath);
|
void setCustomCardDatabasePath(const QString &_customCardDatabasePath);
|
||||||
void setPicsPath(const QString &_picsPath);
|
void setPicsPath(const QString &_picsPath);
|
||||||
void setCardDatabasePath(const QString &_cardDatabasePath);
|
void setCardDatabasePath(const QString &_cardDatabasePath);
|
||||||
|
|
@ -525,6 +535,7 @@ public slots:
|
||||||
void setSpectatorsNeedPassword(const bool _spectatorsNeedPassword);
|
void setSpectatorsNeedPassword(const bool _spectatorsNeedPassword);
|
||||||
void setSpectatorsCanTalk(const bool _spectatorsCanTalk);
|
void setSpectatorsCanTalk(const bool _spectatorsCanTalk);
|
||||||
void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything);
|
void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything);
|
||||||
|
void setCreateGameAsSpectator(const bool _createGameAsSpectator);
|
||||||
void setRememberGameSettings(const bool _rememberGameSettings);
|
void setRememberGameSettings(const bool _rememberGameSettings);
|
||||||
void setNotifyAboutUpdate(int _notifyaboutupdate);
|
void setNotifyAboutUpdate(int _notifyaboutupdate);
|
||||||
void setNotifyAboutNewVersion(int _notifyaboutnewversion);
|
void setNotifyAboutNewVersion(int _notifyaboutnewversion);
|
||||||
|
|
|
||||||
|
|
@ -219,7 +219,7 @@ private:
|
||||||
parseSequenceString("Ctrl+S"),
|
parseSequenceString("Ctrl+S"),
|
||||||
ShortcutGroup::Deck_Editor)},
|
ShortcutGroup::Deck_Editor)},
|
||||||
{"TabDeckEditor/aSaveDeckAs", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Save Deck as..."),
|
{"TabDeckEditor/aSaveDeckAs", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Save Deck as..."),
|
||||||
parseSequenceString(""),
|
parseSequenceString("Ctrl+Shift+S"),
|
||||||
ShortcutGroup::Deck_Editor)},
|
ShortcutGroup::Deck_Editor)},
|
||||||
{"TabDeckEditor/aSaveDeckToClipboard",
|
{"TabDeckEditor/aSaveDeckToClipboard",
|
||||||
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Save Deck to Clipboard, Annotated"),
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Save Deck to Clipboard, Annotated"),
|
||||||
|
|
@ -502,9 +502,31 @@ private:
|
||||||
{"Player/aMoveTopCardToBottom", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Bottom of Library"),
|
{"Player/aMoveTopCardToBottom", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Bottom of Library"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_top)},
|
ShortcutGroup::Move_top)},
|
||||||
|
{"Player/aMoveBottomToPlay",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Stack"), parseSequenceString(""), ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aMoveBottomToPlayFaceDown", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Battlefield, Face Down"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
{"Player/aMoveBottomCardToGrave", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard"),
|
{"Player/aMoveBottomCardToGrave", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Move_bottom)},
|
ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aMoveBottomCardsToGrave", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Graveyard (Multiple)"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aMoveBottomCardToExile",
|
||||||
|
ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile"), parseSequenceString(""), ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aMoveBottomCardsToExile", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Exile (Multiple)"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aMoveBottomCardToTop", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Top of Library"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aDrawBottomCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Draw Bottom Card"),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
|
{"Player/aDrawBottomCards", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Draw Multiple Cards from Bottom..."),
|
||||||
|
parseSequenceString(""),
|
||||||
|
ShortcutGroup::Move_bottom)},
|
||||||
{"Player/aDrawArrow", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Draw Arrow..."),
|
{"Player/aDrawArrow", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Draw Arrow..."),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Gameplay)},
|
ShortcutGroup::Gameplay)},
|
||||||
|
|
@ -537,6 +559,9 @@ private:
|
||||||
{"Player/aAlwaysRevealTopCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Always Reveal Top Card"),
|
{"Player/aAlwaysRevealTopCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Always Reveal Top Card"),
|
||||||
parseSequenceString("Ctrl+N"),
|
parseSequenceString("Ctrl+N"),
|
||||||
ShortcutGroup::Drawing)},
|
ShortcutGroup::Drawing)},
|
||||||
|
{"Player/aAlwaysLookAtTopCard", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Always Look At Top Card"),
|
||||||
|
parseSequenceString("Ctrl+A"),
|
||||||
|
ShortcutGroup::Drawing)},
|
||||||
{"Player/aRotateViewCW", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Rotate View Clockwise"),
|
{"Player/aRotateViewCW", ShortcutKey(QT_TRANSLATE_NOOP("shortcutsTab", "Rotate View Clockwise"),
|
||||||
parseSequenceString(""),
|
parseSequenceString(""),
|
||||||
ShortcutGroup::Gameplay)},
|
ShortcutGroup::Gameplay)},
|
||||||
|
|
|
||||||
|
|
@ -167,8 +167,8 @@ bool SpoilerBackgroundUpdater::saveDownloadedFile(QByteArray data)
|
||||||
QList<QByteArray> lines = data.split('\n');
|
QList<QByteArray> lines = data.split('\n');
|
||||||
|
|
||||||
foreach (QByteArray line, lines) {
|
foreach (QByteArray line, lines) {
|
||||||
if (line.contains("created:")) {
|
if (line.contains("Created At:")) {
|
||||||
QString timeStamp = QString(line).replace("created:", "").trimmed();
|
QString timeStamp = QString(line).replace("Created At:", "").trimmed();
|
||||||
timeStamp.chop(6); // Remove " (UTC)"
|
timeStamp.chop(6); // Remove " (UTC)"
|
||||||
|
|
||||||
auto utcTime = QLocale().toDateTime(timeStamp, "ddd, MMM dd yyyy, hh:mm:ss");
|
auto utcTime = QLocale().toDateTime(timeStamp, "ddd, MMM dd yyyy, hh:mm:ss");
|
||||||
|
|
|
||||||
|
|
@ -47,7 +47,13 @@ QRectF StackZone::boundingRect() const
|
||||||
|
|
||||||
void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
void StackZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||||
{
|
{
|
||||||
painter->fillRect(boundingRect(), themeManager->getStackBgBrush());
|
QBrush brush = themeManager->getStackBgBrush();
|
||||||
|
|
||||||
|
if (player->getZoneId() > 0) {
|
||||||
|
// If the extra image is not found, load the default one
|
||||||
|
brush = themeManager->getExtraStackBgBrush(QString::number(player->getZoneId()), brush);
|
||||||
|
}
|
||||||
|
painter->fillRect(boundingRect(), brush);
|
||||||
}
|
}
|
||||||
|
|
||||||
void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
void StackZone::handleDropEvent(const QList<CardDragItem *> &dragItems,
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
#include "tab_userlists.h"
|
#include "tab_account.h"
|
||||||
|
|
||||||
#include "abstractclient.h"
|
#include "abstractclient.h"
|
||||||
#include "customlineedit.h"
|
#include "customlineedit.h"
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
#ifndef TAB_USERLISTS_H
|
#ifndef TAB_ACCOUNT_H
|
||||||
#define TAB_USERLISTS_H
|
#define TAB_ACCOUNT_H
|
||||||
|
|
||||||
#include "pb/serverinfo_user.pb.h"
|
#include "pb/serverinfo_user.pb.h"
|
||||||
#include "tab.h"
|
#include "tab.h"
|
||||||
|
|
@ -26,8 +26,6 @@
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <QFileDialog>
|
#include <QFileDialog>
|
||||||
#include <QGroupBox>
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QHeaderView>
|
#include <QHeaderView>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
|
@ -89,6 +87,8 @@ void TabDeckEditor::createDeckDock()
|
||||||
commentsLabel = new QLabel();
|
commentsLabel = new QLabel();
|
||||||
commentsLabel->setObjectName("commentsLabel");
|
commentsLabel->setObjectName("commentsLabel");
|
||||||
commentsEdit = new QTextEdit;
|
commentsEdit = new QTextEdit;
|
||||||
|
commentsEdit->setAcceptRichText(false);
|
||||||
|
commentsEdit->setMinimumHeight(nameEdit->minimumSizeHint().height());
|
||||||
commentsEdit->setObjectName("commentsEdit");
|
commentsEdit->setObjectName("commentsEdit");
|
||||||
commentsLabel->setBuddy(commentsEdit);
|
commentsLabel->setBuddy(commentsEdit);
|
||||||
connect(commentsEdit, SIGNAL(textChanged()), this, SLOT(updateComments()));
|
connect(commentsEdit, SIGNAL(textChanged()), this, SLOT(updateComments()));
|
||||||
|
|
@ -139,15 +139,15 @@ void TabDeckEditor::createDeckDock()
|
||||||
lowerLayout->addWidget(deckView, 1, 0, 1, 5);
|
lowerLayout->addWidget(deckView, 1, 0, 1, 5);
|
||||||
|
|
||||||
// Create widgets for both layouts to make splitter work correctly
|
// Create widgets for both layouts to make splitter work correctly
|
||||||
QWidget *topWidget = new QWidget;
|
auto *topWidget = new QWidget;
|
||||||
topWidget->setLayout(upperLayout);
|
topWidget->setLayout(upperLayout);
|
||||||
QWidget *bottomWidget = new QWidget;
|
auto *bottomWidget = new QWidget;
|
||||||
bottomWidget->setLayout(lowerLayout);
|
bottomWidget->setLayout(lowerLayout);
|
||||||
|
|
||||||
auto *split = new QSplitter;
|
auto *split = new QSplitter;
|
||||||
split->setObjectName("deckSplitter");
|
split->setObjectName("deckSplitter");
|
||||||
split->setOrientation(Qt::Vertical);
|
split->setOrientation(Qt::Vertical);
|
||||||
split->setChildrenCollapsible(false);
|
split->setChildrenCollapsible(true);
|
||||||
split->addWidget(topWidget);
|
split->addWidget(topWidget);
|
||||||
split->addWidget(bottomWidget);
|
split->addWidget(bottomWidget);
|
||||||
split->setStretchFactor(0, 1);
|
split->setStretchFactor(0, 1);
|
||||||
|
|
@ -164,7 +164,7 @@ void TabDeckEditor::createDeckDock()
|
||||||
deckDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
deckDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
||||||
deckDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
deckDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
||||||
QDockWidget::DockWidgetMovable);
|
QDockWidget::DockWidgetMovable);
|
||||||
QWidget *deckDockContents = new QWidget();
|
auto *deckDockContents = new QWidget();
|
||||||
deckDockContents->setObjectName("deckDockContents");
|
deckDockContents->setObjectName("deckDockContents");
|
||||||
deckDockContents->setLayout(rightFrame);
|
deckDockContents->setLayout(rightFrame);
|
||||||
deckDock->setWidget(deckDockContents);
|
deckDock->setWidget(deckDockContents);
|
||||||
|
|
@ -188,7 +188,7 @@ void TabDeckEditor::createCardInfoDock()
|
||||||
cardInfoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
cardInfoDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
|
||||||
cardInfoDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
cardInfoDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
||||||
QDockWidget::DockWidgetMovable);
|
QDockWidget::DockWidgetMovable);
|
||||||
QWidget *cardInfoDockContents = new QWidget();
|
auto *cardInfoDockContents = new QWidget();
|
||||||
cardInfoDockContents->setObjectName("cardInfoDockContents");
|
cardInfoDockContents->setObjectName("cardInfoDockContents");
|
||||||
cardInfoDockContents->setLayout(cardInfoFrame);
|
cardInfoDockContents->setLayout(cardInfoFrame);
|
||||||
cardInfoDock->setWidget(cardInfoDockContents);
|
cardInfoDock->setWidget(cardInfoDockContents);
|
||||||
|
|
@ -250,7 +250,7 @@ void TabDeckEditor::createFiltersDock()
|
||||||
|
|
||||||
filterDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
filterDock->setFeatures(QDockWidget::DockWidgetClosable | QDockWidget::DockWidgetFloatable |
|
||||||
QDockWidget::DockWidgetMovable);
|
QDockWidget::DockWidgetMovable);
|
||||||
QWidget *filterDockContents = new QWidget(this);
|
auto *filterDockContents = new QWidget(this);
|
||||||
filterDockContents->setObjectName("filterDockContents");
|
filterDockContents->setObjectName("filterDockContents");
|
||||||
filterDockContents->setLayout(filterFrame);
|
filterDockContents->setLayout(filterFrame);
|
||||||
filterDock->setWidget(filterDockContents);
|
filterDock->setWidget(filterDockContents);
|
||||||
|
|
@ -476,7 +476,7 @@ void TabDeckEditor::databaseCustomMenu(QPoint point)
|
||||||
relatedMenu->setDisabled(true);
|
relatedMenu->setDisabled(true);
|
||||||
} else {
|
} else {
|
||||||
for (const CardRelation *rel : relatedCards) {
|
for (const CardRelation *rel : relatedCards) {
|
||||||
QString relatedCardName = rel->getName();
|
const QString &relatedCardName = rel->getName();
|
||||||
QAction *relatedCard = relatedMenu->addAction(relatedCardName);
|
QAction *relatedCard = relatedMenu->addAction(relatedCardName);
|
||||||
connect(relatedCard, &QAction::triggered, cardInfo,
|
connect(relatedCard, &QAction::triggered, cardInfo,
|
||||||
[this, relatedCardName] { cardInfo->setCard(relatedCardName); });
|
[this, relatedCardName] { cardInfo->setCard(relatedCardName); });
|
||||||
|
|
@ -875,7 +875,7 @@ void TabDeckEditor::actSaveDeckToClipboardRaw()
|
||||||
|
|
||||||
void TabDeckEditor::actPrintDeck()
|
void TabDeckEditor::actPrintDeck()
|
||||||
{
|
{
|
||||||
QPrintPreviewDialog *dlg = new QPrintPreviewDialog(this);
|
auto *dlg = new QPrintPreviewDialog(this);
|
||||||
connect(dlg, SIGNAL(paintRequested(QPrinter *)), deckModel, SLOT(printDeckList(QPrinter *)));
|
connect(dlg, SIGNAL(paintRequested(QPrinter *)), deckModel, SLOT(printDeckList(QPrinter *)));
|
||||||
dlg->exec();
|
dlg->exec();
|
||||||
}
|
}
|
||||||
|
|
@ -933,8 +933,9 @@ void TabDeckEditor::actClearFilterAll()
|
||||||
void TabDeckEditor::actClearFilterOne()
|
void TabDeckEditor::actClearFilterOne()
|
||||||
{
|
{
|
||||||
QModelIndexList selIndexes = filterView->selectionModel()->selectedIndexes();
|
QModelIndexList selIndexes = filterView->selectionModel()->selectedIndexes();
|
||||||
foreach (QModelIndex idx, selIndexes)
|
for (QModelIndex idx : selIndexes) {
|
||||||
filterModel->removeRow(idx.row(), idx.parent());
|
filterModel->removeRow(idx.row(), idx.parent());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabDeckEditor::recursiveExpand(const QModelIndex &index)
|
void TabDeckEditor::recursiveExpand(const QModelIndex &index)
|
||||||
|
|
@ -1249,7 +1250,7 @@ void TabDeckEditor::showSearchSyntaxHelp()
|
||||||
.replace(QRegularExpression("^(##)(.*)", opts), "<h2>\\2</h2>")
|
.replace(QRegularExpression("^(##)(.*)", opts), "<h2>\\2</h2>")
|
||||||
.replace(QRegularExpression("^(#)(.*)", opts), "<h1>\\2</h1>")
|
.replace(QRegularExpression("^(#)(.*)", opts), "<h1>\\2</h1>")
|
||||||
.replace(QRegularExpression("^------*", opts), "<hr />")
|
.replace(QRegularExpression("^------*", opts), "<hr />")
|
||||||
.replace(QRegularExpression("\\[([^\[]+)\\]\\(([^\\)]+)\\)", opts), "<a href=\'\\2\'>\\1</a>");
|
.replace(QRegularExpression(R"(\[([^[]+)\]\(([^\)]+)\))", opts), R"(<a href='\2'>\1</a>)");
|
||||||
|
|
||||||
auto browser = new QTextBrowser;
|
auto browser = new QTextBrowser;
|
||||||
browser->setParent(this, Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint |
|
browser->setParent(this, Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowMinMaxButtonsHint |
|
||||||
|
|
@ -1262,6 +1263,6 @@ void TabDeckEditor::showSearchSyntaxHelp()
|
||||||
browser->document()->setDefaultStyleSheet(sheet);
|
browser->document()->setDefaultStyleSheet(sheet);
|
||||||
|
|
||||||
browser->setHtml(text);
|
browser->setHtml(text);
|
||||||
connect(browser, &QTextBrowser::anchorClicked, [=](QUrl link) { searchEdit->setText(link.fragment()); });
|
connect(browser, &QTextBrowser::anchorClicked, [=](const QUrl &link) { searchEdit->setText(link.fragment()); });
|
||||||
browser->show();
|
browser->show();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -196,6 +196,9 @@ void TabDeckStorage::uploadFinished(const Response &r, const CommandContainer &c
|
||||||
void TabDeckStorage::actDeleteLocalDeck()
|
void TabDeckStorage::actDeleteLocalDeck()
|
||||||
{
|
{
|
||||||
QModelIndex curLeft = localDirView->selectionModel()->currentIndex();
|
QModelIndex curLeft = localDirView->selectionModel()->currentIndex();
|
||||||
|
if (localDirModel->isDir(curLeft))
|
||||||
|
return;
|
||||||
|
|
||||||
if (QMessageBox::warning(this, tr("Delete local file"),
|
if (QMessageBox::warning(this, tr("Delete local file"),
|
||||||
tr("Are you sure you want to delete \"%1\"?").arg(localDirModel->fileName(curLeft)),
|
tr("Are you sure you want to delete \"%1\"?").arg(localDirModel->fileName(curLeft)),
|
||||||
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
|
QMessageBox::Yes | QMessageBox::No) != QMessageBox::Yes)
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
#include "deckview.h"
|
#include "deckview.h"
|
||||||
#include "dlg_creategame.h"
|
#include "dlg_creategame.h"
|
||||||
#include "dlg_load_remote_deck.h"
|
#include "dlg_load_remote_deck.h"
|
||||||
|
#include "dlg_manage_sets.h"
|
||||||
#include "gamescene.h"
|
#include "gamescene.h"
|
||||||
#include "gameview.h"
|
#include "gameview.h"
|
||||||
#include "get_pb_extension.h"
|
#include "get_pb_extension.h"
|
||||||
|
|
@ -52,7 +53,7 @@
|
||||||
#include "replay_timeline_widget.h"
|
#include "replay_timeline_widget.h"
|
||||||
#include "settingscache.h"
|
#include "settingscache.h"
|
||||||
#include "tab_supervisor.h"
|
#include "tab_supervisor.h"
|
||||||
#include "window_sets.h"
|
#include "window_main.h"
|
||||||
#include "zoneviewwidget.h"
|
#include "zoneviewwidget.h"
|
||||||
#include "zoneviewzone.h"
|
#include "zoneviewzone.h"
|
||||||
|
|
||||||
|
|
@ -162,6 +163,9 @@ void DeckViewContainer::updateSideboardLockButtonText()
|
||||||
} else {
|
} else {
|
||||||
sideboardLockButton->setText(tr("Sideboard locked"));
|
sideboardLockButton->setText(tr("Sideboard locked"));
|
||||||
}
|
}
|
||||||
|
// setting text on a button removes its shortcut
|
||||||
|
ShortcutsSettings &shortcuts = SettingsCache::instance().shortcuts();
|
||||||
|
sideboardLockButton->setShortcut(shortcuts.getSingleShortcut("DeckViewContainer/sideboardLockButton"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::refreshShortcuts()
|
void DeckViewContainer::refreshShortcuts()
|
||||||
|
|
@ -855,11 +859,9 @@ void TabGame::processGameEventContainer(const GameEventContainer &cont, Abstract
|
||||||
case GameEvent::LEAVE:
|
case GameEvent::LEAVE:
|
||||||
eventSpectatorLeave(event.GetExtension(Event_Leave::ext), playerId, context);
|
eventSpectatorLeave(event.GetExtension(Event_Leave::ext), playerId, context);
|
||||||
break;
|
break;
|
||||||
default: {
|
default:
|
||||||
qDebug() << "unhandled spectator game event" << eventType;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if ((clients.size() > 1) && (playerId != -1))
|
if ((clients.size() > 1) && (playerId != -1))
|
||||||
if (clients.at(playerId) != client)
|
if (clients.at(playerId) != client)
|
||||||
|
|
@ -1194,6 +1196,11 @@ void TabGame::eventJoin(const Event_Join &event, int /*eventPlayerId*/, const Ga
|
||||||
} else {
|
} else {
|
||||||
Player *newPlayer = addPlayer(playerId, playerInfo.user_info());
|
Player *newPlayer = addPlayer(playerId, playerInfo.user_info());
|
||||||
messageLog->logJoin(newPlayer);
|
messageLog->logJoin(newPlayer);
|
||||||
|
if (trayIcon) {
|
||||||
|
QString gameId(QString::number(gameInfo.game_id()));
|
||||||
|
trayIcon->showMessage(tr("A player has joined game #%1").arg(gameId),
|
||||||
|
tr("%1 has joined the game").arg(newPlayer->getName()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
playerListWidget->addPlayer(playerInfo);
|
playerListWidget->addPlayer(playerInfo);
|
||||||
emitUserEvent();
|
emitUserEvent();
|
||||||
|
|
@ -1408,12 +1415,15 @@ Player *TabGame::getActiveLocalPlayer() const
|
||||||
|
|
||||||
void TabGame::updateCardMenu(AbstractCardItem *card)
|
void TabGame::updateCardMenu(AbstractCardItem *card)
|
||||||
{
|
{
|
||||||
Player *p;
|
Player *player;
|
||||||
if ((clients.size() > 1) || !players.contains(localPlayerId))
|
if ((clients.size() > 1) || !players.contains(localPlayerId)) {
|
||||||
p = card->getOwner();
|
player = card->getOwner();
|
||||||
else
|
} else {
|
||||||
p = players.value(localPlayerId);
|
player = players.value(localPlayerId);
|
||||||
p->updateCardMenu(static_cast<CardItem *>(card));
|
}
|
||||||
|
if (player != nullptr) {
|
||||||
|
player->updateCardMenu(static_cast<CardItem *>(card));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TabGame::createMenuItems()
|
void TabGame::createMenuItems()
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
#include "abstractclient.h"
|
#include "abstractclient.h"
|
||||||
#include "customlineedit.h"
|
#include "customlineedit.h"
|
||||||
|
#include "dlg_manage_sets.h"
|
||||||
#include "pb/moderator_commands.pb.h"
|
#include "pb/moderator_commands.pb.h"
|
||||||
#include "pb/response_viewlog_history.pb.h"
|
#include "pb/response_viewlog_history.pb.h"
|
||||||
#include "pending_command.h"
|
#include "pending_command.h"
|
||||||
#include "window_sets.h"
|
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QDialogButtonBox>
|
#include <QDialogButtonBox>
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@
|
||||||
#include "pb/serverinfo_room.pb.h"
|
#include "pb/serverinfo_room.pb.h"
|
||||||
#include "pending_command.h"
|
#include "pending_command.h"
|
||||||
#include "settingscache.h"
|
#include "settingscache.h"
|
||||||
|
#include "tab_account.h"
|
||||||
#include "tab_supervisor.h"
|
#include "tab_supervisor.h"
|
||||||
#include "tab_userlists.h"
|
|
||||||
#include "userlist.h"
|
#include "userlist.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
|
||||||
|
|
@ -112,7 +112,7 @@ void RoomSelector::processListRoomsEvent(const Event_ListRooms &event)
|
||||||
QString RoomSelector::getRoomPermissionDisplay(const ServerInfo_Room &room)
|
QString RoomSelector::getRoomPermissionDisplay(const ServerInfo_Room &room)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* A room can have a permission level and a privilege level. How ever we want to display only the necessary
|
* A server room can have a permission level and a privilege level. How ever we want to display only the necessary
|
||||||
* information on the server tab needed to inform users of required permissions to enter a room. If the room has a
|
* information on the server tab needed to inform users of required permissions to enter a room. If the room has a
|
||||||
* privilege level the server tab will display the privilege level in the "permissions" column in the row however if
|
* privilege level the server tab will display the privilege level in the "permissions" column in the row however if
|
||||||
* the room contains a permissions level for the room the permissions level defined for the room will be displayed.
|
* the room contains a permissions level for the room the permissions level defined for the room will be displayed.
|
||||||
|
|
@ -206,19 +206,23 @@ void TabServer::joinRoomFinished(const Response &r,
|
||||||
case Response::RespOk:
|
case Response::RespOk:
|
||||||
break;
|
break;
|
||||||
case Response::RespNameNotFound:
|
case Response::RespNameNotFound:
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Failed to join the room: it doesn't exist on the server."));
|
QMessageBox::critical(this, tr("Error"),
|
||||||
|
tr("Failed to join the server room: it doesn't exist on the server."));
|
||||||
return;
|
return;
|
||||||
case Response::RespContextError:
|
case Response::RespContextError:
|
||||||
QMessageBox::critical(this, tr("Error"),
|
QMessageBox::critical(
|
||||||
tr("The server thinks you are in the room but your client is unable to display it. "
|
this, tr("Error"),
|
||||||
|
tr("The server thinks you are in the server room but your client is unable to display it. "
|
||||||
"Try restarting your client."));
|
"Try restarting your client."));
|
||||||
return;
|
return;
|
||||||
case Response::RespUserLevelTooLow:
|
case Response::RespUserLevelTooLow:
|
||||||
QMessageBox::critical(this, tr("Error"), tr("You do not have the required permission to join this room."));
|
QMessageBox::critical(this, tr("Error"),
|
||||||
|
tr("You do not have the required permission to join this server room."));
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
QMessageBox::critical(this, tr("Error"),
|
QMessageBox::critical(
|
||||||
tr("Failed to join the room due to an unknown error: %1.").arg(r.response_code()));
|
this, tr("Error"),
|
||||||
|
tr("Failed to join the server room due to an unknown error: %1.").arg(r.response_code()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@
|
||||||
#include "pb/serverinfo_user.pb.h"
|
#include "pb/serverinfo_user.pb.h"
|
||||||
#include "pixmapgenerator.h"
|
#include "pixmapgenerator.h"
|
||||||
#include "settingscache.h"
|
#include "settingscache.h"
|
||||||
|
#include "tab_account.h"
|
||||||
#include "tab_admin.h"
|
#include "tab_admin.h"
|
||||||
#include "tab_deck_editor.h"
|
#include "tab_deck_editor.h"
|
||||||
#include "tab_deck_storage.h"
|
#include "tab_deck_storage.h"
|
||||||
|
|
@ -22,7 +23,6 @@
|
||||||
#include "tab_replays.h"
|
#include "tab_replays.h"
|
||||||
#include "tab_room.h"
|
#include "tab_room.h"
|
||||||
#include "tab_server.h"
|
#include "tab_server.h"
|
||||||
#include "tab_userlists.h"
|
|
||||||
#include "userlist.h"
|
#include "userlist.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
|
||||||
|
|
@ -9,12 +9,17 @@
|
||||||
#include <QPixmapCache>
|
#include <QPixmapCache>
|
||||||
#include <QStandardPaths>
|
#include <QStandardPaths>
|
||||||
|
|
||||||
#define DEFAULT_THEME_NAME "Default"
|
#define NONE_THEME_NAME "None "
|
||||||
#define STYLE_CSS_NAME "style.css"
|
#define STYLE_CSS_NAME "style.css"
|
||||||
#define HANDZONE_BG_NAME "handzone"
|
#define HANDZONE_BG_NAME "handzone"
|
||||||
#define PLAYERZONE_BG_NAME "playerzone"
|
#define PLAYERZONE_BG_NAME "playerzone"
|
||||||
#define STACKZONE_BG_NAME "stackzone"
|
#define STACKZONE_BG_NAME "stackzone"
|
||||||
#define TABLEZONE_BG_NAME "tablezone"
|
#define TABLEZONE_BG_NAME "tablezone"
|
||||||
|
static const QColor HANDZONE_BG_DEFAULT = QColor(80, 100, 50);
|
||||||
|
static const QColor TABLEZONE_BG_DEFAULT = QColor(70, 50, 100);
|
||||||
|
static const QColor PLAYERZONE_BG_DEFAULT = QColor(200, 200, 200);
|
||||||
|
static const QColor STACKZONE_BG_DEFAULT = QColor(113, 43, 43);
|
||||||
|
static const QStringList DEFAULT_RESOURCE_PATHS = {":/resources"};
|
||||||
|
|
||||||
ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
|
ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
|
||||||
{
|
{
|
||||||
|
|
@ -28,7 +33,7 @@ void ThemeManager::ensureThemeDirectoryExists()
|
||||||
if (SettingsCache::instance().getThemeName().isEmpty() ||
|
if (SettingsCache::instance().getThemeName().isEmpty() ||
|
||||||
!getAvailableThemes().contains(SettingsCache::instance().getThemeName())) {
|
!getAvailableThemes().contains(SettingsCache::instance().getThemeName())) {
|
||||||
qDebug() << "Theme name not set, setting default value";
|
qDebug() << "Theme name not set, setting default value";
|
||||||
SettingsCache::instance().setThemeName(DEFAULT_THEME_NAME);
|
SettingsCache::instance().setThemeName(NONE_THEME_NAME);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -37,13 +42,17 @@ QStringMap &ThemeManager::getAvailableThemes()
|
||||||
QDir dir;
|
QDir dir;
|
||||||
availableThemes.clear();
|
availableThemes.clear();
|
||||||
|
|
||||||
// load themes from user profile dir
|
// add default value
|
||||||
dir.setPath(SettingsCache::instance().getDataPath() + "/themes");
|
availableThemes.insert(NONE_THEME_NAME, QString());
|
||||||
|
|
||||||
foreach (QString themeName, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
// load themes from user profile dir
|
||||||
if (!availableThemes.contains(themeName))
|
dir.setPath(SettingsCache::instance().getThemesPath());
|
||||||
|
|
||||||
|
for (QString themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
||||||
|
if (!availableThemes.contains(themeName)) {
|
||||||
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// load themes from cockatrice system dir
|
// load themes from cockatrice system dir
|
||||||
dir.setPath(qApp->applicationDirPath() +
|
dir.setPath(qApp->applicationDirPath() +
|
||||||
|
|
@ -56,10 +65,11 @@ QStringMap &ThemeManager::getAvailableThemes()
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
|
||||||
foreach (QString themeName, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
for (QString themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
|
||||||
if (!availableThemes.contains(themeName))
|
if (!availableThemes.contains(themeName)) {
|
||||||
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return availableThemes;
|
return availableThemes;
|
||||||
}
|
}
|
||||||
|
|
@ -97,27 +107,40 @@ void ThemeManager::themeChangedSlot()
|
||||||
QString themeName = SettingsCache::instance().getThemeName();
|
QString themeName = SettingsCache::instance().getThemeName();
|
||||||
qDebug() << "Theme changed:" << themeName;
|
qDebug() << "Theme changed:" << themeName;
|
||||||
|
|
||||||
QDir dir = getAvailableThemes().value(themeName);
|
QString dirPath = getAvailableThemes().value(themeName);
|
||||||
|
QDir dir = dirPath;
|
||||||
|
|
||||||
// css
|
// css
|
||||||
if (dir.exists(STYLE_CSS_NAME))
|
if (!dirPath.isEmpty() && dir.exists(STYLE_CSS_NAME)) {
|
||||||
|
|
||||||
qApp->setStyleSheet("file:///" + dir.absoluteFilePath(STYLE_CSS_NAME));
|
qApp->setStyleSheet("file:///" + dir.absoluteFilePath(STYLE_CSS_NAME));
|
||||||
else
|
} else {
|
||||||
qApp->setStyleSheet("");
|
qApp->setStyleSheet("");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dirPath.isEmpty()) {
|
||||||
|
// set default values
|
||||||
|
QDir::setSearchPaths("theme", DEFAULT_RESOURCE_PATHS);
|
||||||
|
handBgBrush = HANDZONE_BG_DEFAULT;
|
||||||
|
tableBgBrush = TABLEZONE_BG_DEFAULT;
|
||||||
|
playerBgBrush = PLAYERZONE_BG_DEFAULT;
|
||||||
|
stackBgBrush = STACKZONE_BG_DEFAULT;
|
||||||
|
} else {
|
||||||
// resources
|
// resources
|
||||||
QStringList resources;
|
QStringList resources;
|
||||||
resources << dir.absolutePath() << ":/resources";
|
resources << dir.absolutePath() << DEFAULT_RESOURCE_PATHS;
|
||||||
QDir::setSearchPaths("theme", resources);
|
QDir::setSearchPaths("theme", resources);
|
||||||
|
|
||||||
// zones bg
|
// zones bg
|
||||||
dir.cd("zones");
|
dir.cd("zones");
|
||||||
handBgBrush = loadBrush(HANDZONE_BG_NAME, QColor(80, 100, 50));
|
handBgBrush = loadBrush(HANDZONE_BG_NAME, HANDZONE_BG_DEFAULT);
|
||||||
tableBgBrush = loadBrush(TABLEZONE_BG_NAME, QColor(70, 50, 100));
|
tableBgBrush = loadBrush(TABLEZONE_BG_NAME, TABLEZONE_BG_DEFAULT);
|
||||||
playerBgBrush = loadBrush(PLAYERZONE_BG_NAME, QColor(200, 200, 200));
|
playerBgBrush = loadBrush(PLAYERZONE_BG_NAME, PLAYERZONE_BG_DEFAULT);
|
||||||
stackBgBrush = loadBrush(STACKZONE_BG_NAME, QColor(113, 43, 43));
|
stackBgBrush = loadBrush(STACKZONE_BG_NAME, STACKZONE_BG_DEFAULT);
|
||||||
|
}
|
||||||
tableBgBrushesCache.clear();
|
tableBgBrushesCache.clear();
|
||||||
|
stackBgBrushesCache.clear();
|
||||||
|
playerBgBrushesCache.clear();
|
||||||
|
handBgBrushesCache.clear();
|
||||||
|
|
||||||
QPixmapCache::clear();
|
QPixmapCache::clear();
|
||||||
|
|
||||||
|
|
@ -137,3 +160,45 @@ QBrush ThemeManager::getExtraTableBgBrush(QString extraNumber, QBrush &fallbackB
|
||||||
|
|
||||||
return returnBrush;
|
return returnBrush;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QBrush ThemeManager::getExtraStackBgBrush(QString extraNumber, QBrush &fallbackBrush)
|
||||||
|
{
|
||||||
|
QBrush returnBrush;
|
||||||
|
|
||||||
|
if (!stackBgBrushesCache.contains(extraNumber.toInt())) {
|
||||||
|
returnBrush = loadExtraBrush(STACKZONE_BG_NAME + extraNumber, fallbackBrush);
|
||||||
|
stackBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
||||||
|
} else {
|
||||||
|
returnBrush = stackBgBrushesCache.value(extraNumber.toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnBrush;
|
||||||
|
}
|
||||||
|
|
||||||
|
QBrush ThemeManager::getExtraPlayerBgBrush(QString extraNumber, QBrush &fallbackBrush)
|
||||||
|
{
|
||||||
|
QBrush returnBrush;
|
||||||
|
|
||||||
|
if (!playerBgBrushesCache.contains(extraNumber.toInt())) {
|
||||||
|
returnBrush = loadExtraBrush(PLAYERZONE_BG_NAME + extraNumber, fallbackBrush);
|
||||||
|
playerBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
||||||
|
} else {
|
||||||
|
returnBrush = playerBgBrushesCache.value(extraNumber.toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnBrush;
|
||||||
|
}
|
||||||
|
|
||||||
|
QBrush ThemeManager::getExtraHandBgBrush(QString extraNumber, QBrush &fallbackBrush)
|
||||||
|
{
|
||||||
|
QBrush returnBrush;
|
||||||
|
|
||||||
|
if (!handBgBrushesCache.contains(extraNumber.toInt())) {
|
||||||
|
returnBrush = loadExtraBrush(HANDZONE_BG_NAME + extraNumber, fallbackBrush);
|
||||||
|
handBgBrushesCache.insert(extraNumber.toInt(), returnBrush);
|
||||||
|
} else {
|
||||||
|
returnBrush = handBgBrushesCache.value(extraNumber.toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
return returnBrush;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,9 @@ private:
|
||||||
QBrush handBgBrush, stackBgBrush, tableBgBrush, playerBgBrush;
|
QBrush handBgBrush, stackBgBrush, tableBgBrush, playerBgBrush;
|
||||||
QStringMap availableThemes;
|
QStringMap availableThemes;
|
||||||
/*
|
/*
|
||||||
Internal cache for table backgrounds
|
Internal cache for multiple backgrounds
|
||||||
*/
|
*/
|
||||||
QBrushMap tableBgBrushesCache;
|
QBrushMap tableBgBrushesCache, stackBgBrushesCache, playerBgBrushesCache, handBgBrushesCache;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void ensureThemeDirectoryExists();
|
void ensureThemeDirectoryExists();
|
||||||
|
|
@ -51,6 +51,9 @@ public:
|
||||||
}
|
}
|
||||||
QStringMap &getAvailableThemes();
|
QStringMap &getAvailableThemes();
|
||||||
QBrush getExtraTableBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
QBrush getExtraTableBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
||||||
|
QBrush getExtraStackBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
||||||
|
QBrush getExtraPlayerBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
||||||
|
QBrush getExtraHandBgBrush(QString extraNumber, QBrush &fallbackBrush);
|
||||||
protected slots:
|
protected slots:
|
||||||
void themeChangedSlot();
|
void themeChangedSlot();
|
||||||
signals:
|
signals:
|
||||||
|
|
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue