mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-03-21 17:55:21 -05:00
Merge branch 'master' into 2474-server-status
This commit is contained in:
commit
894828962b
|
|
@ -24,66 +24,25 @@ clone_depth: 50 #same as travis, see https://www.appveyor.com/blog/2014/06/04
|
|||
image: Visual Studio 2017
|
||||
|
||||
cache:
|
||||
- c:\openssl-release
|
||||
- c:\protobuf-release
|
||||
- c:\zlib-release
|
||||
# TODO: set dependency on ps skript file (in ./ci) / "-> appveyor.yml" maybe not ideal
|
||||
# that way when we update specific cached tools there (like protobuf or zlib), cache will be newly created automatically
|
||||
# https://www.appveyor.com/docs/build-cache/#cleaning-up-cache
|
||||
|
||||
- c:\Tools\vcpkg\installed
|
||||
|
||||
environment:
|
||||
openssl_ver: 1.0.2o
|
||||
protobuf_ver: 3.6.0
|
||||
zlib_ver: 1.2.11
|
||||
|
||||
matrix:
|
||||
- target_arch: win64
|
||||
qt_ver: 5.9\msvc2017_64
|
||||
cmake_generator: Visual Studio 15 2017 Win64
|
||||
cmake_toolset: v141,host=x64
|
||||
vc_arch: amd64
|
||||
vcpkg_arch: x64
|
||||
|
||||
- target_arch: win32
|
||||
qt_ver: 5.9\msvc2015 # Qt doesn't provide a msvc2017_32
|
||||
cmake_generator: Visual Studio 15 2017
|
||||
cmake_toolset: v141
|
||||
vc_arch: amd64_x86
|
||||
|
||||
vcpkg_arch: x86
|
||||
|
||||
install:
|
||||
- ps: |
|
||||
if (Test-Path c:\openssl-release) {
|
||||
echo "using openssl from cache"
|
||||
} else {
|
||||
if ($env:target_arch -eq "win64") { # 64bit filename
|
||||
# echo "downloading 64bit version of openssl"
|
||||
Invoke-WebRequest "https://indy.fulgan.com/SSL/openssl-$env:openssl_ver-x64_86-win64.zip" -OutFile c:\openssl-$env:openssl_ver.zip
|
||||
} else { # 32bit filename
|
||||
# echo "downloading 32bit version of openssl"
|
||||
Invoke-WebRequest "https://indy.fulgan.com/SSL/openssl-$env:openssl_ver-i386-win32.zip" -OutFile c:\openssl-$env:openssl_ver.zip
|
||||
}
|
||||
Expand-Archive -Path c:\openssl-$env:openssl_ver.zip -DestinationPath c:\openssl-release
|
||||
Set-Location -Path C:\openssl-release
|
||||
}
|
||||
if (Test-Path c:\protobuf-release) {
|
||||
echo "using protobuf from cache"
|
||||
} else {
|
||||
Invoke-WebRequest "https://github.com/protocolbuffers/protobuf/releases/download/v$env:protobuf_ver/protobuf-cpp-$env:protobuf_ver.zip" -OutFile c:\protobuf-cpp-$env:protobuf_ver.zip
|
||||
Expand-Archive -Path c:\protobuf-cpp-$env:protobuf_ver.zip -DestinationPath c:\
|
||||
Set-Location -Path C:\protobuf-$env:protobuf_ver\cmake
|
||||
cmake . -G "$env:cmake_generator" -T "$env:cmake_toolset" -Dprotobuf_BUILD_TESTS=0 -Dprotobuf_MSVC_STATIC_RUNTIME=0 -DCMAKE_INSTALL_PREFIX=c:/protobuf-release
|
||||
msbuild INSTALL.vcxproj /p:Configuration=Release
|
||||
}
|
||||
if (Test-Path c:\zlib-release) {
|
||||
echo "using zlib from cache"
|
||||
} else {
|
||||
Invoke-WebRequest "https://github.com/madler/zlib/archive/v$env:zlib_ver.zip" -OutFile c:\zlib-$env:zlib_ver.zip
|
||||
Expand-Archive -Path c:\zlib-$env:zlib_ver.zip -DestinationPath c:\
|
||||
Set-Location -Path C:\zlib-$env:zlib_ver
|
||||
cmake . -G "$env:cmake_generator" -T "$env:cmake_toolset" -DCMAKE_INSTALL_PREFIX=c:/zlib-release
|
||||
msbuild INSTALL.vcxproj /p:Configuration=Release
|
||||
}
|
||||
- vcpkg remove --outdated --recurse
|
||||
- vcpkg install openssl protobuf liblzma zlib --triplet %vcpkg_arch%-windows
|
||||
|
||||
services:
|
||||
- mysql
|
||||
|
|
@ -92,13 +51,10 @@ build_script:
|
|||
- ps: |
|
||||
New-Item -ItemType directory -Path $env:APPVEYOR_BUILD_FOLDER\build
|
||||
Set-Location -Path $env:APPVEYOR_BUILD_FOLDER\build
|
||||
$zlibdir = "c:\zlib-release"
|
||||
$openssldir = "C:\openssl-release"
|
||||
$protodir = "c:\protobuf-release"
|
||||
$protoc = "c:\protobuf-release\bin\protoc.exe"
|
||||
$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_PREFIX_PATH=c:/Qt/$env:qt_ver;$protodir;$zlibdir;$openssldir" "-DWITH_SERVER=1" "-DPROTOBUF_PROTOC_EXECUTABLE=$protoc" "-DMYSQLCLIENT_LIBRARIES=$mysqldll"
|
||||
cmake .. -G "$env:cmake_generator" -T "$env:cmake_toolset" "-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"
|
||||
- msbuild PACKAGE.vcxproj /p:Configuration=Release
|
||||
- ps: |
|
||||
$exe = dir -name *.exe
|
||||
|
|
@ -110,7 +66,7 @@ build_script:
|
|||
(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: off
|
||||
|
||||
|
||||
|
|
|
|||
19
.ci/Fedora29/Dockerfile
Normal file
19
.ci/Fedora29/Dockerfile
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
FROM fedora:29
|
||||
|
||||
RUN dnf install -y \
|
||||
@development-tools \
|
||||
ccache \
|
||||
cmake \
|
||||
desktop-file-utils \
|
||||
file \
|
||||
gcc-c++ \
|
||||
hicolor-icon-theme \
|
||||
libappstream-glib \
|
||||
protobuf-devel \
|
||||
qt5-{qttools,qtsvg,qtmultimedia,qtwebsockets}-devel-5.11.1-2.fc29 \
|
||||
rpm-build \
|
||||
sqlite-devel \
|
||||
wget \
|
||||
zlib-devel \
|
||||
xz-devel \
|
||||
&& dnf clean all
|
||||
22
.ci/UbuntuBionic/Dockerfile
Normal file
22
.ci/UbuntuBionic/Dockerfile
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
FROM ubuntu:bionic
|
||||
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
clang-format \
|
||||
file \
|
||||
g++ \
|
||||
git \
|
||||
ccache \
|
||||
cmake \
|
||||
liblzma-dev \
|
||||
libprotobuf-dev \
|
||||
libqt5multimedia5-plugins \
|
||||
libqt5svg5-dev \
|
||||
libqt5sql5-mysql \
|
||||
libqt5websockets5-dev \
|
||||
protobuf-compiler \
|
||||
qt5-default \
|
||||
qttools5-dev \
|
||||
qttools5-dev-tools \
|
||||
qtmultimedia5-dev \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
|
@ -1,59 +1,149 @@
|
|||
#!/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
|
||||
;;
|
||||
*)
|
||||
if [[ $1 == -* ]]; then
|
||||
echo "unrecognized option: $1"
|
||||
exit 3
|
||||
fi
|
||||
BUILDTYPE="$1"
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Check formatting using clang-format
|
||||
if [[ $CHECK_FORMAT ]]; then
|
||||
echo "Checking your code using clang-format..."
|
||||
diff="$(./clangify.sh --diff --cf-version)"
|
||||
err=$?
|
||||
case $err in
|
||||
1)
|
||||
cat <<EOM
|
||||
***********************************************************
|
||||
*** ***
|
||||
*** Your code does not comply with our styleguide. ***
|
||||
*** ***
|
||||
*** 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 ♥ ***
|
||||
*** ***
|
||||
***********************************************************
|
||||
|
||||
Used clang-format version:
|
||||
${diff%%
|
||||
*}
|
||||
|
||||
The following changes should be made:
|
||||
${diff#*
|
||||
}
|
||||
|
||||
Exiting...
|
||||
EOM
|
||||
exit 2
|
||||
;;
|
||||
0)
|
||||
echo "Thank you for complying with our code standards."
|
||||
;;
|
||||
*)
|
||||
echo "Something went wrong in our formatting checks: clangify returned $err" >&2
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
set -e
|
||||
|
||||
# Setup
|
||||
./servatrice/check_schema_version.sh
|
||||
|
||||
mkdir -p build
|
||||
cd build
|
||||
prefix=""
|
||||
|
||||
if [[ $TRAVIS_OS_NAME == "osx" ]]; then
|
||||
export PATH="/usr/local/opt/ccache/bin:$PATH"
|
||||
prefix="-DCMAKE_PREFIX_PATH=$(echo /usr/local/opt/qt5/)"
|
||||
# Add cmake flags
|
||||
if [[ $MAKE_SERVER ]]; then
|
||||
flags+=" -DWITH_SERVER=1"
|
||||
fi
|
||||
if [[ $TRAVIS_OS_NAME == "linux" ]]; then
|
||||
prefix="-DCMAKE_PREFIX_PATH=$(echo /opt/qt5*/lib/cmake/)"
|
||||
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 -j2
|
||||
|
||||
if [[ $BUILDTYPE == "Debug" ]]; then
|
||||
cmake .. -DWITH_SERVER=1 -DCMAKE_BUILD_TYPE=$BUILDTYPE $prefix -DTEST=1
|
||||
make -j2
|
||||
if [[ $MAKE_TEST ]]; then
|
||||
make test
|
||||
|
||||
if [[ $TRAVIS_OS_NAME == "osx" ]]; then
|
||||
make install
|
||||
fi
|
||||
|
||||
if [[ $TRAVIS_OS_NAME == "linux" ]]; then
|
||||
cd ..
|
||||
clang-format -version
|
||||
clang-format -i \
|
||||
common/*.h \
|
||||
common/*.cpp \
|
||||
cockatrice/src/*.h \
|
||||
cockatrice/src/*.cpp \
|
||||
oracle/src/*.h \
|
||||
oracle/src/*.cpp \
|
||||
servatrice/src/*.h \
|
||||
servatrice/src/*.cpp
|
||||
|
||||
git clean -f
|
||||
git diff --quiet || (
|
||||
echo "*****************************************************";
|
||||
echo "*** This PR is not clean against our code style ***";
|
||||
echo "*** Run clang-format and fix up any differences ***";
|
||||
echo "*** Check our CONTRIBUTING.md file for details! ***";
|
||||
echo "*** Thank you ♥ ***";
|
||||
echo "*****************************************************";
|
||||
)
|
||||
git diff --exit-code
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $BUILDTYPE == "Release" ]]; then
|
||||
cmake .. -DWITH_SERVER=1 -DCMAKE_BUILD_TYPE=$BUILDTYPE $prefix
|
||||
make package -j2
|
||||
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
|
||||
mv "$path/$file" "$path/${file%.*}-$PACKAGE_NAME.${file##*.}"
|
||||
fi
|
||||
fi
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
#!/bin/bash
|
||||
|
||||
if [[ $TRAVIS_OS_NAME == "osx" ]] ; then
|
||||
brew update
|
||||
brew install ccache protobuf qt
|
||||
fi
|
||||
if [[ $TRAVIS_OS_NAME == "linux" ]] ; then
|
||||
echo Skipping... packages are installed with the Travis apt addon for sudo disabled container builds
|
||||
fi
|
||||
119
.github/CONTRIBUTING.md
vendored
119
.github/CONTRIBUTING.md
vendored
|
|
@ -21,6 +21,20 @@ If you have any questions on IDEs, feel free to chat with us on [Gitter](https:/
|
|||
|
||||
# Code Style Guide #
|
||||
|
||||
### 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.
|
||||
|
||||
The message will look somewhat similar to this:
|
||||
```
|
||||
************************************************************
|
||||
*** Your code does not meet our formatting guidelines. ***
|
||||
*** Please correct it then commit and push your changes. ***
|
||||
*** See our CONTRIBUTING.md file for more information. ***
|
||||
************************************************************
|
||||
```
|
||||
The CONTRIBUTING.md file mentioned is this file. Please read [this section](#Formatting) for full information on our formatting guidelines.
|
||||
|
||||
### 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!
|
||||
|
|
@ -28,7 +42,17 @@ Cockatrice is currently compiled on all platforms using <kbd>C++11</kbd>. You'll
|
|||
For consistency, we use Qt data structures where possible. For example, `QString` over
|
||||
`std::string` and `QList` over `std::vector`.
|
||||
|
||||
### Header files ###
|
||||
### 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.
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
#### Header files ####
|
||||
|
||||
Use header files with the extension `.h` and source files with the extension
|
||||
`.cpp`.
|
||||
|
|
@ -38,28 +62,28 @@ Use header guards in the form of `FILE_NAME_H`.
|
|||
Simple functions, such as getters, may be written inline in the header file,
|
||||
but other functions should be written in the source file.
|
||||
|
||||
Keep library includes and project includes grouped together. So this is okay:
|
||||
Group library includes after project includes, and in alphabetic order. Like this:
|
||||
```c++
|
||||
// Good
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include "card.h"
|
||||
#include "deck.h"
|
||||
|
||||
// Good
|
||||
#include "card.h"
|
||||
#include "deck.h"
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
|
||||
// Bad:
|
||||
// Bad
|
||||
#include <QList>
|
||||
#include "card.h"
|
||||
#include <QString>
|
||||
#include "deck.h"
|
||||
|
||||
// Bad
|
||||
#include "card.h"
|
||||
#include "deck.h"
|
||||
#include <QString>
|
||||
#include <QList>
|
||||
```
|
||||
|
||||
### Naming ###
|
||||
#### Naming ####
|
||||
|
||||
Use `UpperCamelCase` for classes, structs, enums, etc. and `lowerCamelCase` for
|
||||
function and variable names.
|
||||
|
|
@ -89,16 +113,16 @@ Bar& bar2 = *bar1;
|
|||
Use `nullptr` instead of `NULL` (or `0`) for null pointers.
|
||||
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.
|
||||
See the following example:
|
||||
```c++
|
||||
int main()
|
||||
{ // function or class: own line
|
||||
if (someCondition) { // control statement: same line
|
||||
doSomething(); // single line statement, braces preferred
|
||||
} else if (someOtherCondition1) { // else goes after closing brace
|
||||
{ // function or class: own line
|
||||
if (someCondition) { // control statement: same line
|
||||
doSomething(); // single line statement, braces preferred
|
||||
} else if (someOtherCondition1) { // else goes on the same line as a closing brace
|
||||
for (int i = 0; i < 100; i++) {
|
||||
doSomethingElse();
|
||||
}
|
||||
|
|
@ -110,20 +134,19 @@ int main()
|
|||
}
|
||||
```
|
||||
|
||||
### Indentation ###
|
||||
#### 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.
|
||||
|
||||
### Lines ###
|
||||
All operators and braces should be separated by spaces, do not add a space next to the inside of a brace.
|
||||
|
||||
Do not have trailing whitespace in your lines, if possible. Most IDEs check for this nowadays and clean it up for you.
|
||||
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 should be 120 characters or less, but you can exceed this if you find it necessary.
|
||||
#### Lines ####
|
||||
|
||||
### Automatic Formatting ###
|
||||
Do not have trailing whitespace in your lines. Most IDEs check for this nowadays and clean it up for you.
|
||||
|
||||
The handy tool `clang-format` can format your code for you, a special `.clang-format` configuration file is included [here](https://github.com/Cockatrice/Cockatrice/blob/master/.clang-format).
|
||||
See [the clang-format documentation](https://clang.llvm.org/docs/ClangFormat.html) for more information.
|
||||
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 ###
|
||||
|
||||
|
|
@ -177,35 +200,32 @@ You can find more information on how we use Protobuf on [our wiki!](https://gith
|
|||
|
||||
# Translations #
|
||||
|
||||
**Basic workflow for translations:**
|
||||
Basic workflow for translations:
|
||||
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;
|
||||
3. Transifex picks up the new files from github every 24 hours;
|
||||
4. Translators translate the new untraslated strings on Transifex;
|
||||
4. Translators translate the new untranslated strings on Transifex;
|
||||
5. Before a release, a maintainer fetches the updated translations from Transifex.
|
||||
|
||||
### Translations (for developers) ###
|
||||
### Using Translations (for developers) ###
|
||||
|
||||
**Step 1: Adding translatable strings to the code (`tr("foo")`)**
|
||||
|
||||
All the user-interface strings inside Cockatrice's source code must be written in
|
||||
english language.<br>
|
||||
All the user-interface strings inside Cockatrice's source code must be written in english.
|
||||
Translations to other languages are managed using [Transifex](https://www.transifex.com/projects/p/cockatrice/).
|
||||
|
||||
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 extracing all the new strings,
|
||||
adding them to the english translation files and making them available to
|
||||
translators on Transifex.
|
||||
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.
|
||||
For example setting the text of this label in a way that the string "My name is:" can be translated:
|
||||
```c++
|
||||
nameLabel.setText(tr("My name is:"));
|
||||
```
|
||||
|
||||
### Translations (for maintainers) ###
|
||||
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.
|
||||
|
||||
**Step 2: Updating `*_en.ts` files with new strings**
|
||||
### Maintaining Translations (for maintainers) ###
|
||||
|
||||
When new translatable strings have been added to the code, it would be nice to
|
||||
When new translatable strings have been added to the code, a maintainer should
|
||||
make them available to translators on Transifex. Every few days, or when a lot
|
||||
of new strings have been added, a maintainer should take care of extracing all
|
||||
of new strings have been added, a maintainer should take care of extracting all
|
||||
the new strings and add them to the english translation files.
|
||||
|
||||
To update the english translation files, re-run cmake enabling the appropriate
|
||||
|
|
@ -227,20 +247,18 @@ You should then notice that the following files have uncommitted changes:
|
|||
cockatrice/translations/cockatrice_en.ts
|
||||
oracle/translations/oracle_en.ts
|
||||
|
||||
It's now suggested to disable the parameter using:
|
||||
It is recommended to disable the parameter afterwards using:
|
||||
```sh
|
||||
cmake .. -DUPDATE_TRANSLATIONS=OFF
|
||||
```
|
||||
Now you are ready to propose your change.
|
||||
|
||||
**Step 3: Automatic pushing to Transifex**
|
||||
|
||||
Once your change gets merged, Transifex will pick up the modified files automatically (checks every 24 hours)
|
||||
Once your change gets merged, Transifex will pick up the modified files automatically (checked every 24 hours)
|
||||
and update the interface where translators will be able to translate the new strings.
|
||||
|
||||
**Step 5: Fetching new translations from Transifex**
|
||||
### Releasing Translations (for maintainers) ###
|
||||
|
||||
Before rushing out a new release, it would be nice to fetch the most up to date
|
||||
Before rushing out a new release, a maintainer should fetch the most up to date
|
||||
translations from Transifex and commit them into the Cockatrice source code.
|
||||
This can be done manually from the Transifex web interface, but it's quite time
|
||||
consuming.
|
||||
|
|
@ -252,10 +270,9 @@ As an alternative, you can install the Transifex CLI:
|
|||
You'll then be able to use a git-like cli command to push and pull translations
|
||||
from Transifex to the source code and vice versa.
|
||||
|
||||
### Translations (for translators) ###
|
||||
|
||||
**Step 4: Editing translations at Transifex**
|
||||
### Adding Translations (for translators) ###
|
||||
|
||||
As a translator you can help translate the new strings on [Transifex](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).
|
||||
|
||||
|
||||
|
|
@ -295,11 +312,11 @@ git tag -d $TAG_NAME
|
|||
|
||||
**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").
|
||||
|
||||
**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 overriden by the version numbers coming from the tag title, it's a good practice to keep them aligned with the real ones.
|
||||
The preferred flow of operations is:
|
||||
**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.
|
||||
The preferred flow of operation is:
|
||||
* just before a release, update the version number in CMakeLists.txt to "next release version";
|
||||
* tag the release following the previously described syntax in order to get it built by CI;
|
||||
* wait for CI to upload the binaries, double check if everything is in order
|
||||
* after the release is complete, update the version number again to "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 pick up the stable release also for users that chose the "beta" release channel.
|
||||
**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.
|
||||
|
|
|
|||
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -7,3 +7,4 @@ mysql.cnf
|
|||
.idea/
|
||||
*.aps
|
||||
cmake-build-debug/
|
||||
preferences
|
||||
|
|
|
|||
132
.travis.yml
132
.travis.yml
|
|
@ -1,54 +1,114 @@
|
|||
language: cpp
|
||||
compiler: gcc
|
||||
cache: ccache
|
||||
|
||||
matrix:
|
||||
include:
|
||||
#Ubuntu
|
||||
- name: Ubuntu (Debug)
|
||||
#Ubuntu Xenial (Debug only)
|
||||
- name: Ubuntu Xenial (Debug)
|
||||
if: tag IS NOT present
|
||||
os: linux
|
||||
dist: xenial
|
||||
group: stable
|
||||
env: BUILDTYPE=Debug
|
||||
- name: Ubuntu (Release)
|
||||
cache: ccache
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libprotobuf-dev
|
||||
- protobuf-compiler
|
||||
- liblzma-dev
|
||||
- qt5-default
|
||||
- qttools5-dev
|
||||
- qttools5-dev-tools
|
||||
- qtmultimedia5-dev
|
||||
- libqt5multimedia5-plugins
|
||||
- libqt5svg5-dev
|
||||
- libqt5sql5-mysql
|
||||
- libqt5websockets5-dev
|
||||
script: bash ./.ci/travis-compile.sh --format --server --test --debug
|
||||
|
||||
#Ubuntu Bionic (on docker)
|
||||
- name: Ubuntu Bionic (Debug)
|
||||
if: tag IS NOT present
|
||||
services: docker
|
||||
env: NAME=UbuntuBionic
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/$NAME/
|
||||
before_install: docker build -t "cockatrice_${NAME,,}" .ci/$NAME && mkdir -p $HOME/$NAME/.ccache
|
||||
script: docker run --mount "type=bind,source=$(pwd),target=/src" -w="/src"
|
||||
--mount "type=bind,source=$HOME/$NAME/.ccache,target=/.ccache" -e "CCACHE_DIR=/.ccache"
|
||||
"cockatrice_${NAME,,}"
|
||||
bash .ci/travis-compile.sh --server --debug
|
||||
|
||||
- name: Ubuntu Bionic (Release)
|
||||
if: (branch = master AND NOT type = pull_request) OR tag IS present
|
||||
os: linux
|
||||
dist: xenial
|
||||
group: stable
|
||||
env: BUILDTYPE=Release
|
||||
services: docker
|
||||
env: NAME=UbuntuBionic
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/$NAME/
|
||||
before_install: docker build -t "cockatrice_${NAME,,}" .ci/$NAME && mkdir -p $HOME/$NAME/.ccache
|
||||
script: docker run --mount "type=bind,source=$(pwd),target=/src" -w="/src"
|
||||
--mount "type=bind,source=$HOME/$NAME/.ccache,target=/.ccache" -e "CCACHE_DIR=/.ccache"
|
||||
"cockatrice_${NAME,,}"
|
||||
bash .ci/travis-compile.sh --server --package "$NAME" --release
|
||||
|
||||
#Fedora 29 (on docker)
|
||||
- name: Fedora 29 (Debug)
|
||||
if: tag IS NOT present
|
||||
services: docker
|
||||
env: NAME=Fedora29
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/$NAME/
|
||||
before_install: docker build -t "cockatrice_${NAME,,}" .ci/$NAME && mkdir -p $HOME/$NAME/.ccache
|
||||
script: docker run --mount "type=bind,source=$(pwd),target=/src" -w="/src"
|
||||
--mount "type=bind,source=$HOME/$NAME/.ccache,target=/.ccache" -e "CCACHE_DIR=/.ccache"
|
||||
"cockatrice_${NAME,,}"
|
||||
bash .ci/travis-compile.sh --server --debug
|
||||
|
||||
- name: Fedora 29 (Release)
|
||||
if: (branch = master AND NOT type = pull_request) OR tag IS present
|
||||
services: docker
|
||||
env: NAME=Fedora29
|
||||
cache:
|
||||
directories:
|
||||
- $HOME/$NAME/
|
||||
before_install: docker build -t "cockatrice_${NAME,,}" .ci/$NAME && mkdir -p $HOME/$NAME/.ccache
|
||||
script: docker run --mount "type=bind,source=$(pwd),target=/src" -w="/src"
|
||||
--mount "type=bind,source=$HOME/$NAME/.ccache,target=/.ccache" -e "CCACHE_DIR=/.ccache"
|
||||
"cockatrice_${NAME,,}"
|
||||
bash .ci/travis-compile.sh --server --package "$NAME" "RPM" --release
|
||||
|
||||
#macOS
|
||||
- name: macOS (Debug)
|
||||
if: tag IS NOT present
|
||||
os: osx
|
||||
osx_image: xcode8
|
||||
env: BUILDTYPE=Debug
|
||||
osx_image: xcode10.1
|
||||
cache: ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
- protobuf
|
||||
- qt
|
||||
- xz
|
||||
script: bash ./.ci/travis-compile.sh --server --install --debug
|
||||
|
||||
- name: macOS (Release)
|
||||
if: (branch = master AND NOT type = pull_request) OR tag IS present
|
||||
os: osx
|
||||
osx_image: xcode8
|
||||
env: BUILDTYPE=Release
|
||||
|
||||
#install dependencies for container-based "linux" builds
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- libprotobuf-dev
|
||||
- protobuf-compiler
|
||||
- qt5-default
|
||||
- qttools5-dev
|
||||
- qttools5-dev-tools
|
||||
- qtmultimedia5-dev
|
||||
- libqt5multimedia5-plugins
|
||||
- libqt5svg5-dev
|
||||
- libqt5sql5-mysql
|
||||
- libqt5websockets5-dev
|
||||
|
||||
|
||||
before_install: bash ./.ci/travis-dependencies.sh
|
||||
|
||||
script: bash ./.ci/travis-compile.sh
|
||||
|
||||
osx_image: xcode9.2
|
||||
cache: ccache
|
||||
addons:
|
||||
homebrew:
|
||||
packages:
|
||||
- ccache
|
||||
- protobuf
|
||||
- qt
|
||||
- xz
|
||||
update: true
|
||||
script: bash ./.ci/travis-compile.sh --server --package "$TRAVIS_OS_NAME" --release
|
||||
|
||||
# Builds for pull requests skip the deployment step altogether
|
||||
deploy:
|
||||
|
|
@ -67,7 +127,7 @@ deploy:
|
|||
on:
|
||||
tags: true
|
||||
repo: Cockatrice/Cockatrice
|
||||
condition: $BUILDTYPE = Release && $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
|
||||
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
|
||||
|
|
@ -82,7 +142,7 @@ deploy:
|
|||
on:
|
||||
tags: true
|
||||
repo: Cockatrice/Cockatrice
|
||||
condition: $BUILDTYPE = Release && $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
|
||||
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:
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ endif()
|
|||
|
||||
# A project name is needed for CPack
|
||||
# Version can be overriden by git tags, see cmake/getversion.cmake
|
||||
PROJECT("Cockatrice" VERSION 2.6.1)
|
||||
PROJECT("Cockatrice" VERSION 2.6.3)
|
||||
|
||||
# Use c++11 for all targets
|
||||
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ ISO Standard")
|
||||
|
|
@ -99,7 +99,8 @@ option(WARNING_AS_ERROR "Treat warnings as errors in debug builds" ON)
|
|||
IF(MSVC)
|
||||
# Visual Studio:
|
||||
# Maximum optimization
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD")
|
||||
# Disable warning C4251
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251")
|
||||
# Generate complete debugging information
|
||||
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
|
||||
ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
|
||||
|
|
@ -171,7 +172,7 @@ IF(MSVC)
|
|||
ENDIF()
|
||||
|
||||
# Package builder
|
||||
set(CPACK_PACKAGE_CONTACT "Gavin Bisesi <Daenyth+github@gmail.com>")
|
||||
set(CPACK_PACKAGE_CONTACT "Zach Halpern <zahalpern+github@gmail.com>")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_NAME})
|
||||
set(CPACK_PACKAGE_VENDOR "Cockatrice Development Team")
|
||||
set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md")
|
||||
|
|
|
|||
27
Dockerfile
27
Dockerfile
|
|
@ -1,30 +1,21 @@
|
|||
FROM ubuntu:trusty
|
||||
MAINTAINER Gavin Bisesi <Daenyth@gmail.com>
|
||||
FROM ubuntu:bionic
|
||||
MAINTAINER Zach Halpern <zahalpern+github@gmail.com>
|
||||
|
||||
RUN apt-get update && apt-get install -y software-properties-common
|
||||
RUN apt-add-repository ppa:ubuntu-sdk-team/ppa
|
||||
RUN add-apt-repository -y ppa:smspillaz/cmake-master
|
||||
RUN apt-get update && apt-get install -y\
|
||||
build-essential g++\
|
||||
build-essential\
|
||||
cmake\
|
||||
git\
|
||||
libprotobuf-dev\
|
||||
libqt5sql5-mysql\
|
||||
libqt5websockets5-dev\
|
||||
protobuf-compiler\
|
||||
qt5-default\
|
||||
qtbase5-dev\
|
||||
qttools5-dev-tools\
|
||||
qttools5-dev\
|
||||
libqt5sql5-mysql
|
||||
qttools5-dev
|
||||
|
||||
ENV dir /home/servatrice/code
|
||||
WORKDIR $dir
|
||||
RUN mkdir oracle
|
||||
COPY LICENSE LICENSE
|
||||
COPY CMakeLists.txt CMakeLists.txt
|
||||
COPY cmake/ cmake/
|
||||
COPY common/ common/
|
||||
COPY servatrice/ servatrice/
|
||||
COPY README.md README.md
|
||||
COPY . /home/servatrice/code/
|
||||
WORKDIR /home/servatrice/code
|
||||
|
||||
WORKDIR build
|
||||
RUN cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 &&\
|
||||
|
|
@ -35,4 +26,4 @@ WORKDIR /home/servatrice
|
|||
|
||||
EXPOSE 4747
|
||||
|
||||
ENTRYPOINT [ "servatrice" ]
|
||||
CMD [ "servatrice", "--log-to-console" ]
|
||||
|
|
|
|||
|
|
@ -82,13 +82,14 @@ Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Tra
|
|||
|
||||
**Detailed compiling instructions are on the Cockatrice wiki under [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)**
|
||||
|
||||
Dependencies:
|
||||
Dependencies: *(for minimum requirements search our [CMake file](https://github.com/Cockatrice/Cockatrice/blob/master/CMakeLists.txt))*
|
||||
- [Qt](https://www.qt.io/developers/)
|
||||
- [protobuf](https://github.com/google/protobuf)
|
||||
- [CMake](https://www.cmake.org/)
|
||||
|
||||
Oracle can optionally use zlib to load zipped files:
|
||||
Oracle can optionally use zlib and xz to load compressed files:
|
||||
- [zlib](https://www.zlib.net/)
|
||||
- [xz](https://tukaani.org/xz/)
|
||||
|
||||
To compile:
|
||||
|
||||
|
|
|
|||
217
clangify.sh
217
clangify.sh
|
|
@ -1,22 +1,209 @@
|
|||
#!/bin/bash
|
||||
|
||||
# This script will run clang-format on all modified, non-3rd-party C++/Header files.
|
||||
# Never, ever, should this recieve a path with a newline in it. Don't bother proofing it for that.
|
||||
|
||||
set -e
|
||||
|
||||
if hash clang-format 2>/dev/null && hash git 2>/dev/null; then
|
||||
files_to_clean=($(git diff --name-only $(git merge-base origin/master HEAD)))
|
||||
# go to the project root directory, this file should be located in the project root directory
|
||||
cd "${BASH_SOURCE%/*}/" || exit 2 # could not find path, this could happen with special links etc.
|
||||
|
||||
printf "%s\n" ${files_to_clean[@]} | \
|
||||
xargs -I{} find '{}' \( -name "*.cpp" -o -name "*.h" \) \
|
||||
-not -path "./cockatrice/src/qt-json/*" \
|
||||
-not -path "./servatrice/src/smtp/*" \
|
||||
-not -path "./common/sfmt/*" \
|
||||
-not -path "./oracle/src/zip/*" \
|
||||
-not -path "./build*/*" \
|
||||
-exec clang-format -style=file -i {} \;
|
||||
echo "Successfully formatted following files:"
|
||||
printf "%s\n" ${files_to_clean[@]}
|
||||
else
|
||||
echo "Please install clang-format and git to use this program"
|
||||
# defaults
|
||||
include=("common" \
|
||||
"cockatrice/src" \
|
||||
"oracle/src" \
|
||||
"servatrice/src")
|
||||
exclude=("servatrice/src/smtp" \
|
||||
"common/sfmt" \
|
||||
"common/lib" \
|
||||
"oracle/src/zip" \
|
||||
"oracle/src/lzma" \
|
||||
"oracle/src/qt-json")
|
||||
exts=("cpp" "h")
|
||||
cf_cmd="clang-format"
|
||||
branch="origin/master"
|
||||
|
||||
# parse options
|
||||
while [[ $@ ]]; do
|
||||
case "$1" in
|
||||
'-b'|'--branch')
|
||||
branch=$2
|
||||
set_branch=1
|
||||
shift 2
|
||||
;;
|
||||
'-c'|'--color-diff')
|
||||
color=" --color=always"
|
||||
mode=diff
|
||||
shift
|
||||
;;
|
||||
'-d'|'--diff')
|
||||
mode=diff
|
||||
shift
|
||||
;;
|
||||
'-h'|'--help')
|
||||
cat <<EOM
|
||||
A bash script to automatically format your code using clang-format.
|
||||
|
||||
If no options are given, all dirty source files are edited in place.
|
||||
If <dir>s are given, all source files in those directories of the project root
|
||||
path are formatted. To only format changed files in these directories use the
|
||||
--branch option in combination. <dir> has to be a path relative to the project
|
||||
root path or a full path inside $PWD.
|
||||
. can not be specified as a dir, if you really want to format everything use */.
|
||||
|
||||
USAGE: $0 [option] [--branch <git branch or object>] [<dir> ...]
|
||||
|
||||
DEFAULTS:
|
||||
Current includes are:
|
||||
${include[@]/%/
|
||||
}
|
||||
Default excludes are:
|
||||
${exclude[@]/%/
|
||||
}
|
||||
OPTIONS:
|
||||
-b, --branch <branch>
|
||||
Compare to this git branch and format only files that differ.
|
||||
If unspecified it defaults to origin/master.
|
||||
To not compare to a branch this has to be explicitly set to "".
|
||||
When not comparing to a branch, git will not be used at all and every
|
||||
source file in the entire project will be parsed.
|
||||
|
||||
-c, --color-diff
|
||||
Display a colored diff. Implies --diff.
|
||||
Only available on systems which support 'diff --color'.
|
||||
|
||||
-d, --diff
|
||||
Display a diff. Implies --test.
|
||||
|
||||
-h, --help
|
||||
Display this message and exit.
|
||||
|
||||
-n, --names
|
||||
Display a list of filenames that require formatting. Implies --test.
|
||||
|
||||
-t, --test
|
||||
Do not edit files in place. Set exit code to 1 if changes are required.
|
||||
|
||||
--cf-version
|
||||
Print the version of clang-format being used before continuing.
|
||||
|
||||
EXIT CODES:
|
||||
0 on a successful format or if no files require formatting.
|
||||
1 if a file requires formatting.
|
||||
2 if given incorrect arguments.
|
||||
3 if clang-format could not be found.
|
||||
|
||||
EXAMPLES:
|
||||
$0 --test \$PWD || echo "code requires formatting"
|
||||
Tests if the source files in the current directory are correctly
|
||||
formatted and prints an error message if formatting is required.
|
||||
|
||||
$0 --branch $USER/patch-2 ${include[0]}
|
||||
Formats all changed files compared to the git branch "$USER/patch-2"
|
||||
in the directory ${include[0]}.
|
||||
EOM
|
||||
exit 0
|
||||
;;
|
||||
'-n'|'--names')
|
||||
mode=name
|
||||
shift
|
||||
;;
|
||||
'-t'|'--test')
|
||||
mode=code
|
||||
shift
|
||||
;;
|
||||
'--cf-version')
|
||||
print_version=1
|
||||
shift
|
||||
;;
|
||||
'--')
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
if next_dir=$(cd "$1" && pwd); then
|
||||
if [[ ${next_dir#$PWD/} == /* ]]; then
|
||||
echo "error in parsing arguments of $0: $next_dir is not in $PWD" >&2
|
||||
exit 2 # input error
|
||||
elif ! [[ $set_include ]]; then
|
||||
include=() # remove default includes
|
||||
set_include=1
|
||||
fi
|
||||
include+=("${next_dir#$PWD/}")
|
||||
else
|
||||
echo "error in parsing arguments of $0: $PWD/$1 is not a directory" >&2
|
||||
exit 2 # input error
|
||||
fi
|
||||
if ! [[ $set_branch ]]; then
|
||||
unset branch # unset branch if not set explicitly
|
||||
fi
|
||||
shift
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# check availability of clang-format
|
||||
if ! hash $cf_cmd 2>/dev/null; then
|
||||
echo "could not find $cf_cmd" >&2
|
||||
# find any clang-format-x.x in /usr/bin
|
||||
cf_cmd=$(find /usr/bin -regex '.*/clang-format-[0-9]+\.[0-9]+' -print -quit)
|
||||
if [[ $cf_cmd ]]; then
|
||||
echo "found $cf_cmd instead" >&2
|
||||
else
|
||||
exit 3 # special exit code for missing dependency
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $branch ]]; then
|
||||
# get all dirty files through git
|
||||
if ! base=$(git merge-base ${branch} HEAD); then
|
||||
echo "could not find git merge base" >&2
|
||||
exit 2 # input error
|
||||
fi
|
||||
declare -a reg
|
||||
for ex in ${exts[@]}; do
|
||||
reg+=(${include[@]/%/.*\\.$ex\$})
|
||||
done
|
||||
names=$(git diff --name-only $base | grep ${reg[@]/#/-e ^})
|
||||
else
|
||||
names=$(find ${include[@]} -type f -false ${exts[@]/#/-o -name *\\.})
|
||||
fi
|
||||
|
||||
# filter excludes
|
||||
names=$(<<<"$names" grep -v ${exclude[@]/#/-e ^})
|
||||
|
||||
if ! [[ $names ]]; then
|
||||
exit 0 # nothing to format means format is successful!
|
||||
fi
|
||||
|
||||
# optionally print version
|
||||
[[ $print_version ]] && $cf_cmd -version
|
||||
|
||||
# format
|
||||
case $mode in
|
||||
diff)
|
||||
declare -i code=0
|
||||
for name in ${names[@]}; do
|
||||
if ! $cf_cmd "$name" | diff "$name" - -p $color; then
|
||||
code=1
|
||||
fi
|
||||
done
|
||||
exit $code
|
||||
;;
|
||||
name)
|
||||
declare -i code=0
|
||||
for name in ${names[@]}; do
|
||||
if ! $cf_cmd "$name" | diff "$name" - -q >/dev/null; then
|
||||
echo "$name"
|
||||
code=1
|
||||
fi
|
||||
done
|
||||
exit $code
|
||||
;;
|
||||
code)
|
||||
for name in ${names[@]}; do
|
||||
$cf_cmd "$name" | diff "$name" - -q >/dev/null || exit 1
|
||||
done
|
||||
;;
|
||||
*)
|
||||
$cf_cmd -i $names
|
||||
;;
|
||||
esac
|
||||
|
|
|
|||
|
|
@ -1,36 +1,36 @@
|
|||
# Find the MS Visual Studio VC redistributable package
|
||||
|
||||
if (WIN32)
|
||||
set(VCREDISTRUNTIME_FOUND "NO")
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8) # 64-bit
|
||||
set(REDIST_ARCH x64)
|
||||
else()
|
||||
set(REDIST_ARCH x86)
|
||||
endif()
|
||||
|
||||
set(REDIST_FILE vc_redist.${REDIST_ARCH}.exe)
|
||||
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
# Check if the list contains minimum one element, to get the path from
|
||||
list(LENGTH CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS libsCount)
|
||||
if (libsCount GREATER 0)
|
||||
list(GET CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS 0 _path)
|
||||
|
||||
get_filename_component(_path ${_path} DIRECTORY)
|
||||
get_filename_component(_path ${_path}/../../ ABSOLUTE)
|
||||
|
||||
if (EXISTS "${_path}/${REDIST_FILE}") # VS 2017
|
||||
set(VCREDISTRUNTIME_FOUND "YES")
|
||||
set(VCREDISTRUNTIME_FILE ${_path}/${REDIST_FILE})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(VCREDISTRUNTIME_FOUND)
|
||||
message(STATUS "Found VCredist ${VCREDISTRUNTIME_FILE}")
|
||||
else()
|
||||
message(WARNING "Could not find VCredist package. It's not required for compiling, but needs to be available at runtime.")
|
||||
endif()
|
||||
endif()
|
||||
# Find the MS Visual Studio VC redistributable package
|
||||
|
||||
if (WIN32)
|
||||
set(VCREDISTRUNTIME_FOUND "NO")
|
||||
|
||||
if(CMAKE_SIZEOF_VOID_P EQUAL 8) # 64-bit
|
||||
set(REDIST_ARCH x64)
|
||||
else()
|
||||
set(REDIST_ARCH x86)
|
||||
endif()
|
||||
|
||||
set(REDIST_FILE vcredist_${REDIST_ARCH}.exe)
|
||||
|
||||
set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_SKIP TRUE)
|
||||
include(InstallRequiredSystemLibraries)
|
||||
|
||||
# Check if the list contains minimum one element, to get the path from
|
||||
list(LENGTH CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS libsCount)
|
||||
if (libsCount GREATER 0)
|
||||
list(GET CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS 0 _path)
|
||||
|
||||
get_filename_component(_path ${_path} DIRECTORY)
|
||||
get_filename_component(_path ${_path}/../../ ABSOLUTE)
|
||||
|
||||
if (EXISTS "${_path}/${REDIST_FILE}") # VS 2017
|
||||
set(VCREDISTRUNTIME_FOUND "YES")
|
||||
set(VCREDISTRUNTIME_FILE ${_path}/${REDIST_FILE})
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(VCREDISTRUNTIME_FOUND)
|
||||
message(STATUS "Found VCredist ${VCREDISTRUNTIME_FILE}")
|
||||
else()
|
||||
message(WARNING "Could not find VCredist package. It's not required for compiling, but needs to be available at runtime.")
|
||||
endif()
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -1,69 +1,71 @@
|
|||
# Find the OpenSSL runtime libraries (.dll) for Windows that
|
||||
# will be needed by Qt in order to access https urls.
|
||||
|
||||
if (WIN32)
|
||||
# Get standard installation paths for OpenSSL under Windows
|
||||
|
||||
# http://www.slproweb.com/products/Win32OpenSSL.html
|
||||
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
# target win64
|
||||
set(_OPENSSL_ROOT_HINTS
|
||||
${OPENSSL_ROOT_DIR}
|
||||
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]"
|
||||
ENV OPENSSL_ROOT_DIR
|
||||
)
|
||||
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
|
||||
set(_OPENSSL_ROOT_PATHS
|
||||
"${_programfiles}/OpenSSL-Win64"
|
||||
"C:/OpenSSL-Win64/"
|
||||
)
|
||||
unset(_programfiles)
|
||||
else( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
# target win32
|
||||
set(_OPENSSL_ROOT_HINTS
|
||||
${OPENSSL_ROOT_DIR}
|
||||
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]"
|
||||
ENV OPENSSL_ROOT_DIR
|
||||
)
|
||||
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
|
||||
set(_OPENSSL_ROOT_PATHS
|
||||
"${_programfiles}/OpenSSL"
|
||||
"${_programfiles}/OpenSSL-Win32"
|
||||
"C:/OpenSSL/"
|
||||
"C:/OpenSSL-Win32/"
|
||||
)
|
||||
unset(_programfiles)
|
||||
endif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
|
||||
else ()
|
||||
set(_OPENSSL_ROOT_HINTS
|
||||
${OPENSSL_ROOT_DIR}
|
||||
ENV OPENSSL_ROOT_DIR
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(_OPENSSL_ROOT_HINTS_AND_PATHS
|
||||
HINTS ${_OPENSSL_ROOT_HINTS}
|
||||
PATHS ${_OPENSSL_ROOT_PATHS}
|
||||
)
|
||||
|
||||
# For OpenSSL < 1.1, they are named libeay32 and ssleay32 and even if the dll is 64bit, it's still suffixed as *32.dll
|
||||
# For OpenSSL >= 1.1, they are named libcrypto and libssl with no suffix
|
||||
FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libeay32.dll libcrypto.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
|
||||
FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES ssleay32.dll libssl.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
|
||||
|
||||
|
||||
IF(WIN32SSLRUNTIME_LIBEAY AND WIN32SSLRUNTIME_SSLEAY)
|
||||
SET(WIN32SSLRUNTIME_LIBRARIES "${WIN32SSLRUNTIME_LIBEAY}" "${WIN32SSLRUNTIME_SSLEAY}")
|
||||
SET(WIN32SSLRUNTIME_FOUND "YES")
|
||||
message(STATUS "Found OpenSSL ${WIN32SSLRUNTIME_LIBRARIES}")
|
||||
ELSE()
|
||||
SET(WIN32SSLRUNTIME_FOUND "NO")
|
||||
message(WARNING "Could not find OpenSSL runtime libraries. They are not required for compiling, but needs to be available at runtime.")
|
||||
ENDIF()
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
WIN32SSLRUNTIME_LIBEAY
|
||||
WIN32SSLRUNTIME_SSLEAY
|
||||
)
|
||||
# Find the OpenSSL runtime libraries (.dll) for Windows that
|
||||
# will be needed by Qt in order to access https urls.
|
||||
|
||||
if (WIN32)
|
||||
# Get standard installation paths for OpenSSL under Windows
|
||||
|
||||
# http://www.slproweb.com/products/Win32OpenSSL.html
|
||||
|
||||
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
# target win64
|
||||
set(_OPENSSL_ROOT_HINTS
|
||||
${OPENSSL_ROOT_DIR}
|
||||
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]"
|
||||
ENV OPENSSL_ROOT_DIR
|
||||
)
|
||||
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
|
||||
set(_OPENSSL_ROOT_PATHS
|
||||
"C:/Tools/vcpkg/installed/x64-windows/bin"
|
||||
"${_programfiles}/OpenSSL-Win64"
|
||||
"C:/OpenSSL-Win64/"
|
||||
)
|
||||
unset(_programfiles)
|
||||
else( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
# target win32
|
||||
set(_OPENSSL_ROOT_HINTS
|
||||
${OPENSSL_ROOT_DIR}
|
||||
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (32-bit)_is1;Inno Setup: App Path]"
|
||||
ENV OPENSSL_ROOT_DIR
|
||||
)
|
||||
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
|
||||
set(_OPENSSL_ROOT_PATHS
|
||||
"C:/Tools/vcpkg/installed/x86-windows/bin"
|
||||
"${_programfiles}/OpenSSL"
|
||||
"${_programfiles}/OpenSSL-Win32"
|
||||
"C:/OpenSSL/"
|
||||
"C:/OpenSSL-Win32/"
|
||||
)
|
||||
unset(_programfiles)
|
||||
endif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
|
||||
|
||||
else ()
|
||||
set(_OPENSSL_ROOT_HINTS
|
||||
${OPENSSL_ROOT_DIR}
|
||||
ENV OPENSSL_ROOT_DIR
|
||||
)
|
||||
endif ()
|
||||
|
||||
set(_OPENSSL_ROOT_HINTS_AND_PATHS
|
||||
HINTS ${_OPENSSL_ROOT_HINTS}
|
||||
PATHS ${_OPENSSL_ROOT_PATHS}
|
||||
)
|
||||
|
||||
# For OpenSSL < 1.1, they are named libeay32 and ssleay32 and even if the dll is 64bit, it's still suffixed as *32.dll
|
||||
# For OpenSSL >= 1.1, they are named libcrypto and libssl with no suffix
|
||||
FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libeay32.dll libcrypto.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
|
||||
FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES ssleay32.dll libssl.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
|
||||
|
||||
|
||||
IF(WIN32SSLRUNTIME_LIBEAY AND WIN32SSLRUNTIME_SSLEAY)
|
||||
SET(WIN32SSLRUNTIME_LIBRARIES "${WIN32SSLRUNTIME_LIBEAY}" "${WIN32SSLRUNTIME_SSLEAY}")
|
||||
SET(WIN32SSLRUNTIME_FOUND "YES")
|
||||
message(STATUS "Found OpenSSL ${WIN32SSLRUNTIME_LIBRARIES}")
|
||||
ELSE()
|
||||
SET(WIN32SSLRUNTIME_FOUND "NO")
|
||||
message(WARNING "Could not find OpenSSL runtime libraries. They are not required for compiling, but needs to be available at runtime.")
|
||||
ENDIF()
|
||||
|
||||
MARK_AS_ADVANCED(
|
||||
WIN32SSLRUNTIME_LIBEAY
|
||||
WIN32SSLRUNTIME_SSLEAY
|
||||
)
|
||||
|
|
|
|||
|
|
@ -34,5 +34,7 @@
|
|||
<string>${MACOSX_BUNDLE_COPYRIGHT}</string>
|
||||
<key>NSHighResolutionCapable</key>
|
||||
<true/>
|
||||
<key>NSRequiresAquaSystemAppearance</key>
|
||||
<true/>
|
||||
</dict>
|
||||
</plist>
|
||||
</plist>
|
||||
|
|
|
|||
|
|
@ -247,20 +247,20 @@ ${If} $PortableMode = 0
|
|||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "VersionMajor" "@CPACK_PACKAGE_VERSION_MAJOR@"
|
||||
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\Cockatrice" "VersionMinor" "@CPACK_PACKAGE_VERSION_MINOR@"
|
||||
|
||||
IfFileExists "$INSTDIR\vc_redist.x86.exe" VcRedist86Exists PastVcRedist86Check
|
||||
IfFileExists "$INSTDIR\vcredist_x86.exe" VcRedist86Exists PastVcRedist86Check
|
||||
VcRedist86Exists:
|
||||
ExecWait '"$INSTDIR\vc_redist.x86.exe" /passive /norestart'
|
||||
ExecWait '"$INSTDIR\vcredist_x86.exe" /passive /norestart'
|
||||
DetailPrint "Sleep to ensure unlock of vc_redist file after installation..."
|
||||
Sleep 3000
|
||||
Delete "$INSTDIR\vc_redist.x86.exe"
|
||||
Delete "$INSTDIR\vcredist_x86.exe"
|
||||
PastVcRedist86Check:
|
||||
|
||||
IfFileExists "$INSTDIR\vc_redist.x64.exe" VcRedist64Exists PastVcRedist64Check
|
||||
IfFileExists "$INSTDIR\vcredist_x64.exe" VcRedist64Exists PastVcRedist64Check
|
||||
VcRedist64Exists:
|
||||
ExecWait '"$INSTDIR\vc_redist.x64.exe" /passive /norestart'
|
||||
ExecWait '"$INSTDIR\vcredist_x64.exe" /passive /norestart'
|
||||
DetailPrint "Sleep to ensure unlock of vc_redist file after installation..."
|
||||
Sleep 3000
|
||||
Delete "$INSTDIR\vc_redist.x64.exe"
|
||||
Delete "$INSTDIR\vcredist_x64.exe"
|
||||
PastVcRedist64Check:
|
||||
|
||||
${Else}
|
||||
|
|
|
|||
|
|
@ -100,7 +100,6 @@ SET(cockatrice_SOURCES
|
|||
src/localserver.cpp
|
||||
src/localserverinterface.cpp
|
||||
src/localclient.cpp
|
||||
src/qt-json/json.cpp
|
||||
src/soundengine.cpp
|
||||
src/pending_command.cpp
|
||||
src/pictureloader.cpp
|
||||
|
|
@ -114,15 +113,18 @@ SET(cockatrice_SOURCES
|
|||
src/settings/messagesettings.cpp
|
||||
src/settings/gamefilterssettings.cpp
|
||||
src/settings/layoutssettings.cpp
|
||||
src/settings/downloadsettings.cpp
|
||||
src/update_downloader.cpp
|
||||
src/logger.cpp
|
||||
src/releasechannel.cpp
|
||||
src/userconnection_information.cpp
|
||||
src/spoilerbackgroundupdater.cpp
|
||||
src/handle_public_servers.cpp
|
||||
src/carddbparser/carddatabaseparser.cpp
|
||||
src/carddbparser/cockatricexml3.cpp
|
||||
src/carddbparser/cockatricexml4.cpp
|
||||
${VERSION_STRING_CPP}
|
||||
)
|
||||
)
|
||||
|
||||
add_subdirectory(sounds)
|
||||
add_subdirectory(themes)
|
||||
|
|
@ -149,8 +151,8 @@ if(APPLE)
|
|||
ENDIF(APPLE)
|
||||
|
||||
# Qt5
|
||||
find_package(Qt5 COMPONENTS Concurrent Multimedia Network PrintSupport Svg Widgets REQUIRED)
|
||||
set(COCKATRICE_QT_MODULES Qt5::Concurrent Qt5::Multimedia Qt5::Network Qt5::PrintSupport Qt5::Svg Qt5::Widgets)
|
||||
find_package(Qt5 COMPONENTS Concurrent Multimedia Network PrintSupport Svg WebSockets Widgets REQUIRED)
|
||||
set(COCKATRICE_QT_MODULES Qt5::Concurrent Qt5::Multimedia Qt5::Network Qt5::PrintSupport Qt5::Svg Qt5::Widgets Qt5::WebSockets)
|
||||
|
||||
# Qt5LinguistTools
|
||||
find_package(Qt5LinguistTools)
|
||||
|
|
@ -254,6 +256,8 @@ if(WIN32)
|
|||
set(plugin_dest_dir Plugins)
|
||||
set(qtconf_dest_dir .)
|
||||
|
||||
install(DIRECTORY "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${CMAKE_BUILD_TYPE}/" DESTINATION ./ FILES_MATCHING PATTERN "*.dll")
|
||||
|
||||
# qt5 plugins: audio, iconengines, imageformats, platforms, printsupport
|
||||
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
|
||||
FILES_MATCHING REGEX "(audio|iconengines|imageformats|platforms|printsupport)/.*[^d]\\.dll")
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@
|
|||
<file>resources/tips/images/cockatrice_register.png</file>
|
||||
<file>resources/tips/images/cockatrice_wiki.png</file>
|
||||
<file>resources/tips/images/coin_flip.png</file>
|
||||
<file>resources/tips/images/counter_expression.png</file>
|
||||
<file>resources/tips/images/face_down.png</file>
|
||||
<file>resources/tips/images/filter_games.png</file>
|
||||
<file>resources/tips/images/github_logo.png</file>
|
||||
|
|
|
|||
BIN
cockatrice/resources/tips/images/counter_expression.png
Normal file
BIN
cockatrice/resources/tips/images/counter_expression.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 44 KiB |
|
|
@ -83,4 +83,10 @@
|
|||
<image>face_down.png</image>
|
||||
<date>2018-03-01</date>
|
||||
</tip>
|
||||
<tip>
|
||||
<title>Counter expressions</title>
|
||||
<text>When setting a counter value, you can type a math expression in the box and the counter will be set to the result.<br>The "x" variable contains the current counter value.</text>
|
||||
<image>counter_expression.png</image>
|
||||
<date>2019-02-02</date>
|
||||
</tip>
|
||||
</tips>
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
#include "abstractcounter.h"
|
||||
#include "expression.h"
|
||||
#include "pb/command_inc_counter.pb.h"
|
||||
#include "pb/command_set_counter.pb.h"
|
||||
#include "player.h"
|
||||
#include "settingscache.h"
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QGraphicsSceneHoverEvent>
|
||||
#include <QGraphicsSceneMouseEvent>
|
||||
#include <QMenu>
|
||||
|
|
@ -17,7 +19,7 @@ AbstractCounter::AbstractCounter(Player *_player,
|
|||
bool _useNameForShortcut,
|
||||
QGraphicsItem *parent)
|
||||
: QGraphicsItem(parent), player(_player), id(_id), name(_name), value(_value),
|
||||
useNameForShortcut(_useNameForShortcut), hovered(false), aDec(0), aInc(0), dialogSemaphore(false),
|
||||
useNameForShortcut(_useNameForShortcut), hovered(false), aDec(nullptr), aInc(nullptr), dialogSemaphore(false),
|
||||
deleteAfterDialog(false), shownInCounterArea(_shownInCounterArea)
|
||||
{
|
||||
setAcceptHoverEvents(true);
|
||||
|
|
@ -46,7 +48,7 @@ AbstractCounter::AbstractCounter(Player *_player,
|
|||
} else
|
||||
menu = nullptr;
|
||||
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()), this, SLOT(refreshShortcuts()));
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||
refreshShortcuts();
|
||||
retranslateUi();
|
||||
}
|
||||
|
|
@ -114,7 +116,11 @@ void AbstractCounter::setValue(int _value)
|
|||
void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
||||
{
|
||||
if (isUnderMouse() && player->getLocal()) {
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
if (event->button() == Qt::MidButton || (QApplication::keyboardModifiers() & Qt::ShiftModifier)) {
|
||||
if (menu)
|
||||
menu->exec(event->screenPos());
|
||||
event->accept();
|
||||
} else if (event->button() == Qt::LeftButton) {
|
||||
Command_IncCounter cmd;
|
||||
cmd.set_counter_id(id);
|
||||
cmd.set_delta(1);
|
||||
|
|
@ -126,10 +132,6 @@ void AbstractCounter::mousePressEvent(QGraphicsSceneMouseEvent *event)
|
|||
cmd.set_delta(-1);
|
||||
player->sendGameCommand(cmd);
|
||||
event->accept();
|
||||
} else if (event->button() == Qt::MidButton) {
|
||||
if (menu)
|
||||
menu->exec(event->screenPos());
|
||||
event->accept();
|
||||
}
|
||||
} else
|
||||
event->ignore();
|
||||
|
|
@ -160,8 +162,12 @@ void AbstractCounter::setCounter()
|
|||
{
|
||||
bool ok;
|
||||
dialogSemaphore = true;
|
||||
int newValue = QInputDialog::getInt(0, tr("Set counter"), tr("New value for counter '%1':").arg(name), value,
|
||||
-2000000000, 2000000000, 1, &ok);
|
||||
QString expression = QInputDialog::getText(nullptr, tr("Set counter"), tr("New value for counter '%1':").arg(name),
|
||||
QLineEdit::Normal, QString::number(value), &ok);
|
||||
|
||||
Expression exp(value);
|
||||
int newValue = static_cast<int>(exp.parse(expression));
|
||||
|
||||
if (deleteAfterDialog) {
|
||||
deleteLater();
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ class AbstractCounter : public QObject, public QGraphicsItem
|
|||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(QGraphicsItem)
|
||||
|
||||
protected:
|
||||
Player *player;
|
||||
int id;
|
||||
|
|
@ -18,15 +19,17 @@ protected:
|
|||
int value;
|
||||
bool useNameForShortcut, hovered;
|
||||
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event);
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
void hoverLeaveEvent(QGraphicsSceneHoverEvent *event) override;
|
||||
|
||||
private:
|
||||
QAction *aSet, *aDec, *aInc;
|
||||
QMenu *menu;
|
||||
bool dialogSemaphore, deleteAfterDialog;
|
||||
bool shownInCounterArea;
|
||||
bool shortcutActive;
|
||||
|
||||
private slots:
|
||||
void refreshShortcuts();
|
||||
void incrementCounter();
|
||||
|
|
@ -39,14 +42,19 @@ public:
|
|||
bool _shownInCounterArea,
|
||||
int _value,
|
||||
bool _useNameForShortcut = false,
|
||||
QGraphicsItem *parent = 0);
|
||||
~AbstractCounter();
|
||||
QGraphicsItem *parent = nullptr);
|
||||
~AbstractCounter() override;
|
||||
|
||||
void retranslateUi();
|
||||
void setValue(int _value);
|
||||
void setShortcutsActive();
|
||||
void setShortcutsInactive();
|
||||
void delCounter();
|
||||
|
||||
QMenu *getMenu() const
|
||||
{
|
||||
return menu;
|
||||
}
|
||||
void retranslateUi();
|
||||
|
||||
int getId() const
|
||||
{
|
||||
|
|
@ -64,12 +72,6 @@ public:
|
|||
{
|
||||
return value;
|
||||
}
|
||||
void setValue(int _value);
|
||||
void delCounter();
|
||||
|
||||
void setShortcutsActive();
|
||||
void setShortcutsInactive();
|
||||
bool shortcutActive;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#include "carddatabase.h"
|
||||
#include "carddbparser/cockatricexml3.h"
|
||||
#include "carddbparser/cockatricexml4.h"
|
||||
#include "game_specific_terms.h"
|
||||
#include "pictureloader.h"
|
||||
#include "settingscache.h"
|
||||
#include "spoilerbackgroundupdater.h"
|
||||
|
|
@ -207,30 +209,23 @@ void SetList::guessSortKeys()
|
|||
}
|
||||
}
|
||||
|
||||
CardInfoPerSet::CardInfoPerSet(const CardSetPtr &_set) : set(_set)
|
||||
{
|
||||
}
|
||||
|
||||
CardInfo::CardInfo(const QString &_name,
|
||||
bool _isToken,
|
||||
const QString &_manacost,
|
||||
const QString &_cmc,
|
||||
const QString &_cardtype,
|
||||
const QString &_powtough,
|
||||
const QString &_text,
|
||||
const QStringList &_colors,
|
||||
bool _isToken,
|
||||
QVariantHash _properties,
|
||||
const QList<CardRelation *> &_relatedCards,
|
||||
const QList<CardRelation *> &_reverseRelatedCards,
|
||||
bool _upsideDownArt,
|
||||
const QString &_loyalty,
|
||||
CardInfoPerSetMap _sets,
|
||||
bool _cipt,
|
||||
int _tableRow,
|
||||
const SetList &_sets,
|
||||
const QStringMap &_customPicURLs,
|
||||
MuidMap _muIds,
|
||||
QStringMap _collectorNumbers,
|
||||
QStringMap _rarities)
|
||||
: name(_name), isToken(_isToken), sets(_sets), manacost(_manacost), cmc(_cmc), cardtype(_cardtype),
|
||||
powtough(_powtough), text(_text), colors(_colors), relatedCards(_relatedCards),
|
||||
reverseRelatedCards(_reverseRelatedCards), setsNames(), upsideDownArt(_upsideDownArt), loyalty(_loyalty),
|
||||
customPicURLs(_customPicURLs), muIds(std::move(_muIds)), collectorNumbers(std::move(_collectorNumbers)),
|
||||
rarities(std::move(_rarities)), cipt(_cipt), tableRow(_tableRow)
|
||||
bool _upsideDownArt)
|
||||
: name(_name), text(_text), isToken(_isToken), properties(std::move(_properties)), relatedCards(_relatedCards),
|
||||
reverseRelatedCards(_reverseRelatedCards), sets(std::move(_sets)), cipt(_cipt), tableRow(_tableRow),
|
||||
upsideDownArt(_upsideDownArt)
|
||||
{
|
||||
pixmapCacheKey = QLatin1String("card_") + name;
|
||||
simpleName = CardInfo::simplifyName(name);
|
||||
|
|
@ -244,76 +239,27 @@ CardInfo::~CardInfo()
|
|||
}
|
||||
|
||||
CardInfoPtr CardInfo::newInstance(const QString &_name,
|
||||
bool _isToken,
|
||||
const QString &_manacost,
|
||||
const QString &_cmc,
|
||||
const QString &_cardtype,
|
||||
const QString &_powtough,
|
||||
const QString &_text,
|
||||
const QStringList &_colors,
|
||||
bool _isToken,
|
||||
QVariantHash _properties,
|
||||
const QList<CardRelation *> &_relatedCards,
|
||||
const QList<CardRelation *> &_reverseRelatedCards,
|
||||
bool _upsideDownArt,
|
||||
const QString &_loyalty,
|
||||
CardInfoPerSetMap _sets,
|
||||
bool _cipt,
|
||||
int _tableRow,
|
||||
const SetList &_sets,
|
||||
const QStringMap &_customPicURLs,
|
||||
MuidMap _muIds,
|
||||
QStringMap _collectorNumbers,
|
||||
QStringMap _rarities)
|
||||
bool _upsideDownArt)
|
||||
{
|
||||
CardInfoPtr ptr(new CardInfo(_name, _isToken, _manacost, _cmc, _cardtype, _powtough, _text, _colors, _relatedCards,
|
||||
_reverseRelatedCards, _upsideDownArt, _loyalty, _cipt, _tableRow, _sets,
|
||||
_customPicURLs, std::move(_muIds), std::move(_collectorNumbers),
|
||||
std::move(_rarities)));
|
||||
CardInfoPtr ptr(new CardInfo(_name, _text, _isToken, std::move(_properties), _relatedCards, _reverseRelatedCards,
|
||||
_sets, _cipt, _tableRow, _upsideDownArt));
|
||||
ptr->setSmartPointer(ptr);
|
||||
|
||||
for (int i = 0; i < _sets.size(); i++) {
|
||||
_sets[i]->append(ptr);
|
||||
for (const CardInfoPerSet &set : _sets) {
|
||||
set.getPtr()->append(ptr);
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
QString CardInfo::getMainCardType() const
|
||||
{
|
||||
QString result = getCardType();
|
||||
/*
|
||||
Legendary Artifact Creature - Golem
|
||||
Instant // Instant
|
||||
*/
|
||||
|
||||
int pos;
|
||||
if ((pos = result.indexOf('-')) != -1) {
|
||||
result.remove(pos, result.length());
|
||||
}
|
||||
|
||||
if ((pos = result.indexOf("—")) != -1) {
|
||||
result.remove(pos, result.length());
|
||||
}
|
||||
|
||||
if ((pos = result.indexOf("//")) != -1) {
|
||||
result.remove(pos, result.length());
|
||||
}
|
||||
|
||||
result = result.simplified();
|
||||
/*
|
||||
Legendary Artifact Creature
|
||||
Instant
|
||||
*/
|
||||
|
||||
if ((pos = result.lastIndexOf(' ')) != -1) {
|
||||
result = result.mid(pos + 1);
|
||||
}
|
||||
/*
|
||||
Creature
|
||||
Instant
|
||||
*/
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
QString CardInfo::getCorrectedName() const
|
||||
{
|
||||
QString result = name;
|
||||
|
|
@ -321,26 +267,21 @@ QString CardInfo::getCorrectedName() const
|
|||
return result.remove(" // ").remove(':').remove('"').remove('?').replace('/', ' ');
|
||||
}
|
||||
|
||||
void CardInfo::addToSet(CardSetPtr set)
|
||||
void CardInfo::addToSet(const CardSetPtr &_set, const CardInfoPerSet _info)
|
||||
{
|
||||
if (set.isNull()) {
|
||||
qDebug() << "addToSet(nullptr)";
|
||||
return;
|
||||
}
|
||||
|
||||
set->append(smartThis);
|
||||
sets << set;
|
||||
_set->append(smartThis);
|
||||
sets.insert(_set->getShortName(), _info);
|
||||
|
||||
refreshCachedSetNames();
|
||||
}
|
||||
|
||||
void CardInfo::refreshCachedSetNames()
|
||||
{
|
||||
// update the cached list of set names
|
||||
QStringList setList;
|
||||
for (int i = 0; i < sets.size(); i++) {
|
||||
if (sets[i]->getEnabled()) {
|
||||
setList << sets[i]->getShortName();
|
||||
// update the cached list of set names
|
||||
for (const auto &set : sets) {
|
||||
if (set.getPtr()->getEnabled()) {
|
||||
setList << set.getPtr()->getShortName();
|
||||
}
|
||||
}
|
||||
setsNames = setList.join(", ");
|
||||
|
|
@ -369,11 +310,12 @@ QString CardInfo::simplifyName(const QString &name)
|
|||
|
||||
const QChar CardInfo::getColorChar() const
|
||||
{
|
||||
QString colors = getColors();
|
||||
switch (colors.size()) {
|
||||
case 0:
|
||||
return QChar();
|
||||
case 1:
|
||||
return colors.first().isEmpty() ? QChar() : colors.first().at(0);
|
||||
return colors.at(0);
|
||||
default:
|
||||
return QChar('m');
|
||||
}
|
||||
|
|
@ -386,6 +328,7 @@ CardDatabase::CardDatabase(QObject *parent) : QObject(parent), loadStatus(NotLoa
|
|||
|
||||
// add new parsers here
|
||||
availableParsers << new CockatriceXml3Parser;
|
||||
availableParsers << new CockatriceXml4Parser;
|
||||
|
||||
for (auto &parser : availableParsers) {
|
||||
connect(parser, SIGNAL(addCard(CardInfoPtr)), this, SLOT(addCard(CardInfoPtr)), Qt::DirectConnection);
|
||||
|
|
@ -417,9 +360,7 @@ void CardDatabase::clear()
|
|||
simpleNameCards.clear();
|
||||
|
||||
sets.clear();
|
||||
for (auto parser : availableParsers) {
|
||||
parser->clearSetlist();
|
||||
}
|
||||
ICardDatabaseParser::clearSetlist();
|
||||
|
||||
loadStatus = NotLoaded;
|
||||
|
||||
|
|
@ -436,12 +377,8 @@ void CardDatabase::addCard(CardInfoPtr card)
|
|||
// if card already exists just add the new set property
|
||||
if (cards.contains(card->getName())) {
|
||||
CardInfoPtr sameCard = cards[card->getName()];
|
||||
for (auto set : card->getSets()) {
|
||||
QString setName = set->getCorrectedShortName();
|
||||
sameCard->setSet(set);
|
||||
sameCard->setMuId(setName, card->getMuId(setName));
|
||||
sameCard->setRarity(setName, card->getRarity(setName));
|
||||
sameCard->setSetNumber(setName, card->getCollectorNumber(setName));
|
||||
for (const CardInfoPerSet &set : card->getSets()) {
|
||||
sameCard->addToSet(set.getPtr(), set);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
@ -582,7 +519,7 @@ LoadStatus CardDatabase::loadCardDatabases()
|
|||
|
||||
// load custom card databases
|
||||
QDir dir(settingsCache->getCustomCardDatabasePath());
|
||||
for (QString fileName :
|
||||
for (const QString &fileName :
|
||||
dir.entryList(QStringList("*.xml"), QDir::Files | QDir::Readable, QDir::Name | QDir::IgnoreCase)) {
|
||||
loadCardDatabase(dir.absoluteFilePath(fileName));
|
||||
}
|
||||
|
|
@ -614,20 +551,13 @@ void CardDatabase::refreshCachedReverseRelatedCards()
|
|||
continue;
|
||||
}
|
||||
|
||||
QString relatedCardName;
|
||||
if (card->getPowTough().size() > 0) {
|
||||
relatedCardName = card->getPowTough() + " " + card->getName(); // "n/n name"
|
||||
} else {
|
||||
relatedCardName = card->getName(); // "name"
|
||||
}
|
||||
|
||||
foreach (CardRelation *cardRelation, card->getReverseRelatedCards()) {
|
||||
const QString &targetCard = cardRelation->getName();
|
||||
if (!cards.contains(targetCard)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto *newCardRelation = new CardRelation(relatedCardName, cardRelation->getDoesAttach(),
|
||||
auto *newCardRelation = new CardRelation(card->getName(), cardRelation->getDoesAttach(),
|
||||
cardRelation->getIsCreateAllExclusion(),
|
||||
cardRelation->getIsVariable(), cardRelation->getDefaultCount());
|
||||
cards.value(targetCard)->addReverseRelatedCards2Me(newCardRelation);
|
||||
|
|
@ -635,23 +565,6 @@ void CardDatabase::refreshCachedReverseRelatedCards()
|
|||
}
|
||||
}
|
||||
|
||||
QStringList CardDatabase::getAllColors() const
|
||||
{
|
||||
QSet<QString> colors;
|
||||
QHashIterator<QString, CardInfoPtr> cardIterator(cards);
|
||||
while (cardIterator.hasNext()) {
|
||||
const QStringList &cardColors = cardIterator.next().value()->getColors();
|
||||
if (cardColors.isEmpty()) {
|
||||
colors.insert("X");
|
||||
} else {
|
||||
for (int i = 0; i < cardColors.size(); ++i) {
|
||||
colors.insert(cardColors[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return colors.toList();
|
||||
}
|
||||
|
||||
QStringList CardDatabase::getAllMainCardTypes() const
|
||||
{
|
||||
QSet<QString> types;
|
||||
|
|
@ -717,8 +630,8 @@ bool CardDatabase::saveCustomTokensToFile()
|
|||
tmpSets.insert(CardDatabase::TOKENS_SETNAME, customTokensSet);
|
||||
|
||||
CardNameMap tmpCards;
|
||||
for (CardInfoPtr card : cards) {
|
||||
if (card->getSets().contains(customTokensSet)) {
|
||||
for (const CardInfoPtr &card : cards) {
|
||||
if (card->getSets().contains(CardDatabase::TOKENS_SETNAME)) {
|
||||
tmpCards.insert(card->getName(), card);
|
||||
}
|
||||
}
|
||||
|
|
@ -743,4 +656,46 @@ void CardInfo::resetReverseRelatedCards2Me()
|
|||
cardRelation->deleteLater();
|
||||
}
|
||||
reverseRelatedCardsToMe = QList<CardRelation *>();
|
||||
}
|
||||
|
||||
// Back-compatibility methods. Remove ASAP
|
||||
const QString CardInfo::getCardType() const
|
||||
{
|
||||
return getProperty(Mtg::CardType);
|
||||
}
|
||||
void CardInfo::setCardType(const QString &value)
|
||||
{
|
||||
setProperty(Mtg::CardType, value);
|
||||
}
|
||||
const QString CardInfo::getCmc() const
|
||||
{
|
||||
return getProperty(Mtg::ConvertedManaCost);
|
||||
}
|
||||
const QString CardInfo::getColors() const
|
||||
{
|
||||
return getProperty(Mtg::Colors);
|
||||
}
|
||||
void CardInfo::setColors(const QString &value)
|
||||
{
|
||||
setProperty(Mtg::Colors, value);
|
||||
}
|
||||
const QString CardInfo::getLoyalty() const
|
||||
{
|
||||
return getProperty(Mtg::Loyalty);
|
||||
}
|
||||
const QString CardInfo::getMainCardType() const
|
||||
{
|
||||
return getProperty(Mtg::MainCardType);
|
||||
}
|
||||
const QString CardInfo::getManaCost() const
|
||||
{
|
||||
return getProperty(Mtg::ManaCost);
|
||||
}
|
||||
const QString CardInfo::getPowTough() const
|
||||
{
|
||||
return getProperty(Mtg::PowTough);
|
||||
}
|
||||
void CardInfo::setPowTough(const QString &value)
|
||||
{
|
||||
setProperty(Mtg::PowTough, value);
|
||||
}
|
||||
|
|
@ -9,10 +9,13 @@
|
|||
#include <QMetaType>
|
||||
#include <QSharedPointer>
|
||||
#include <QStringList>
|
||||
#include <QVariant>
|
||||
#include <QVector>
|
||||
#include <utility>
|
||||
|
||||
class CardDatabase;
|
||||
class CardInfo;
|
||||
class CardInfoPerSet;
|
||||
class CardSet;
|
||||
class CardRelation;
|
||||
class ICardDatabaseParser;
|
||||
|
|
@ -21,6 +24,7 @@ typedef QMap<QString, QString> QStringMap;
|
|||
typedef QMap<QString, int> MuidMap;
|
||||
typedef QSharedPointer<CardInfo> CardInfoPtr;
|
||||
typedef QSharedPointer<CardSet> CardSetPtr;
|
||||
typedef QMap<QString, CardInfoPerSet> CardInfoPerSetMap;
|
||||
|
||||
Q_DECLARE_METATYPE(CardInfoPtr)
|
||||
|
||||
|
|
@ -112,175 +116,162 @@ public:
|
|||
QStringList getUnknownSetsNames();
|
||||
};
|
||||
|
||||
class CardInfoPerSet
|
||||
{
|
||||
public:
|
||||
explicit CardInfoPerSet(const CardSetPtr &_set = QSharedPointer<CardSet>(nullptr));
|
||||
~CardInfoPerSet() = default;
|
||||
|
||||
private:
|
||||
CardSetPtr set;
|
||||
// per-set card properties;
|
||||
QVariantHash properties;
|
||||
|
||||
public:
|
||||
const CardSetPtr getPtr() const
|
||||
{
|
||||
return set;
|
||||
}
|
||||
const QStringList getProperties() const
|
||||
{
|
||||
return properties.keys();
|
||||
}
|
||||
const QString getProperty(const QString &propertyName) const
|
||||
{
|
||||
return properties.value(propertyName).toString();
|
||||
}
|
||||
void setProperty(const QString &_name, const QString &_value)
|
||||
{
|
||||
properties.insert(_name, _value);
|
||||
}
|
||||
};
|
||||
|
||||
class CardInfo : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
private:
|
||||
CardInfoPtr smartThis;
|
||||
// The card name
|
||||
QString name;
|
||||
|
||||
/*
|
||||
* The name without punctuation or capitalization, for better card tag name
|
||||
* recognition.
|
||||
*/
|
||||
// The name without punctuation or capitalization, for better card name recognition.
|
||||
QString simpleName;
|
||||
|
||||
bool isToken;
|
||||
SetList sets;
|
||||
QString manacost;
|
||||
QString cmc;
|
||||
QString cardtype;
|
||||
QString powtough;
|
||||
// The key used to identify this card in the cache
|
||||
QString pixmapCacheKey;
|
||||
// card text
|
||||
QString text;
|
||||
QStringList colors;
|
||||
|
||||
// whether this is not a "real" card but a token
|
||||
bool isToken;
|
||||
// basic card properties; common for all the sets
|
||||
QVariantHash properties;
|
||||
// the cards i'm related to
|
||||
QList<CardRelation *> relatedCards;
|
||||
|
||||
// the card i'm reverse-related to
|
||||
QList<CardRelation *> reverseRelatedCards;
|
||||
|
||||
// the cards thare are reverse-related to me
|
||||
QList<CardRelation *> reverseRelatedCardsToMe;
|
||||
|
||||
// card sets
|
||||
CardInfoPerSetMap sets;
|
||||
// cached set names
|
||||
QString setsNames;
|
||||
|
||||
bool upsideDownArt;
|
||||
QString loyalty;
|
||||
QStringMap customPicURLs;
|
||||
MuidMap muIds;
|
||||
QStringMap collectorNumbers;
|
||||
QStringMap rarities;
|
||||
// positioning properties; used by UI
|
||||
bool cipt;
|
||||
int tableRow;
|
||||
QString pixmapCacheKey;
|
||||
bool upsideDownArt;
|
||||
|
||||
public:
|
||||
explicit CardInfo(const QString &_name = QString(),
|
||||
bool _isToken = false,
|
||||
const QString &_manacost = QString(),
|
||||
const QString &_cmc = QString(),
|
||||
const QString &_cardtype = QString(),
|
||||
const QString &_powtough = QString(),
|
||||
const QString &_text = QString(),
|
||||
const QStringList &_colors = QStringList(),
|
||||
bool _isToken = false,
|
||||
QVariantHash _properties = QVariantHash(),
|
||||
const QList<CardRelation *> &_relatedCards = QList<CardRelation *>(),
|
||||
const QList<CardRelation *> &_reverseRelatedCards = QList<CardRelation *>(),
|
||||
bool _upsideDownArt = false,
|
||||
const QString &_loyalty = QString(),
|
||||
CardInfoPerSetMap _sets = CardInfoPerSetMap(),
|
||||
bool _cipt = false,
|
||||
int _tableRow = 0,
|
||||
const SetList &_sets = SetList(),
|
||||
const QStringMap &_customPicURLs = QStringMap(),
|
||||
MuidMap muids = MuidMap(),
|
||||
QStringMap _collectorNumbers = QStringMap(),
|
||||
QStringMap _rarities = QStringMap());
|
||||
bool _upsideDownArt = false);
|
||||
~CardInfo() override;
|
||||
|
||||
static CardInfoPtr newInstance(const QString &_name = QString(),
|
||||
bool _isToken = false,
|
||||
const QString &_manacost = QString(),
|
||||
const QString &_cmc = QString(),
|
||||
const QString &_cardtype = QString(),
|
||||
const QString &_powtough = QString(),
|
||||
const QString &_text = QString(),
|
||||
const QStringList &_colors = QStringList(),
|
||||
bool _isToken = false,
|
||||
QVariantHash _properties = QVariantHash(),
|
||||
const QList<CardRelation *> &_relatedCards = QList<CardRelation *>(),
|
||||
const QList<CardRelation *> &_reverseRelatedCards = QList<CardRelation *>(),
|
||||
bool _upsideDownArt = false,
|
||||
const QString &_loyalty = QString(),
|
||||
CardInfoPerSetMap _sets = CardInfoPerSetMap(),
|
||||
bool _cipt = false,
|
||||
int _tableRow = 0,
|
||||
const SetList &_sets = SetList(),
|
||||
const QStringMap &_customPicURLs = QStringMap(),
|
||||
MuidMap muids = MuidMap(),
|
||||
QStringMap _collectorNumbers = QStringMap(),
|
||||
QStringMap _rarities = QStringMap());
|
||||
bool _upsideDownArt = false);
|
||||
|
||||
void setSmartPointer(CardInfoPtr _ptr)
|
||||
{
|
||||
smartThis = _ptr;
|
||||
smartThis = std::move(_ptr);
|
||||
}
|
||||
|
||||
// basic properties
|
||||
inline const QString &getName() const
|
||||
{
|
||||
return name;
|
||||
}
|
||||
inline const QString &getSetsNames() const
|
||||
{
|
||||
return setsNames;
|
||||
}
|
||||
const QString &getSimpleName() const
|
||||
{
|
||||
return simpleName;
|
||||
}
|
||||
bool getIsToken() const
|
||||
{
|
||||
return isToken;
|
||||
}
|
||||
const SetList &getSets() const
|
||||
{
|
||||
return sets;
|
||||
}
|
||||
inline const QString &getManaCost() const
|
||||
{
|
||||
return manacost;
|
||||
}
|
||||
inline const QString &getCmc() const
|
||||
{
|
||||
return cmc;
|
||||
}
|
||||
inline const QString &getCardType() const
|
||||
{
|
||||
return cardtype;
|
||||
}
|
||||
inline const QString &getPowTough() const
|
||||
{
|
||||
return powtough;
|
||||
}
|
||||
const QString &getText() const
|
||||
{
|
||||
return text;
|
||||
}
|
||||
const QString &getPixmapCacheKey() const
|
||||
{
|
||||
return pixmapCacheKey;
|
||||
}
|
||||
const QString &getLoyalty() const
|
||||
|
||||
const QString &getText() const
|
||||
{
|
||||
return loyalty;
|
||||
}
|
||||
bool getCipt() const
|
||||
{
|
||||
return cipt;
|
||||
}
|
||||
// void setManaCost(const QString &_manaCost) { manacost = _manaCost; emit cardInfoChanged(smartThis); }
|
||||
// void setCmc(const QString &_cmc) { cmc = _cmc; emit cardInfoChanged(smartThis); }
|
||||
void setCardType(const QString &_cardType)
|
||||
{
|
||||
cardtype = _cardType;
|
||||
emit cardInfoChanged(smartThis);
|
||||
}
|
||||
void setPowTough(const QString &_powTough)
|
||||
{
|
||||
powtough = _powTough;
|
||||
emit cardInfoChanged(smartThis);
|
||||
return text;
|
||||
}
|
||||
void setText(const QString &_text)
|
||||
{
|
||||
text = _text;
|
||||
emit cardInfoChanged(smartThis);
|
||||
}
|
||||
void setColors(const QStringList &_colors)
|
||||
|
||||
bool getIsToken() const
|
||||
{
|
||||
colors = _colors;
|
||||
return isToken;
|
||||
}
|
||||
const QStringList getProperties() const
|
||||
{
|
||||
return properties.keys();
|
||||
}
|
||||
const QString getProperty(const QString &propertyName) const
|
||||
{
|
||||
return properties.value(propertyName).toString();
|
||||
}
|
||||
void setProperty(const QString &_name, const QString &_value)
|
||||
{
|
||||
properties.insert(_name, _value);
|
||||
emit cardInfoChanged(smartThis);
|
||||
}
|
||||
const QChar getColorChar() const;
|
||||
const QStringList &getColors() const
|
||||
const CardInfoPerSetMap &getSets() const
|
||||
{
|
||||
return colors;
|
||||
return sets;
|
||||
}
|
||||
const QString &getSetsNames() const
|
||||
{
|
||||
return setsNames;
|
||||
}
|
||||
const QString getSetProperty(const QString &setName, const QString &propertyName) const
|
||||
{
|
||||
if (!sets.contains(setName))
|
||||
return "";
|
||||
return sets[setName].getProperty(propertyName);
|
||||
}
|
||||
void setSetProperty(const QString &setName, const QString &_name, const QString &_value)
|
||||
{
|
||||
if (!sets.contains(setName))
|
||||
return;
|
||||
|
||||
sets[setName].setProperty(_name, _value);
|
||||
emit cardInfoChanged(smartThis);
|
||||
}
|
||||
|
||||
// related cards
|
||||
const QList<CardRelation *> &getRelatedCards() const
|
||||
{
|
||||
return relatedCards;
|
||||
|
|
@ -298,32 +289,12 @@ public:
|
|||
{
|
||||
reverseRelatedCardsToMe.append(cardRelation);
|
||||
}
|
||||
bool getUpsideDownArt() const
|
||||
|
||||
// positioning
|
||||
bool getCipt() const
|
||||
{
|
||||
return upsideDownArt;
|
||||
return cipt;
|
||||
}
|
||||
QString getCustomPicURL(const QString &set) const
|
||||
{
|
||||
return customPicURLs.value(set);
|
||||
}
|
||||
int getMuId(const QString &set) const
|
||||
{
|
||||
return muIds.value(set);
|
||||
}
|
||||
QString getCollectorNumber(const QString &set) const
|
||||
{
|
||||
return collectorNumbers.value(set);
|
||||
}
|
||||
QString getRarity(const QString &set) const
|
||||
{
|
||||
return rarities.value(set);
|
||||
}
|
||||
QStringMap getRarities() const
|
||||
{
|
||||
return rarities;
|
||||
}
|
||||
QString getMainCardType() const;
|
||||
QString getCorrectedName() const;
|
||||
int getTableRow() const
|
||||
{
|
||||
return tableRow;
|
||||
|
|
@ -332,27 +303,31 @@ public:
|
|||
{
|
||||
tableRow = _tableRow;
|
||||
}
|
||||
// void setLoyalty(int _loyalty) { loyalty = _loyalty; emit cardInfoChanged(smartThis); }
|
||||
// void setCustomPicURL(const QString &_set, const QString &_customPicURL) { customPicURLs.insert(_set,
|
||||
// _customPicURL); }
|
||||
void setSet(const CardSetPtr &_set)
|
||||
bool getUpsideDownArt() const
|
||||
{
|
||||
sets.append(_set);
|
||||
refreshCachedSetNames();
|
||||
return upsideDownArt;
|
||||
}
|
||||
void setMuId(const QString &_set, const int &_muId)
|
||||
const QChar getColorChar() const;
|
||||
|
||||
// Back-compatibility methods. Remove ASAP
|
||||
const QString getCardType() const;
|
||||
void setCardType(const QString &value);
|
||||
const QString getCmc() const;
|
||||
const QString getColors() const;
|
||||
void setColors(const QString &value);
|
||||
const QString getLoyalty() const;
|
||||
const QString getMainCardType() const;
|
||||
const QString getManaCost() const;
|
||||
const QString getPowTough() const;
|
||||
void setPowTough(const QString &value);
|
||||
|
||||
// methods using per-set properties
|
||||
QString getCustomPicURL(const QString &set) const
|
||||
{
|
||||
muIds.insert(_set, _muId);
|
||||
return getSetProperty(set, "picurl");
|
||||
}
|
||||
void setSetNumber(const QString &_set, const QString &_setNumber)
|
||||
{
|
||||
collectorNumbers.insert(_set, _setNumber);
|
||||
}
|
||||
void setRarity(const QString &_set, const QString &_setNumber)
|
||||
{
|
||||
rarities.insert(_set, _setNumber);
|
||||
}
|
||||
void addToSet(CardSetPtr set);
|
||||
QString getCorrectedName() const;
|
||||
void addToSet(const CardSetPtr &_set, CardInfoPerSet _info = CardInfoPerSet());
|
||||
void emitPixmapUpdated()
|
||||
{
|
||||
emit pixmapUpdated();
|
||||
|
|
@ -439,7 +414,6 @@ public:
|
|||
SetList getSetList() const;
|
||||
LoadStatus loadFromFile(const QString &fileName);
|
||||
bool saveCustomTokensToFile();
|
||||
QStringList getAllColors() const;
|
||||
QStringList getAllMainCardTypes() const;
|
||||
LoadStatus getLoadStatus() const
|
||||
{
|
||||
|
|
@ -506,4 +480,4 @@ public:
|
|||
return defaultCount;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -14,9 +14,7 @@ CardDatabaseModel::CardDatabaseModel(CardDatabase *_db, bool _showOnlyCardsFromE
|
|||
cardDatabaseEnabledSetsChanged();
|
||||
}
|
||||
|
||||
CardDatabaseModel::~CardDatabaseModel()
|
||||
{
|
||||
}
|
||||
CardDatabaseModel::~CardDatabaseModel() = default;
|
||||
|
||||
QMap<wchar_t, wchar_t> CardDatabaseDisplayModel::characterTranslation = {{L'“', L'\"'},
|
||||
{L'”', L'\"'},
|
||||
|
|
@ -53,7 +51,7 @@ QVariant CardDatabaseModel::data(const QModelIndex &index, int role) const
|
|||
case PTColumn:
|
||||
return card->getPowTough();
|
||||
case ColorColumn:
|
||||
return card->getColors().join("");
|
||||
return card->getColors();
|
||||
default:
|
||||
return QVariant();
|
||||
}
|
||||
|
|
@ -97,8 +95,8 @@ bool CardDatabaseModel::checkCardHasAtLeastOneEnabledSet(CardInfoPtr card)
|
|||
if (!showOnlyCardsFromEnabledSets)
|
||||
return true;
|
||||
|
||||
for (CardSetPtr set : card->getSets()) {
|
||||
if (set->getEnabled())
|
||||
for (const auto &set : card->getSets()) {
|
||||
if (set.getPtr()->getEnabled())
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -26,12 +26,12 @@ public:
|
|||
{
|
||||
SortRole = Qt::UserRole
|
||||
};
|
||||
CardDatabaseModel(CardDatabase *_db, bool _showOnlyCardsFromEnabledSets, QObject *parent = 0);
|
||||
~CardDatabaseModel();
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
CardDatabaseModel(CardDatabase *_db, bool _showOnlyCardsFromEnabledSets, QObject *parent = nullptr);
|
||||
~CardDatabaseModel() override;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
|
||||
CardDatabase *getDatabase() const
|
||||
{
|
||||
return db;
|
||||
|
|
@ -77,7 +77,7 @@ private:
|
|||
static QMap<wchar_t, wchar_t> characterTranslation;
|
||||
|
||||
public:
|
||||
CardDatabaseDisplayModel(QObject *parent = 0);
|
||||
explicit CardDatabaseDisplayModel(QObject *parent = nullptr);
|
||||
void setFilterTree(FilterTree *filterTree);
|
||||
void setIsToken(FilterBool _isToken)
|
||||
{
|
||||
|
|
@ -119,15 +119,15 @@ public:
|
|||
invalidate();
|
||||
}
|
||||
void clearFilterAll();
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
protected:
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const;
|
||||
bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
|
||||
static int lessThanNumerically(const QString &left, const QString &right);
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
bool rowMatchesCardName(CardInfoPtr info) const;
|
||||
bool canFetchMore(const QModelIndex &parent) const;
|
||||
void fetchMore(const QModelIndex &parent);
|
||||
bool canFetchMore(const QModelIndex &parent) const override;
|
||||
void fetchMore(const QModelIndex &parent) override;
|
||||
private slots:
|
||||
void filterTreeChanged();
|
||||
/** Will translate all undesirable characters in DIRTYNAME according to the TABLE. */
|
||||
|
|
@ -138,11 +138,11 @@ class TokenDisplayModel : public CardDatabaseDisplayModel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TokenDisplayModel(QObject *parent = 0);
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const;
|
||||
explicit TokenDisplayModel(QObject *parent = nullptr);
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
|
||||
|
||||
protected:
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const;
|
||||
bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
27
cockatrice/src/carddbparser/carddatabaseparser.cpp
Normal file
27
cockatrice/src/carddbparser/carddatabaseparser.cpp
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
#include "carddatabaseparser.h"
|
||||
|
||||
SetNameMap ICardDatabaseParser::sets;
|
||||
|
||||
void ICardDatabaseParser::clearSetlist()
|
||||
{
|
||||
sets.clear();
|
||||
}
|
||||
|
||||
CardSetPtr ICardDatabaseParser::internalAddSet(const QString &setName,
|
||||
const QString &longName,
|
||||
const QString &setType,
|
||||
const QDate &releaseDate)
|
||||
{
|
||||
if (sets.contains(setName)) {
|
||||
return sets.value(setName);
|
||||
}
|
||||
|
||||
CardSetPtr newSet = CardSet::newInstance(setName);
|
||||
newSet->setLongName(longName);
|
||||
newSet->setSetType(setType);
|
||||
newSet->setReleaseDate(releaseDate);
|
||||
|
||||
sets.insert(setName, newSet);
|
||||
emit addSet(newSet);
|
||||
return newSet;
|
||||
}
|
||||
|
|
@ -9,15 +9,27 @@
|
|||
class ICardDatabaseParser : public QObject
|
||||
{
|
||||
public:
|
||||
virtual ~ICardDatabaseParser()
|
||||
{
|
||||
}
|
||||
~ICardDatabaseParser() override = default;
|
||||
|
||||
virtual bool getCanParseFile(const QString &name, QIODevice &device) = 0;
|
||||
virtual void parseFile(QIODevice &device) = 0;
|
||||
virtual bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) = 0;
|
||||
virtual void clearSetlist() = 0;
|
||||
static void clearSetlist();
|
||||
|
||||
protected:
|
||||
/*
|
||||
* A cached list of the available sets, needed to cross-reference sets from cards.
|
||||
* Shared between all parsers
|
||||
*/
|
||||
static SetNameMap sets;
|
||||
|
||||
CardSetPtr internalAddSet(const QString &setName,
|
||||
const QString &longName = "",
|
||||
const QString &setType = "",
|
||||
const QDate &releaseDate = QDate());
|
||||
signals:
|
||||
virtual void addCard(CardInfoPtr card) = 0;
|
||||
virtual void addSet(CardSetPtr set) = 0;
|
||||
};
|
||||
|
||||
Q_DECLARE_INTERFACE(ICardDatabaseParser, "ICardDatabaseParser")
|
||||
|
|
|
|||
|
|
@ -61,30 +61,6 @@ void CockatriceXml3Parser::parseFile(QIODevice &device)
|
|||
}
|
||||
}
|
||||
|
||||
CardSetPtr CockatriceXml3Parser::internalAddSet(const QString &setName,
|
||||
const QString &longName,
|
||||
const QString &setType,
|
||||
const QDate &releaseDate)
|
||||
{
|
||||
if (sets.contains(setName)) {
|
||||
return sets.value(setName);
|
||||
}
|
||||
|
||||
CardSetPtr newSet = CardSet::newInstance(setName);
|
||||
newSet->setLongName(longName);
|
||||
newSet->setSetType(setType);
|
||||
newSet->setReleaseDate(releaseDate);
|
||||
|
||||
sets.insert(setName, newSet);
|
||||
emit addSet(newSet);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
void CockatriceXml3Parser::clearSetlist()
|
||||
{
|
||||
sets.clear();
|
||||
}
|
||||
|
||||
void CockatriceXml3Parser::loadSetsFromXml(QXmlStreamReader &xml)
|
||||
{
|
||||
while (!xml.atEnd()) {
|
||||
|
|
@ -120,6 +96,44 @@ void CockatriceXml3Parser::loadSetsFromXml(QXmlStreamReader &xml)
|
|||
}
|
||||
}
|
||||
|
||||
QString CockatriceXml3Parser::getMainCardType(QString &type)
|
||||
{
|
||||
QString result = type;
|
||||
/*
|
||||
Legendary Artifact Creature - Golem
|
||||
Instant // Instant
|
||||
*/
|
||||
|
||||
int pos;
|
||||
if ((pos = result.indexOf('-')) != -1) {
|
||||
result.remove(pos, result.length());
|
||||
}
|
||||
|
||||
if ((pos = result.indexOf("—")) != -1) {
|
||||
result.remove(pos, result.length());
|
||||
}
|
||||
|
||||
if ((pos = result.indexOf("//")) != -1) {
|
||||
result.remove(pos, result.length());
|
||||
}
|
||||
|
||||
result = result.simplified();
|
||||
/*
|
||||
Legendary Artifact Creature
|
||||
Instant
|
||||
*/
|
||||
|
||||
if ((pos = result.lastIndexOf(' ')) != -1) {
|
||||
result = result.mid(pos + 1);
|
||||
}
|
||||
/*
|
||||
Creature
|
||||
Instant
|
||||
*/
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
||||
{
|
||||
while (!xml.atEnd()) {
|
||||
|
|
@ -128,55 +142,77 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
|||
}
|
||||
|
||||
if (xml.name() == "card") {
|
||||
QString name, manacost, cmc, type, pt, text, loyalty;
|
||||
QStringList colors;
|
||||
QString name = QString("");
|
||||
QString text = QString("");
|
||||
QVariantHash properties = QVariantHash();
|
||||
QString colors = QString("");
|
||||
QList<CardRelation *> relatedCards, reverseRelatedCards;
|
||||
QStringMap customPicURLs;
|
||||
MuidMap muids;
|
||||
QStringMap collectorNumbers, rarities;
|
||||
SetList sets;
|
||||
CardInfoPerSetMap sets = CardInfoPerSetMap();
|
||||
int tableRow = 0;
|
||||
bool cipt = false;
|
||||
bool isToken = false;
|
||||
bool upsideDown = false;
|
||||
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
||||
break;
|
||||
}
|
||||
|
||||
// variable - assigned properties
|
||||
if (xml.name() == "name") {
|
||||
name = xml.readElementText();
|
||||
} else if (xml.name() == "manacost") {
|
||||
manacost = xml.readElementText();
|
||||
} else if (xml.name() == "cmc") {
|
||||
cmc = xml.readElementText();
|
||||
} else if (xml.name() == "type") {
|
||||
type = xml.readElementText();
|
||||
} else if (xml.name() == "pt") {
|
||||
pt = xml.readElementText();
|
||||
} else if (xml.name() == "text") {
|
||||
text = xml.readElementText();
|
||||
} else if (xml.name() == "color") {
|
||||
colors.append(xml.readElementText());
|
||||
} else if (xml.name() == "token") {
|
||||
isToken = static_cast<bool>(xml.readElementText().toInt());
|
||||
// generic properties
|
||||
} else if (xml.name() == "manacost") {
|
||||
properties.insert("manacost", xml.readElementText());
|
||||
} else if (xml.name() == "cmc") {
|
||||
properties.insert("cmc", xml.readElementText());
|
||||
} else if (xml.name() == "type") {
|
||||
QString type = xml.readElementText();
|
||||
properties.insert("type", type);
|
||||
properties.insert("maintype", getMainCardType(type));
|
||||
} else if (xml.name() == "pt") {
|
||||
properties.insert("pt", xml.readElementText());
|
||||
} else if (xml.name() == "loyalty") {
|
||||
properties.insert("loyalty", xml.readElementText());
|
||||
// positioning info
|
||||
} else if (xml.name() == "tablerow") {
|
||||
tableRow = xml.readElementText().toInt();
|
||||
} else if (xml.name() == "cipt") {
|
||||
cipt = (xml.readElementText() == "1");
|
||||
} else if (xml.name() == "upsidedown") {
|
||||
upsideDown = (xml.readElementText() == "1");
|
||||
// sets
|
||||
} else if (xml.name() == "set") {
|
||||
// NOTE: attributes must be read before readElementText()
|
||||
QXmlStreamAttributes attrs = xml.attributes();
|
||||
QString setName = xml.readElementText();
|
||||
sets.append(internalAddSet(setName));
|
||||
CardInfoPerSet setInfo(internalAddSet(setName));
|
||||
if (attrs.hasAttribute("muId")) {
|
||||
muids[setName] = attrs.value("muId").toString().toInt();
|
||||
setInfo.setProperty("muid", attrs.value("muId").toString());
|
||||
}
|
||||
|
||||
if (attrs.hasAttribute("muId")) {
|
||||
setInfo.setProperty("uuid", attrs.value("uuId").toString());
|
||||
}
|
||||
|
||||
if (attrs.hasAttribute("picURL")) {
|
||||
customPicURLs[setName] = attrs.value("picURL").toString();
|
||||
setInfo.setProperty("picurl", attrs.value("picURL").toString());
|
||||
}
|
||||
|
||||
if (attrs.hasAttribute("num")) {
|
||||
collectorNumbers[setName] = attrs.value("num").toString();
|
||||
setInfo.setProperty("num", attrs.value("num").toString());
|
||||
}
|
||||
|
||||
if (attrs.hasAttribute("rarity")) {
|
||||
rarities[setName] = attrs.value("rarity").toString();
|
||||
setInfo.setProperty("rarity", attrs.value("rarity").toString());
|
||||
}
|
||||
} else if (xml.name() == "color") {
|
||||
colors << xml.readElementText();
|
||||
sets.insert(setName, setInfo);
|
||||
// relatd cards
|
||||
} else if (xml.name() == "related" || xml.name() == "reverse-related") {
|
||||
bool attach = false;
|
||||
bool exclude = false;
|
||||
|
|
@ -213,16 +249,6 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
|||
} else {
|
||||
relatedCards << relation;
|
||||
}
|
||||
} else if (xml.name() == "tablerow") {
|
||||
tableRow = xml.readElementText().toInt();
|
||||
} else if (xml.name() == "cipt") {
|
||||
cipt = (xml.readElementText() == "1");
|
||||
} else if (xml.name() == "upsidedown") {
|
||||
upsideDown = (xml.readElementText() == "1");
|
||||
} else if (xml.name() == "loyalty") {
|
||||
loyalty = xml.readElementText();
|
||||
} else if (xml.name() == "token") {
|
||||
isToken = static_cast<bool>(xml.readElementText().toInt());
|
||||
} else if (xml.name() != "") {
|
||||
qDebug() << "[CockatriceXml3Parser] Unknown card property" << xml.name()
|
||||
<< ", trying to continue anyway";
|
||||
|
|
@ -230,9 +256,9 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
|||
}
|
||||
}
|
||||
|
||||
CardInfoPtr newCard = CardInfo::newInstance(
|
||||
name, isToken, manacost, cmc, type, pt, text, colors, relatedCards, reverseRelatedCards, upsideDown,
|
||||
loyalty, cipt, tableRow, sets, customPicURLs, muids, collectorNumbers, rarities);
|
||||
properties.insert("colors", colors);
|
||||
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards,
|
||||
reverseRelatedCards, sets, cipt, tableRow, upsideDown);
|
||||
emit addCard(newCard);
|
||||
}
|
||||
}
|
||||
|
|
@ -262,37 +288,60 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
|
|||
return xml;
|
||||
}
|
||||
|
||||
xml.writeStartElement("card");
|
||||
xml.writeTextElement("name", info->getName());
|
||||
|
||||
const SetList &sets = info->getSets();
|
||||
QString tmpString;
|
||||
QString tmpSet;
|
||||
for (int i = 0; i < sets.size(); i++) {
|
||||
|
||||
xml.writeStartElement("card");
|
||||
|
||||
// variable - assigned properties
|
||||
xml.writeTextElement("name", info->getName());
|
||||
xml.writeTextElement("text", info->getText());
|
||||
if (info->getIsToken()) {
|
||||
xml.writeTextElement("token", "1");
|
||||
}
|
||||
|
||||
// generic properties
|
||||
xml.writeTextElement("manacost", info->getProperty("manacost"));
|
||||
xml.writeTextElement("cmc", info->getProperty("cmc"));
|
||||
xml.writeTextElement("type", info->getProperty("type"));
|
||||
|
||||
int colorSize = info->getColors().size();
|
||||
for (int i = 0; i < colorSize; ++i) {
|
||||
xml.writeTextElement("color", info->getColors().at(i));
|
||||
}
|
||||
|
||||
tmpString = info->getProperty("pt");
|
||||
if (!tmpString.isEmpty()) {
|
||||
xml.writeTextElement("pt", tmpString);
|
||||
}
|
||||
|
||||
tmpString = info->getProperty("loyalty");
|
||||
if (!tmpString.isEmpty()) {
|
||||
xml.writeTextElement("loyalty", tmpString);
|
||||
}
|
||||
|
||||
// sets
|
||||
const CardInfoPerSetMap sets = info->getSets();
|
||||
for (CardInfoPerSet set : sets) {
|
||||
xml.writeStartElement("set");
|
||||
xml.writeAttribute("rarity", set.getProperty("rarity"));
|
||||
xml.writeAttribute("muId", set.getProperty("muid"));
|
||||
xml.writeAttribute("uuId", set.getProperty("uuid"));
|
||||
|
||||
tmpSet = sets[i]->getShortName();
|
||||
xml.writeAttribute("rarity", info->getRarity(tmpSet));
|
||||
xml.writeAttribute("muId", QString::number(info->getMuId(tmpSet)));
|
||||
|
||||
tmpString = info->getCollectorNumber(tmpSet);
|
||||
tmpString = set.getProperty("num");
|
||||
if (!tmpString.isEmpty()) {
|
||||
xml.writeAttribute("num", info->getCollectorNumber(tmpSet));
|
||||
xml.writeAttribute("num", tmpString);
|
||||
}
|
||||
|
||||
tmpString = info->getCustomPicURL(tmpSet);
|
||||
tmpString = set.getProperty("picurl");
|
||||
if (!tmpString.isEmpty()) {
|
||||
xml.writeAttribute("picURL", tmpString);
|
||||
}
|
||||
|
||||
xml.writeCharacters(tmpSet);
|
||||
xml.writeCharacters(set.getPtr()->getShortName());
|
||||
xml.writeEndElement();
|
||||
}
|
||||
const QStringList &colors = info->getColors();
|
||||
for (int i = 0; i < colors.size(); i++) {
|
||||
xml.writeTextElement("color", colors[i]);
|
||||
}
|
||||
|
||||
// related cards
|
||||
const QList<CardRelation *> related = info->getRelatedCards();
|
||||
for (auto i : related) {
|
||||
xml.writeStartElement("related");
|
||||
|
|
@ -338,23 +387,12 @@ static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &in
|
|||
xml.writeCharacters(i->getName());
|
||||
xml.writeEndElement();
|
||||
}
|
||||
xml.writeTextElement("manacost", info->getManaCost());
|
||||
xml.writeTextElement("cmc", info->getCmc());
|
||||
xml.writeTextElement("type", info->getCardType());
|
||||
if (!info->getPowTough().isEmpty()) {
|
||||
xml.writeTextElement("pt", info->getPowTough());
|
||||
}
|
||||
|
||||
// positioning
|
||||
xml.writeTextElement("tablerow", QString::number(info->getTableRow()));
|
||||
xml.writeTextElement("text", info->getText());
|
||||
if (info->getMainCardType() == "Planeswalker") {
|
||||
xml.writeTextElement("loyalty", info->getLoyalty());
|
||||
}
|
||||
if (info->getCipt()) {
|
||||
xml.writeTextElement("cipt", "1");
|
||||
}
|
||||
if (info->getIsToken()) {
|
||||
xml.writeTextElement("token", "1");
|
||||
}
|
||||
if (info->getUpsideDownArt()) {
|
||||
xml.writeTextElement("upsidedown", "1");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,27 +11,18 @@ class CockatriceXml3Parser : public ICardDatabaseParser
|
|||
Q_INTERFACES(ICardDatabaseParser)
|
||||
public:
|
||||
CockatriceXml3Parser() = default;
|
||||
~CockatriceXml3Parser() = default;
|
||||
bool getCanParseFile(const QString &name, QIODevice &device);
|
||||
void parseFile(QIODevice &device);
|
||||
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName);
|
||||
void clearSetlist();
|
||||
~CockatriceXml3Parser() override = default;
|
||||
bool getCanParseFile(const QString &name, QIODevice &device) override;
|
||||
void parseFile(QIODevice &device) override;
|
||||
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) override;
|
||||
|
||||
private:
|
||||
/*
|
||||
* A cached list of the available sets, needed to cross-reference sets from cards.
|
||||
*/
|
||||
SetNameMap sets;
|
||||
|
||||
CardSetPtr internalAddSet(const QString &setName,
|
||||
const QString &longName = "",
|
||||
const QString &setType = "",
|
||||
const QDate &releaseDate = QDate());
|
||||
void loadCardsFromXml(QXmlStreamReader &xml);
|
||||
void loadSetsFromXml(QXmlStreamReader &xml);
|
||||
QString getMainCardType(QString &type);
|
||||
signals:
|
||||
void addCard(CardInfoPtr card);
|
||||
void addSet(CardSetPtr set);
|
||||
void addCard(CardInfoPtr card) override;
|
||||
void addSet(CardSetPtr set) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
362
cockatrice/src/carddbparser/cockatricexml4.cpp
Normal file
362
cockatrice/src/carddbparser/cockatricexml4.cpp
Normal file
|
|
@ -0,0 +1,362 @@
|
|||
#include "cockatricexml4.h"
|
||||
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#define COCKATRICE_XML4_TAGNAME "cockatrice_carddatabase"
|
||||
#define COCKATRICE_XML4_TAGVER 4
|
||||
|
||||
bool CockatriceXml4Parser::getCanParseFile(const QString &fileName, QIODevice &device)
|
||||
{
|
||||
qDebug() << "[CockatriceXml4Parser] Trying to parse: " << fileName;
|
||||
|
||||
if (!fileName.endsWith(".xml", Qt::CaseInsensitive)) {
|
||||
qDebug() << "[CockatriceXml4Parser] Parsing failed: wrong extension";
|
||||
return false;
|
||||
}
|
||||
|
||||
QXmlStreamReader xml(&device);
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::StartElement) {
|
||||
if (xml.name() == COCKATRICE_XML4_TAGNAME) {
|
||||
int version = xml.attributes().value("version").toString().toInt();
|
||||
if (version == COCKATRICE_XML4_TAGVER) {
|
||||
return true;
|
||||
} else {
|
||||
qDebug() << "[CockatriceXml4Parser] Parsing failed: wrong version" << version;
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
qDebug() << "[CockatriceXml4Parser] Parsing failed: wrong element tag" << xml.name();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CockatriceXml4Parser::parseFile(QIODevice &device)
|
||||
{
|
||||
QXmlStreamReader xml(&device);
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::StartElement) {
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (xml.name() == "sets") {
|
||||
loadSetsFromXml(xml);
|
||||
} else if (xml.name() == "cards") {
|
||||
loadCardsFromXml(xml);
|
||||
} else if (xml.name() != "") {
|
||||
qDebug() << "[CockatriceXml4Parser] Unknown item" << xml.name() << ", trying to continue anyway";
|
||||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CockatriceXml4Parser::loadSetsFromXml(QXmlStreamReader &xml)
|
||||
{
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (xml.name() == "set") {
|
||||
QString shortName, longName, setType;
|
||||
QDate releaseDate;
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (xml.name() == "name") {
|
||||
shortName = xml.readElementText();
|
||||
} else if (xml.name() == "longname") {
|
||||
longName = xml.readElementText();
|
||||
} else if (xml.name() == "settype") {
|
||||
setType = xml.readElementText();
|
||||
} else if (xml.name() == "releasedate") {
|
||||
releaseDate = QDate::fromString(xml.readElementText(), Qt::ISODate);
|
||||
} else if (xml.name() != "") {
|
||||
qDebug() << "[CockatriceXml4Parser] Unknown set property" << xml.name()
|
||||
<< ", trying to continue anyway";
|
||||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
internalAddSet(shortName, longName, setType, releaseDate);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QVariantHash CockatriceXml4Parser::loadCardPropertiesFromXml(QXmlStreamReader &xml)
|
||||
{
|
||||
QVariantHash properties = QVariantHash();
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (xml.name() != "") {
|
||||
properties.insert(xml.name().toString(), xml.readElementText());
|
||||
}
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
|
||||
{
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (xml.name() == "card") {
|
||||
QString name = QString("");
|
||||
QString text = QString("");
|
||||
QVariantHash properties = QVariantHash();
|
||||
QList<CardRelation *> relatedCards, reverseRelatedCards;
|
||||
CardInfoPerSetMap sets = CardInfoPerSetMap();
|
||||
int tableRow = 0;
|
||||
bool cipt = false;
|
||||
bool isToken = false;
|
||||
bool upsideDown = false;
|
||||
|
||||
while (!xml.atEnd()) {
|
||||
if (xml.readNext() == QXmlStreamReader::EndElement) {
|
||||
break;
|
||||
}
|
||||
// variable - assigned properties
|
||||
if (xml.name() == "name") {
|
||||
name = xml.readElementText();
|
||||
} else if (xml.name() == "text") {
|
||||
text = xml.readElementText();
|
||||
} else if (xml.name() == "token") {
|
||||
isToken = static_cast<bool>(xml.readElementText().toInt());
|
||||
// generic properties
|
||||
} else if (xml.name() == "prop") {
|
||||
properties = loadCardPropertiesFromXml(xml);
|
||||
// positioning info
|
||||
} else if (xml.name() == "tablerow") {
|
||||
tableRow = xml.readElementText().toInt();
|
||||
} else if (xml.name() == "cipt") {
|
||||
cipt = (xml.readElementText() == "1");
|
||||
} else if (xml.name() == "upsidedown") {
|
||||
upsideDown = (xml.readElementText() == "1");
|
||||
// sets
|
||||
} else if (xml.name() == "set") {
|
||||
// NOTE: attributes but be read before readElementText()
|
||||
QXmlStreamAttributes attrs = xml.attributes();
|
||||
QString setName = xml.readElementText();
|
||||
CardInfoPerSet setInfo(internalAddSet(setName));
|
||||
for (QXmlStreamAttribute attr : attrs) {
|
||||
setInfo.setProperty(attr.name().toString(), attr.value().toString());
|
||||
}
|
||||
sets.insert(setName, setInfo);
|
||||
// relatd cards
|
||||
} else if (xml.name() == "related" || xml.name() == "reverse-related") {
|
||||
bool attach = false;
|
||||
bool exclude = false;
|
||||
bool variable = false;
|
||||
int count = 1;
|
||||
QXmlStreamAttributes attrs = xml.attributes();
|
||||
QString cardName = xml.readElementText();
|
||||
if (attrs.hasAttribute("count")) {
|
||||
if (attrs.value("count").toString().indexOf("x=") == 0) {
|
||||
variable = true;
|
||||
count = attrs.value("count").toString().remove(0, 2).toInt();
|
||||
} else if (attrs.value("count").toString().indexOf("x") == 0) {
|
||||
variable = true;
|
||||
} else {
|
||||
count = attrs.value("count").toString().toInt();
|
||||
}
|
||||
|
||||
if (count < 1) {
|
||||
count = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (attrs.hasAttribute("attach")) {
|
||||
attach = true;
|
||||
}
|
||||
|
||||
if (attrs.hasAttribute("exclude")) {
|
||||
exclude = true;
|
||||
}
|
||||
|
||||
auto *relation = new CardRelation(cardName, attach, exclude, variable, count);
|
||||
if (xml.name() == "reverse-related") {
|
||||
reverseRelatedCards << relation;
|
||||
} else {
|
||||
relatedCards << relation;
|
||||
}
|
||||
} else if (xml.name() != "") {
|
||||
qDebug() << "[CockatriceXml4Parser] Unknown card property" << xml.name()
|
||||
<< ", trying to continue anyway";
|
||||
xml.skipCurrentElement();
|
||||
}
|
||||
}
|
||||
|
||||
CardInfoPtr newCard = CardInfo::newInstance(name, text, isToken, properties, relatedCards,
|
||||
reverseRelatedCards, sets, cipt, tableRow, upsideDown);
|
||||
emit addCard(newCard);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardSetPtr &set)
|
||||
{
|
||||
if (set.isNull()) {
|
||||
qDebug() << "&operator<< set is nullptr";
|
||||
return xml;
|
||||
}
|
||||
|
||||
xml.writeStartElement("set");
|
||||
xml.writeTextElement("name", set->getShortName());
|
||||
xml.writeTextElement("longname", set->getLongName());
|
||||
xml.writeTextElement("settype", set->getSetType());
|
||||
xml.writeTextElement("releasedate", set->getReleaseDate().toString(Qt::ISODate));
|
||||
xml.writeEndElement();
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
static QXmlStreamWriter &operator<<(QXmlStreamWriter &xml, const CardInfoPtr &info)
|
||||
{
|
||||
if (info.isNull()) {
|
||||
qDebug() << "operator<< info is nullptr";
|
||||
return xml;
|
||||
}
|
||||
|
||||
QString tmpString;
|
||||
|
||||
xml.writeStartElement("card");
|
||||
|
||||
// variable - assigned properties
|
||||
xml.writeTextElement("name", info->getName());
|
||||
xml.writeTextElement("text", info->getText());
|
||||
if (info->getIsToken()) {
|
||||
xml.writeTextElement("token", "1");
|
||||
}
|
||||
|
||||
// generic properties
|
||||
xml.writeStartElement("prop");
|
||||
for (QString propName : info->getProperties()) {
|
||||
xml.writeTextElement(propName, info->getProperty(propName));
|
||||
}
|
||||
xml.writeEndElement();
|
||||
|
||||
// sets
|
||||
for (CardInfoPerSet set : info->getSets()) {
|
||||
xml.writeStartElement("set");
|
||||
for (QString propName : set.getProperties()) {
|
||||
xml.writeAttribute(propName, set.getProperty(propName));
|
||||
}
|
||||
|
||||
xml.writeCharacters(set.getPtr()->getShortName());
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
// related cards
|
||||
const QList<CardRelation *> related = info->getRelatedCards();
|
||||
for (auto i : related) {
|
||||
xml.writeStartElement("related");
|
||||
if (i->getDoesAttach()) {
|
||||
xml.writeAttribute("attach", "attach");
|
||||
}
|
||||
if (i->getIsCreateAllExclusion()) {
|
||||
xml.writeAttribute("exclude", "exclude");
|
||||
}
|
||||
|
||||
if (i->getIsVariable()) {
|
||||
if (1 == i->getDefaultCount()) {
|
||||
xml.writeAttribute("count", "x");
|
||||
} else {
|
||||
xml.writeAttribute("count", "x=" + QString::number(i->getDefaultCount()));
|
||||
}
|
||||
} else if (1 != i->getDefaultCount()) {
|
||||
xml.writeAttribute("count", QString::number(i->getDefaultCount()));
|
||||
}
|
||||
xml.writeCharacters(i->getName());
|
||||
xml.writeEndElement();
|
||||
}
|
||||
const QList<CardRelation *> reverseRelated = info->getReverseRelatedCards();
|
||||
for (auto i : reverseRelated) {
|
||||
xml.writeStartElement("reverse-related");
|
||||
if (i->getDoesAttach()) {
|
||||
xml.writeAttribute("attach", "attach");
|
||||
}
|
||||
|
||||
if (i->getIsCreateAllExclusion()) {
|
||||
xml.writeAttribute("exclude", "exclude");
|
||||
}
|
||||
|
||||
if (i->getIsVariable()) {
|
||||
if (1 == i->getDefaultCount()) {
|
||||
xml.writeAttribute("count", "x");
|
||||
} else {
|
||||
xml.writeAttribute("count", "x=" + QString::number(i->getDefaultCount()));
|
||||
}
|
||||
} else if (1 != i->getDefaultCount()) {
|
||||
xml.writeAttribute("count", QString::number(i->getDefaultCount()));
|
||||
}
|
||||
xml.writeCharacters(i->getName());
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
// positioning
|
||||
xml.writeTextElement("tablerow", QString::number(info->getTableRow()));
|
||||
if (info->getCipt()) {
|
||||
xml.writeTextElement("cipt", "1");
|
||||
}
|
||||
if (info->getUpsideDownArt()) {
|
||||
xml.writeTextElement("upsidedown", "1");
|
||||
}
|
||||
|
||||
xml.writeEndElement(); // card
|
||||
|
||||
return xml;
|
||||
}
|
||||
|
||||
bool CockatriceXml4Parser::saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName)
|
||||
{
|
||||
QFile file(fileName);
|
||||
if (!file.open(QIODevice::WriteOnly)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
QXmlStreamWriter xml(&file);
|
||||
|
||||
xml.setAutoFormatting(true);
|
||||
xml.writeStartDocument();
|
||||
xml.writeStartElement(COCKATRICE_XML4_TAGNAME);
|
||||
xml.writeAttribute("version", QString::number(COCKATRICE_XML4_TAGVER));
|
||||
|
||||
if (sets.count() > 0) {
|
||||
xml.writeStartElement("sets");
|
||||
for (CardSetPtr set : sets) {
|
||||
xml << set;
|
||||
}
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
if (cards.count() > 0) {
|
||||
xml.writeStartElement("cards");
|
||||
for (CardInfoPtr card : cards) {
|
||||
xml << card;
|
||||
}
|
||||
xml.writeEndElement();
|
||||
}
|
||||
|
||||
xml.writeEndElement(); // cockatrice_carddatabase
|
||||
xml.writeEndDocument();
|
||||
|
||||
return true;
|
||||
}
|
||||
28
cockatrice/src/carddbparser/cockatricexml4.h
Normal file
28
cockatrice/src/carddbparser/cockatricexml4.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef COCKATRICE_XML4_H
|
||||
#define COCKATRICE_XML4_H
|
||||
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include "carddatabaseparser.h"
|
||||
|
||||
class CockatriceXml4Parser : public ICardDatabaseParser
|
||||
{
|
||||
Q_OBJECT
|
||||
Q_INTERFACES(ICardDatabaseParser)
|
||||
public:
|
||||
CockatriceXml4Parser() = default;
|
||||
~CockatriceXml4Parser() override = default;
|
||||
bool getCanParseFile(const QString &name, QIODevice &device) override;
|
||||
void parseFile(QIODevice &device) override;
|
||||
bool saveToFile(SetNameMap sets, CardNameMap cards, const QString &fileName) override;
|
||||
|
||||
private:
|
||||
QVariantHash loadCardPropertiesFromXml(QXmlStreamReader &xml);
|
||||
void loadCardsFromXml(QXmlStreamReader &xml);
|
||||
void loadSetsFromXml(QXmlStreamReader &xml);
|
||||
signals:
|
||||
void addCard(CardInfoPtr card) override;
|
||||
void addSet(CardSetPtr set) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -1,47 +1,47 @@
|
|||
#include "cardfilter.h"
|
||||
|
||||
const char *CardFilter::typeName(Type t)
|
||||
const QString CardFilter::typeName(Type t)
|
||||
{
|
||||
switch (t) {
|
||||
case TypeAnd:
|
||||
return "AND";
|
||||
return tr("AND", "Logical conjunction operator used in card filter");
|
||||
case TypeOr:
|
||||
return "OR";
|
||||
return tr("OR", "Logical disjunction operator used in card filter");
|
||||
case TypeAndNot:
|
||||
return "AND NOT";
|
||||
return tr("AND NOT", "Negated logical conjunction operator used in card filter");
|
||||
case TypeOrNot:
|
||||
return "OR NOT";
|
||||
return tr("OR NOT", "Negated logical disjunction operator used in card filter");
|
||||
default:
|
||||
return "";
|
||||
return QString("");
|
||||
}
|
||||
}
|
||||
|
||||
const char *CardFilter::attrName(Attr a)
|
||||
const QString CardFilter::attrName(Attr a)
|
||||
{
|
||||
switch (a) {
|
||||
case AttrName:
|
||||
return "Name";
|
||||
return tr("Name");
|
||||
case AttrType:
|
||||
return "Type";
|
||||
return tr("Type");
|
||||
case AttrColor:
|
||||
return "Color";
|
||||
return tr("Color");
|
||||
case AttrText:
|
||||
return "Text";
|
||||
return tr("Text");
|
||||
case AttrSet:
|
||||
return "Set";
|
||||
return tr("Set");
|
||||
case AttrManaCost:
|
||||
return "Mana Cost";
|
||||
return tr("Mana Cost");
|
||||
case AttrCmc:
|
||||
return "CMC";
|
||||
return tr("CMC");
|
||||
case AttrRarity:
|
||||
return "Rarity";
|
||||
return tr("Rarity");
|
||||
case AttrPow:
|
||||
return "Power";
|
||||
return tr("Power");
|
||||
case AttrTough:
|
||||
return "Toughness";
|
||||
return tr("Toughness");
|
||||
case AttrLoyalty:
|
||||
return "Loyalty";
|
||||
return tr("Loyalty");
|
||||
default:
|
||||
return "";
|
||||
return QString("");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,13 @@
|
|||
#ifndef CARDFILTER_H
|
||||
#define CARDFILTER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QString>
|
||||
|
||||
class CardFilter
|
||||
class CardFilter : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
enum Type
|
||||
{
|
||||
|
|
@ -54,8 +57,8 @@ public:
|
|||
return a;
|
||||
}
|
||||
|
||||
static const char *typeName(Type t);
|
||||
static const char *attrName(Attr a);
|
||||
static const QString typeName(Type t);
|
||||
static const QString attrName(Attr a);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
#include <utility>
|
||||
|
||||
#include "cardframe.h"
|
||||
|
||||
#include "cardinfopicture.h"
|
||||
|
|
@ -16,6 +18,7 @@ CardFrame::CardFrame(const QString &cardName, QWidget *parent) : QTabWidget(pare
|
|||
pic->setObjectName("pic");
|
||||
text = new CardInfoText();
|
||||
text->setObjectName("text");
|
||||
connect(text, SIGNAL(linkActivated(const QString &)), this, SLOT(setCard(const QString &)));
|
||||
|
||||
tab1 = new QWidget(this);
|
||||
tab2 = new QWidget(this);
|
||||
|
|
@ -93,10 +96,10 @@ void CardFrame::setCard(CardInfoPtr card)
|
|||
disconnect(info.data(), nullptr, this, nullptr);
|
||||
}
|
||||
|
||||
info = card;
|
||||
info = std::move(card);
|
||||
|
||||
if (info) {
|
||||
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clear()));
|
||||
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clearCard()));
|
||||
}
|
||||
|
||||
text->setCard(info);
|
||||
|
|
@ -115,7 +118,7 @@ void CardFrame::setCard(AbstractCardItem *card)
|
|||
}
|
||||
}
|
||||
|
||||
void CardFrame::clear()
|
||||
void CardFrame::clearCard()
|
||||
{
|
||||
setCard((CardInfoPtr) nullptr);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ public slots:
|
|||
void setCard(CardInfoPtr card);
|
||||
void setCard(const QString &cardName);
|
||||
void setCard(AbstractCardItem *card);
|
||||
void clear();
|
||||
void clearCard();
|
||||
void setViewMode(int mode);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,137 +1,83 @@
|
|||
#include "cardinfotext.h"
|
||||
|
||||
#include "carditem.h"
|
||||
#include "game_specific_terms.h"
|
||||
#include "main.h"
|
||||
|
||||
#include <QGridLayout>
|
||||
#include <QLabel>
|
||||
#include <QTextEdit>
|
||||
|
||||
CardInfoText::CardInfoText(QWidget *parent) : QFrame(parent), info(nullptr)
|
||||
{
|
||||
nameLabel1 = new QLabel;
|
||||
nameLabel2 = new QLabel;
|
||||
nameLabel2->setWordWrap(true);
|
||||
nameLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
manacostLabel1 = new QLabel;
|
||||
manacostLabel2 = new QLabel;
|
||||
manacostLabel2->setWordWrap(true);
|
||||
manacostLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
colorLabel1 = new QLabel;
|
||||
colorLabel2 = new QLabel;
|
||||
colorLabel2->setWordWrap(true);
|
||||
colorLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
cardtypeLabel1 = new QLabel;
|
||||
cardtypeLabel2 = new QLabel;
|
||||
cardtypeLabel2->setWordWrap(true);
|
||||
cardtypeLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
powtoughLabel1 = new QLabel;
|
||||
powtoughLabel2 = new QLabel;
|
||||
powtoughLabel2->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
loyaltyLabel1 = new QLabel;
|
||||
loyaltyLabel2 = new QLabel;
|
||||
loyaltyLabel1->setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
nameLabel = new QLabel;
|
||||
nameLabel->setOpenExternalLinks(false);
|
||||
connect(nameLabel, SIGNAL(linkActivated(const QString &)), this, SIGNAL(linkActivated(const QString &)));
|
||||
|
||||
textLabel = new QTextEdit();
|
||||
textLabel->setReadOnly(true);
|
||||
|
||||
QGridLayout *grid = new QGridLayout(this);
|
||||
int row = 0;
|
||||
grid->addWidget(nameLabel1, row, 0);
|
||||
grid->addWidget(nameLabel2, row++, 1);
|
||||
grid->addWidget(manacostLabel1, row, 0);
|
||||
grid->addWidget(manacostLabel2, row++, 1);
|
||||
grid->addWidget(colorLabel1, row, 0);
|
||||
grid->addWidget(colorLabel2, row++, 1);
|
||||
grid->addWidget(cardtypeLabel1, row, 0);
|
||||
grid->addWidget(cardtypeLabel2, row++, 1);
|
||||
grid->addWidget(powtoughLabel1, row, 0);
|
||||
grid->addWidget(powtoughLabel2, row++, 1);
|
||||
grid->addWidget(loyaltyLabel1, row, 0);
|
||||
grid->addWidget(loyaltyLabel2, row++, 1);
|
||||
grid->addWidget(textLabel, row, 0, -1, 2);
|
||||
grid->setRowStretch(row, 1);
|
||||
grid->addWidget(nameLabel, 0, 0);
|
||||
grid->addWidget(textLabel, 1, 0, -1, 2);
|
||||
grid->setRowStretch(1, 1);
|
||||
grid->setColumnStretch(1, 1);
|
||||
|
||||
retranslateUi();
|
||||
}
|
||||
// Reset every label which is optionally hidden
|
||||
void CardInfoText::resetLabels()
|
||||
{
|
||||
nameLabel1->show();
|
||||
nameLabel2->show();
|
||||
manacostLabel1->show();
|
||||
manacostLabel2->show();
|
||||
colorLabel1->show();
|
||||
colorLabel2->show();
|
||||
cardtypeLabel1->show();
|
||||
cardtypeLabel2->show();
|
||||
powtoughLabel1->show();
|
||||
powtoughLabel2->show();
|
||||
loyaltyLabel1->show();
|
||||
loyaltyLabel2->show();
|
||||
textLabel->show();
|
||||
}
|
||||
|
||||
void CardInfoText::setCard(CardInfoPtr card)
|
||||
{
|
||||
if (card) {
|
||||
resetLabels();
|
||||
nameLabel2->setText(card->getName());
|
||||
if (!card->getManaCost().isEmpty()) {
|
||||
manacostLabel2->setText(card->getManaCost());
|
||||
} else {
|
||||
manacostLabel1->hide();
|
||||
manacostLabel2->hide();
|
||||
}
|
||||
if (!card->getColors().isEmpty()) {
|
||||
colorLabel2->setText(card->getColors().join(""));
|
||||
} else {
|
||||
colorLabel2->setText("Colorless");
|
||||
}
|
||||
cardtypeLabel2->setText(card->getCardType());
|
||||
if (!card->getPowTough().isEmpty()) {
|
||||
powtoughLabel2->setText(card->getPowTough());
|
||||
} else {
|
||||
powtoughLabel1->hide();
|
||||
powtoughLabel2->hide();
|
||||
}
|
||||
if (!card->getLoyalty().isEmpty()) {
|
||||
loyaltyLabel2->setText(card->getLoyalty());
|
||||
} else {
|
||||
loyaltyLabel1->hide();
|
||||
loyaltyLabel2->hide();
|
||||
}
|
||||
textLabel->setText(card->getText());
|
||||
} else {
|
||||
nameLabel1->hide();
|
||||
nameLabel2->hide();
|
||||
manacostLabel1->hide();
|
||||
manacostLabel2->hide();
|
||||
colorLabel1->hide();
|
||||
colorLabel2->hide();
|
||||
cardtypeLabel1->hide();
|
||||
cardtypeLabel2->hide();
|
||||
powtoughLabel1->hide();
|
||||
powtoughLabel2->hide();
|
||||
loyaltyLabel1->hide();
|
||||
loyaltyLabel2->hide();
|
||||
textLabel->hide();
|
||||
if (card == nullptr) {
|
||||
nameLabel->setText("");
|
||||
textLabel->setText("");
|
||||
return;
|
||||
}
|
||||
|
||||
QString text = "<table width=\"100%\" border=0 cellspacing=0 cellpadding=0>";
|
||||
text += QString("<tr><td>%1</td><td width=\"5\"></td><td>%2</td></tr>")
|
||||
.arg(tr("Name:"), card->getName().toHtmlEscaped());
|
||||
|
||||
QStringList cardProps = card->getProperties();
|
||||
foreach (QString key, cardProps) {
|
||||
QString keyText = Mtg::getNicePropertyName(key).toHtmlEscaped() + ":";
|
||||
text +=
|
||||
QString("<tr><td>%1</td><td></td><td>%2</td></tr>").arg(keyText, card->getProperty(key).toHtmlEscaped());
|
||||
}
|
||||
|
||||
auto relatedCards = card->getRelatedCards();
|
||||
auto reverserelatedCards2Me = card->getReverseRelatedCards2Me();
|
||||
if (relatedCards.size() || reverserelatedCards2Me.size()) {
|
||||
text += QString("<tr><td>%1</td><td width=\"5\"></td><td>").arg(tr("Related cards:"));
|
||||
|
||||
for (int i = 0; i < relatedCards.size(); ++i) {
|
||||
QString tmp = relatedCards.at(i)->getName().toHtmlEscaped();
|
||||
text += "<a href=\"" + tmp + "\">" + tmp + "</a><br>";
|
||||
}
|
||||
|
||||
for (int i = 0; i < reverserelatedCards2Me.size(); ++i) {
|
||||
QString tmp = reverserelatedCards2Me.at(i)->getName().toHtmlEscaped();
|
||||
text += "<a href=\"" + tmp + "\">" + tmp + "</a><br>";
|
||||
}
|
||||
|
||||
text += "</td></tr>";
|
||||
}
|
||||
|
||||
text += "</table>";
|
||||
nameLabel->setText(text);
|
||||
textLabel->setText(card->getText());
|
||||
}
|
||||
|
||||
void CardInfoText::setInvalidCardName(const QString &cardName)
|
||||
{
|
||||
nameLabel1->setText(tr("Unknown card:"));
|
||||
nameLabel1->show();
|
||||
nameLabel2->setText(cardName);
|
||||
nameLabel2->show();
|
||||
nameLabel->setText(tr("Unknown card:") + " " + cardName);
|
||||
textLabel->setText("");
|
||||
}
|
||||
|
||||
void CardInfoText::retranslateUi()
|
||||
{
|
||||
nameLabel1->setText(tr("Name:"));
|
||||
manacostLabel1->setText(tr("Mana cost:"));
|
||||
colorLabel1->setText(tr("Color(s):"));
|
||||
cardtypeLabel1->setText(tr("Card type:"));
|
||||
powtoughLabel1->setText(tr("P / T:"));
|
||||
loyaltyLabel1->setText(tr("Loyalty:"));
|
||||
/*
|
||||
* There's no way we can really translate the text currently being rendered.
|
||||
* The best we can do is invalidate the current text.
|
||||
*/
|
||||
setInvalidCardName("");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,23 +12,17 @@ class CardInfoText : public QFrame
|
|||
Q_OBJECT
|
||||
|
||||
private:
|
||||
QLabel *nameLabel1, *nameLabel2;
|
||||
QLabel *manacostLabel1, *manacostLabel2;
|
||||
QLabel *colorLabel1, *colorLabel2;
|
||||
QLabel *cardtypeLabel1, *cardtypeLabel2;
|
||||
QLabel *powtoughLabel1, *powtoughLabel2;
|
||||
QLabel *loyaltyLabel1, *loyaltyLabel2;
|
||||
QLabel *nameLabel;
|
||||
QTextEdit *textLabel;
|
||||
|
||||
CardInfoPtr info;
|
||||
|
||||
void resetLabels();
|
||||
|
||||
public:
|
||||
CardInfoText(QWidget *parent = 0);
|
||||
void retranslateUi();
|
||||
void setInvalidCardName(const QString &cardName);
|
||||
|
||||
signals:
|
||||
void linkActivated(const QString &link);
|
||||
public slots:
|
||||
void setCard(CardInfoPtr card);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
#include "cardinfowidget.h"
|
||||
#include <utility>
|
||||
|
||||
#include "cardinfopicture.h"
|
||||
#include "cardinfotext.h"
|
||||
#include "cardinfowidget.h"
|
||||
#include "carditem.h"
|
||||
#include "main.h"
|
||||
#include <QDesktopWidget>
|
||||
|
|
@ -14,8 +16,9 @@ CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::Win
|
|||
pic->setObjectName("pic");
|
||||
text = new CardInfoText();
|
||||
text->setObjectName("text");
|
||||
connect(text, SIGNAL(linkActivated(const QString &)), this, SLOT(setCard(const QString &)));
|
||||
|
||||
QVBoxLayout *layout = new QVBoxLayout();
|
||||
auto *layout = new QVBoxLayout();
|
||||
layout->setObjectName("layout");
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->setSpacing(0);
|
||||
|
|
@ -26,7 +29,7 @@ CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::Win
|
|||
setFrameStyle(QFrame::Panel | QFrame::Raised);
|
||||
QDesktopWidget desktopWidget;
|
||||
int pixmapHeight = desktopWidget.screenGeometry().height() / 3;
|
||||
int pixmapWidth = pixmapHeight / aspectRatio;
|
||||
int pixmapWidth = static_cast<int>(pixmapHeight / aspectRatio);
|
||||
pic->setFixedWidth(pixmapWidth);
|
||||
pic->setFixedHeight(pixmapHeight);
|
||||
setFixedWidth(pixmapWidth + 150);
|
||||
|
|
@ -41,7 +44,7 @@ void CardInfoWidget::setCard(CardInfoPtr card)
|
|||
{
|
||||
if (info)
|
||||
disconnect(info.data(), nullptr, this, nullptr);
|
||||
info = card;
|
||||
info = std::move(card);
|
||||
if (info)
|
||||
connect(info.data(), SIGNAL(destroyed()), this, SLOT(clear()));
|
||||
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ private:
|
|||
CardInfoText *text;
|
||||
|
||||
public:
|
||||
CardInfoWidget(const QString &cardName, QWidget *parent = 0, Qt::WindowFlags f = 0);
|
||||
explicit CardInfoWidget(const QString &cardName, QWidget *parent = nullptr, Qt::WindowFlags f = nullptr);
|
||||
|
||||
public slots:
|
||||
void setCard(CardInfoPtr card);
|
||||
|
|
|
|||
|
|
@ -322,9 +322,7 @@ QModelIndex DeckListModel::addCard(const QString &cardName, const QString &zoneN
|
|||
// This is usually called from tab_deck_editor
|
||||
// So we'll create a new CardInfo with the name
|
||||
// and default values for all fields
|
||||
info = CardInfo::newInstance(cardName, false, nullptr, nullptr, "unknown", nullptr, nullptr, QStringList(),
|
||||
QList<CardRelation *>(), QList<CardRelation *>(), false, 0, false, 0,
|
||||
SetList(), QStringMap(), MuidMap(), QStringMap(), QStringMap());
|
||||
info = CardInfo::newInstance(cardName);
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@
|
|||
|
||||
class DeckLoader;
|
||||
class CardDatabase;
|
||||
class QProgressDialog;
|
||||
class QPrinter;
|
||||
class QTextCursor;
|
||||
|
||||
|
|
@ -21,19 +20,19 @@ public:
|
|||
: AbstractDecklistCardNode(_parent), dataNode(_dataNode)
|
||||
{
|
||||
}
|
||||
int getNumber() const
|
||||
int getNumber() const override
|
||||
{
|
||||
return dataNode->getNumber();
|
||||
}
|
||||
void setNumber(int _number)
|
||||
void setNumber(int _number) override
|
||||
{
|
||||
dataNode->setNumber(_number);
|
||||
}
|
||||
QString getName() const
|
||||
QString getName() const override
|
||||
{
|
||||
return dataNode->getName();
|
||||
}
|
||||
void setName(const QString &_name)
|
||||
void setName(const QString &_name) override
|
||||
{
|
||||
dataNode->setName(_name);
|
||||
}
|
||||
|
|
@ -54,20 +53,20 @@ signals:
|
|||
void deckHashChanged();
|
||||
|
||||
public:
|
||||
DeckListModel(QObject *parent = 0);
|
||||
~DeckListModel();
|
||||
int rowCount(const QModelIndex &parent) const;
|
||||
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const;
|
||||
QVariant data(const QModelIndex &index, int role) const;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const;
|
||||
QModelIndex parent(const QModelIndex &index) const;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role);
|
||||
bool removeRows(int row, int count, const QModelIndex &parent);
|
||||
explicit DeckListModel(QObject *parent = nullptr);
|
||||
~DeckListModel() override;
|
||||
int rowCount(const QModelIndex &parent) const override;
|
||||
int columnCount(const QModelIndex & /*parent*/ = QModelIndex()) const override;
|
||||
QVariant data(const QModelIndex &index, int role) const override;
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override;
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent) const override;
|
||||
QModelIndex parent(const QModelIndex &index) const override;
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override;
|
||||
bool setData(const QModelIndex &index, const QVariant &value, int role) override;
|
||||
bool removeRows(int row, int count, const QModelIndex &parent) override;
|
||||
QModelIndex findCard(const QString &cardName, const QString &zoneName) const;
|
||||
QModelIndex addCard(const QString &cardName, const QString &zoneName, bool abAddAnyway = false);
|
||||
void sort(int column, Qt::SortOrder order);
|
||||
void sort(int column, Qt::SortOrder order) override;
|
||||
void cleanList();
|
||||
DeckLoader *getDeckList() const
|
||||
{
|
||||
|
|
|
|||
|
|
@ -14,8 +14,6 @@
|
|||
#include <QPushButton>
|
||||
#include <QRadioButton>
|
||||
|
||||
#define PUBLIC_SERVERS_URL "https://github.com/Cockatrice/Cockatrice/wiki/Public-Servers"
|
||||
|
||||
DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
previousHostButton = new QRadioButton(tr("Known Hosts"), this);
|
||||
|
|
@ -273,15 +271,15 @@ void DlgConnect::newHostSelected(bool state)
|
|||
previousHosts->setDisabled(true);
|
||||
btnRefreshServers->setDisabled(true);
|
||||
hostEdit->clear();
|
||||
hostEdit->setPlaceholderText("Server URL");
|
||||
hostEdit->setPlaceholderText(tr("Server URL"));
|
||||
hostEdit->setDisabled(false);
|
||||
portEdit->clear();
|
||||
portEdit->setPlaceholderText("Communication Port");
|
||||
portEdit->setPlaceholderText(tr("Communication Port"));
|
||||
portEdit->setDisabled(false);
|
||||
playernameEdit->clear();
|
||||
passwordEdit->clear();
|
||||
saveEdit->clear();
|
||||
saveEdit->setPlaceholderText("Unique Server Name");
|
||||
saveEdit->setPlaceholderText(tr("Unique Server Name"));
|
||||
saveEdit->setDisabled(false);
|
||||
serverContactLabel->setText("");
|
||||
serverContactLink->setText("");
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@
|
|||
#include <QTreeView>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(0)
|
||||
DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(nullptr)
|
||||
{
|
||||
nameLabel = new QLabel(tr("&Name:"));
|
||||
nameEdit = new QLineEdit;
|
||||
|
|
@ -46,7 +46,7 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(0)
|
|||
annotationLabel->setBuddy(annotationEdit);
|
||||
connect(annotationEdit, SIGNAL(textChanged(QString)), this, SLOT(annotationChanged(QString)));
|
||||
|
||||
QGridLayout *grid = new QGridLayout;
|
||||
auto *grid = new QGridLayout;
|
||||
grid->addWidget(nameLabel, 0, 0);
|
||||
grid->addWidget(nameEdit, 0, 1);
|
||||
grid->addWidget(colorLabel, 1, 0);
|
||||
|
|
@ -89,15 +89,15 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(0)
|
|||
aRemoveToken->setIcon(QPixmap("theme:icons/decrement"));
|
||||
connect(aRemoveToken, SIGNAL(triggered()), this, SLOT(actRemoveToken()));
|
||||
|
||||
QToolBar *databaseToolBar = new QToolBar;
|
||||
auto *databaseToolBar = new QToolBar;
|
||||
databaseToolBar->addAction(aAddToken);
|
||||
databaseToolBar->addAction(aRemoveToken);
|
||||
|
||||
QVBoxLayout *leftVBox = new QVBoxLayout;
|
||||
auto *leftVBox = new QVBoxLayout;
|
||||
leftVBox->addWidget(chooseTokenView);
|
||||
leftVBox->addWidget(databaseToolBar);
|
||||
|
||||
QHBoxLayout *hbox = new QHBoxLayout;
|
||||
auto *hbox = new QHBoxLayout;
|
||||
hbox->addLayout(leftVBox);
|
||||
hbox->addWidget(tokenDataGroupBox);
|
||||
|
||||
|
|
@ -105,7 +105,7 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(0)
|
|||
connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
|
||||
connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
auto *mainLayout = new QVBoxLayout;
|
||||
mainLayout->addLayout(hbox);
|
||||
mainLayout->addWidget(buttonBox);
|
||||
|
||||
|
|
@ -154,9 +154,10 @@ void DlgEditTokens::actAddToken()
|
|||
}
|
||||
} while (askAgain);
|
||||
|
||||
CardInfoPtr card = CardInfo::newInstance(name, true);
|
||||
card->addToSet(databaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME));
|
||||
CardInfoPtr card = CardInfo::newInstance(name, "", true);
|
||||
card->setCardType("Token");
|
||||
card->addToSet(databaseModel->getDatabase()->getSet(CardDatabase::TOKENS_SETNAME));
|
||||
|
||||
databaseModel->getDatabase()->addCard(card);
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +173,7 @@ void DlgEditTokens::actRemoveToken()
|
|||
void DlgEditTokens::colorChanged(int colorIndex)
|
||||
{
|
||||
if (currentCard)
|
||||
currentCard->setColors(QStringList() << QString(colorEdit->itemData(colorIndex).toChar()));
|
||||
currentCard->setColors(QString(colorEdit->itemData(colorIndex).toChar()));
|
||||
}
|
||||
|
||||
void DlgEditTokens::ptChanged(const QString &_pt)
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ private:
|
|||
QTreeView *chooseTokenView;
|
||||
|
||||
public:
|
||||
DlgEditTokens(QWidget *parent = nullptr);
|
||||
explicit DlgEditTokens(QWidget *parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) : QDialog(pa
|
|||
resize(500, 500);
|
||||
|
||||
actRefresh();
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()), this, SLOT(refreshShortcuts()));
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||
refreshShortcuts();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,8 +45,6 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
languageBox.setCurrentIndex(i);
|
||||
}
|
||||
|
||||
picDownloadCheckBox.setChecked(settingsCache->getPicDownload());
|
||||
|
||||
// updates
|
||||
QList<ReleaseChannel *> channels = settingsCache->getUpdateReleaseChannels();
|
||||
foreach (ReleaseChannel *chan, channels) {
|
||||
|
|
@ -55,6 +53,7 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
updateReleaseChannelBox.setCurrentIndex(settingsCache->getUpdateReleaseChannel()->getIndex());
|
||||
|
||||
updateNotificationCheckBox.setChecked(settingsCache->getNotifyAboutUpdates());
|
||||
newVersionOracleCheckBox.setChecked(settingsCache->getNotifyAboutNewVersion());
|
||||
|
||||
// pixmap cache
|
||||
pixmapCacheEdit.setMinimum(PIXMAPCACHE_SIZE_MIN);
|
||||
|
|
@ -64,27 +63,16 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
pixmapCacheEdit.setValue(settingsCache->getPixmapCacheSize());
|
||||
pixmapCacheEdit.setSuffix(" MB");
|
||||
|
||||
defaultUrlEdit = new QLineEdit(settingsCache->getPicUrl());
|
||||
fallbackUrlEdit = new QLineEdit(settingsCache->getPicUrlFallback());
|
||||
|
||||
showTipsOnStartup.setChecked(settingsCache->getShowTipsOnStartup());
|
||||
|
||||
connect(&clearDownloadedPicsButton, SIGNAL(clicked()), this, SLOT(clearDownloadedPicsButtonClicked()));
|
||||
connect(&languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
|
||||
connect(&picDownloadCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownload(int)));
|
||||
connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), settingsCache, SLOT(setPixmapCacheSize(int)));
|
||||
connect(&updateReleaseChannelBox, SIGNAL(currentIndexChanged(int)), settingsCache,
|
||||
SLOT(setUpdateReleaseChannel(int)));
|
||||
connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setNotifyAboutUpdate(int)));
|
||||
connect(&picDownloadCheckBox, SIGNAL(clicked(bool)), this, SLOT(setEnabledStatus(bool)));
|
||||
connect(defaultUrlEdit, SIGNAL(textChanged(QString)), settingsCache, SLOT(setPicUrl(QString)));
|
||||
connect(fallbackUrlEdit, SIGNAL(textChanged(QString)), settingsCache, SLOT(setPicUrlFallback(QString)));
|
||||
connect(&defaultUrlRestoreButton, SIGNAL(clicked()), this, SLOT(defaultUrlRestoreButtonClicked()));
|
||||
connect(&fallbackUrlRestoreButton, SIGNAL(clicked()), this, SLOT(fallbackUrlRestoreButtonClicked()));
|
||||
connect(&newVersionOracleCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setNotifyAboutNewVersion(int)));
|
||||
connect(&showTipsOnStartup, SIGNAL(clicked(bool)), settingsCache, SLOT(setShowTipsOnStartup(bool)));
|
||||
|
||||
setEnabledStatus(settingsCache->getPicDownload());
|
||||
|
||||
auto *personalGrid = new QGridLayout;
|
||||
personalGrid->addWidget(&languageLabel, 0, 0);
|
||||
personalGrid->addWidget(&languageBox, 0, 1);
|
||||
|
|
@ -93,19 +81,8 @@ GeneralSettingsPage::GeneralSettingsPage()
|
|||
personalGrid->addWidget(&pixmapCacheLabel, 2, 0);
|
||||
personalGrid->addWidget(&pixmapCacheEdit, 2, 1);
|
||||
personalGrid->addWidget(&updateNotificationCheckBox, 3, 0);
|
||||
personalGrid->addWidget(&showTipsOnStartup, 4, 0);
|
||||
personalGrid->addWidget(&picDownloadCheckBox, 5, 0);
|
||||
personalGrid->addWidget(&urlLinkLabel, 5, 1);
|
||||
personalGrid->addWidget(&defaultUrlLabel, 6, 0, 1, 1);
|
||||
personalGrid->addWidget(defaultUrlEdit, 6, 1, 1, 1);
|
||||
personalGrid->addWidget(&defaultUrlRestoreButton, 6, 2, 1, 1);
|
||||
personalGrid->addWidget(&fallbackUrlLabel, 7, 0, 1, 1);
|
||||
personalGrid->addWidget(fallbackUrlEdit, 7, 1, 1, 1);
|
||||
personalGrid->addWidget(&fallbackUrlRestoreButton, 7, 2, 1, 1);
|
||||
personalGrid->addWidget(&clearDownloadedPicsButton, 8, 1);
|
||||
|
||||
urlLinkLabel.setTextInteractionFlags(Qt::LinksAccessibleByMouse);
|
||||
urlLinkLabel.setOpenExternalLinks(true);
|
||||
personalGrid->addWidget(&newVersionOracleCheckBox, 4, 0);
|
||||
personalGrid->addWidget(&showTipsOnStartup, 5, 0);
|
||||
|
||||
personalGroupBox = new QGroupBox;
|
||||
personalGroupBox->setLayout(personalGrid);
|
||||
|
|
@ -194,20 +171,6 @@ QString GeneralSettingsPage::languageName(const QString &qmFile)
|
|||
return translator.translate("i18n", DEFAULT_LANG_NAME);
|
||||
}
|
||||
|
||||
void GeneralSettingsPage::defaultUrlRestoreButtonClicked()
|
||||
{
|
||||
QString path = PIC_URL_DEFAULT;
|
||||
defaultUrlEdit->setText(path);
|
||||
settingsCache->setPicUrl(path);
|
||||
}
|
||||
|
||||
void GeneralSettingsPage::fallbackUrlRestoreButtonClicked()
|
||||
{
|
||||
QString path = PIC_URL_FALLBACK;
|
||||
fallbackUrlEdit->setText(path);
|
||||
settingsCache->setPicUrlFallback(path);
|
||||
}
|
||||
|
||||
void GeneralSettingsPage::deckPathButtonClicked()
|
||||
{
|
||||
QString path = QFileDialog::getExistingDirectory(this, tr("Choose path"));
|
||||
|
|
@ -238,30 +201,6 @@ void GeneralSettingsPage::picsPathButtonClicked()
|
|||
settingsCache->setPicsPath(path);
|
||||
}
|
||||
|
||||
void GeneralSettingsPage::clearDownloadedPicsButtonClicked()
|
||||
{
|
||||
QString picsPath = settingsCache->getPicsPath() + "/downloadedPics/";
|
||||
QStringList dirs = QDir(picsPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
|
||||
bool outerSuccessRemove = true;
|
||||
for (int i = 0; i < dirs.length(); i++) {
|
||||
QString currentPath = picsPath + dirs.at(i) + "/";
|
||||
QStringList files = QDir(currentPath).entryList(QDir::Files);
|
||||
bool innerSuccessRemove = true;
|
||||
for (int j = 0; j < files.length(); j++)
|
||||
if (!QDir(currentPath).remove(files.at(j))) {
|
||||
qDebug() << "Failed to remove " + currentPath.toUtf8() + files.at(j).toUtf8();
|
||||
outerSuccessRemove = false;
|
||||
innerSuccessRemove = false;
|
||||
}
|
||||
if (innerSuccessRemove)
|
||||
QDir(picsPath).rmdir(dirs.at(i));
|
||||
}
|
||||
if (outerSuccessRemove)
|
||||
QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset."));
|
||||
else
|
||||
QMessageBox::critical(this, tr("Error"), tr("One or more downloaded card pictures could not be cleared."));
|
||||
}
|
||||
|
||||
void GeneralSettingsPage::cardDatabasePathButtonClicked()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Choose path"));
|
||||
|
|
@ -291,7 +230,6 @@ void GeneralSettingsPage::retranslateUi()
|
|||
{
|
||||
personalGroupBox->setTitle(tr("Personal settings"));
|
||||
languageLabel.setText(tr("Language:"));
|
||||
picDownloadCheckBox.setText(tr("Download card pictures on the fly"));
|
||||
|
||||
if (settingsCache->getIsPortableBuild()) {
|
||||
pathsGroupBox->setTitle(tr("Paths (editing disabled in portable mode)"));
|
||||
|
|
@ -305,26 +243,12 @@ void GeneralSettingsPage::retranslateUi()
|
|||
cardDatabasePathLabel.setText(tr("Card database:"));
|
||||
tokenDatabasePathLabel.setText(tr("Token database:"));
|
||||
pixmapCacheLabel.setText(tr("Picture cache size:"));
|
||||
defaultUrlLabel.setText(tr("Primary download URL:"));
|
||||
fallbackUrlLabel.setText(tr("Fallback download URL:"));
|
||||
urlLinkLabel.setText(
|
||||
QString("<a href='%1'>%2</a>").arg(WIKI_CUSTOM_PIC_URL).arg(tr("How to set a custom picture url")));
|
||||
clearDownloadedPicsButton.setText(tr("Reset/clear downloaded pictures"));
|
||||
updateReleaseChannelLabel.setText(tr("Update channel"));
|
||||
updateNotificationCheckBox.setText(tr("Notify if a feature supported by the server is missing in my client"));
|
||||
defaultUrlRestoreButton.setText(tr("Reset"));
|
||||
fallbackUrlRestoreButton.setText(tr("Reset"));
|
||||
newVersionOracleCheckBox.setText(tr("Automatically run Oracle when running a new version of Cockatrice"));
|
||||
showTipsOnStartup.setText(tr("Show tips on startup"));
|
||||
}
|
||||
|
||||
void GeneralSettingsPage::setEnabledStatus(bool status)
|
||||
{
|
||||
defaultUrlEdit->setEnabled(status);
|
||||
fallbackUrlEdit->setEnabled(status);
|
||||
defaultUrlRestoreButton.setEnabled(status);
|
||||
fallbackUrlRestoreButton.setEnabled(status);
|
||||
}
|
||||
|
||||
AppearanceSettingsPage::AppearanceSettingsPage()
|
||||
{
|
||||
QString themeName = settingsCache->getThemeName();
|
||||
|
|
@ -498,6 +422,15 @@ void UserInterfaceSettingsPage::retranslateUi()
|
|||
|
||||
DeckEditorSettingsPage::DeckEditorSettingsPage()
|
||||
{
|
||||
picDownloadCheckBox.setChecked(settingsCache->getPicDownload());
|
||||
connect(&picDownloadCheckBox, SIGNAL(stateChanged(int)), settingsCache, SLOT(setPicDownload(int)));
|
||||
|
||||
urlLinkLabel.setTextInteractionFlags(Qt::LinksAccessibleByMouse);
|
||||
urlLinkLabel.setOpenExternalLinks(true);
|
||||
|
||||
connect(&clearDownloadedPicsButton, SIGNAL(clicked()), this, SLOT(clearDownloadedPicsButtonClicked()));
|
||||
connect(&resetDownloadURLs, SIGNAL(clicked()), this, SLOT(resetDownloadedURLsButtonClicked()));
|
||||
|
||||
auto *lpGeneralGrid = new QGridLayout;
|
||||
auto *lpSpoilerGrid = new QGridLayout;
|
||||
|
||||
|
|
@ -515,9 +448,46 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
|
|||
// Update the GUI depending on if the box is ticked or not
|
||||
setSpoilersEnabled(mcDownloadSpoilersCheckBox.isChecked());
|
||||
|
||||
// Create the layout
|
||||
lpGeneralGrid->addWidget(&mcGeneralMessageLabel, 0, 0);
|
||||
urlList = new QListWidget;
|
||||
urlList->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||
urlList->setAlternatingRowColors(true);
|
||||
urlList->setDragEnabled(true);
|
||||
urlList->setDragDropMode(QAbstractItemView::InternalMove);
|
||||
connect(urlList->model(), SIGNAL(rowsMoved(const QModelIndex, int, int, const QModelIndex, int)), this,
|
||||
SLOT(urlListChanged(const QModelIndex, int, int, const QModelIndex, int)));
|
||||
|
||||
for (int i = 0; i < settingsCache->downloads().getCount(); i++)
|
||||
urlList->addItem(settingsCache->downloads().getDownloadUrlAt(i));
|
||||
|
||||
auto aAdd = new QAction(this);
|
||||
aAdd->setIcon(QPixmap("theme:icons/increment"));
|
||||
connect(aAdd, SIGNAL(triggered()), this, SLOT(actAddURL()));
|
||||
auto aEdit = new QAction(this);
|
||||
aEdit->setIcon(QPixmap("theme:icons/pencil"));
|
||||
connect(aEdit, SIGNAL(triggered()), this, SLOT(actEditURL()));
|
||||
auto aRemove = new QAction(this);
|
||||
aRemove->setIcon(QPixmap("theme:icons/decrement"));
|
||||
connect(aRemove, SIGNAL(triggered()), this, SLOT(actRemoveURL()));
|
||||
|
||||
auto *messageToolBar = new QToolBar;
|
||||
messageToolBar->setOrientation(Qt::Vertical);
|
||||
messageToolBar->addAction(aAdd);
|
||||
messageToolBar->addAction(aRemove);
|
||||
messageToolBar->addAction(aEdit);
|
||||
messageToolBar->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
|
||||
|
||||
auto *messageListLayout = new QHBoxLayout;
|
||||
messageListLayout->addWidget(messageToolBar);
|
||||
messageListLayout->addWidget(urlList);
|
||||
|
||||
// Top Layout
|
||||
lpGeneralGrid->addWidget(&picDownloadCheckBox, 0, 0);
|
||||
lpGeneralGrid->addWidget(&resetDownloadURLs, 0, 1);
|
||||
lpGeneralGrid->addLayout(messageListLayout, 1, 0, 1, 2);
|
||||
lpGeneralGrid->addWidget(&urlLinkLabel, 2, 0);
|
||||
lpGeneralGrid->addWidget(&clearDownloadedPicsButton, 2, 1);
|
||||
|
||||
// Spoiler Layout
|
||||
lpSpoilerGrid->addWidget(&mcDownloadSpoilersCheckBox, 0, 0);
|
||||
lpSpoilerGrid->addWidget(&mcSpoilerSaveLabel, 1, 0);
|
||||
lpSpoilerGrid->addWidget(mpSpoilerSavePathLineEdit, 1, 1);
|
||||
|
|
@ -543,6 +513,94 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
|
|||
setLayout(lpMainLayout);
|
||||
}
|
||||
|
||||
void DeckEditorSettingsPage::resetDownloadedURLsButtonClicked()
|
||||
{
|
||||
settingsCache->downloads().clear();
|
||||
urlList->clear();
|
||||
urlList->addItems(settingsCache->downloads().getAllURLs());
|
||||
QMessageBox::information(this, tr("Success"), tr("Download URLs have been reset."));
|
||||
}
|
||||
|
||||
void DeckEditorSettingsPage::clearDownloadedPicsButtonClicked()
|
||||
{
|
||||
QString picsPath = settingsCache->getPicsPath() + "/downloadedPics/";
|
||||
QStringList dirs = QDir(picsPath).entryList(QDir::AllDirs | QDir::NoDotAndDotDot);
|
||||
bool outerSuccessRemove = true;
|
||||
for (const auto &dir : dirs) {
|
||||
QString currentPath = picsPath + dir + "/";
|
||||
QStringList files = QDir(currentPath).entryList(QDir::Files);
|
||||
bool innerSuccessRemove = true;
|
||||
for (int j = 0; j < files.length(); j++) {
|
||||
if (!QDir(currentPath).remove(files.at(j))) {
|
||||
qInfo() << "Failed to remove " + currentPath.toUtf8() + files.at(j).toUtf8();
|
||||
outerSuccessRemove = false;
|
||||
innerSuccessRemove = false;
|
||||
}
|
||||
qInfo() << "Removed " << currentPath << files.at(j);
|
||||
}
|
||||
|
||||
if (innerSuccessRemove) {
|
||||
bool success = QDir(picsPath).rmdir(dir);
|
||||
if (!success) {
|
||||
qInfo() << "Failed to remove inner directory" << picsPath;
|
||||
} else {
|
||||
qInfo() << "Removed" << currentPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (outerSuccessRemove) {
|
||||
QMessageBox::information(this, tr("Success"), tr("Downloaded card pictures have been reset."));
|
||||
} else {
|
||||
QMessageBox::critical(this, tr("Error"), tr("One or more downloaded card pictures could not be cleared."));
|
||||
}
|
||||
}
|
||||
|
||||
void DeckEditorSettingsPage::actAddURL()
|
||||
{
|
||||
bool ok;
|
||||
QString msg = QInputDialog::getText(this, tr("Add URL"), tr("URL:"), QLineEdit::Normal, QString(), &ok);
|
||||
if (ok) {
|
||||
urlList->addItem(msg);
|
||||
storeSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckEditorSettingsPage::actRemoveURL()
|
||||
{
|
||||
if (urlList->currentItem() != nullptr) {
|
||||
delete urlList->takeItem(urlList->currentRow());
|
||||
storeSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void DeckEditorSettingsPage::actEditURL()
|
||||
{
|
||||
if (urlList->currentItem()) {
|
||||
QString oldText = urlList->currentItem()->text();
|
||||
bool ok;
|
||||
QString msg = QInputDialog::getText(this, tr("Edit URL"), tr("URL:"), QLineEdit::Normal, oldText, &ok);
|
||||
if (ok) {
|
||||
urlList->currentItem()->setText(msg);
|
||||
storeSettings();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DeckEditorSettingsPage::storeSettings()
|
||||
{
|
||||
qInfo() << "URL Priority Reset";
|
||||
settingsCache->downloads().clear();
|
||||
for (int i = 0; i < urlList->count(); i++) {
|
||||
qInfo() << "Priority" << i << ":" << urlList->item(i)->text();
|
||||
settingsCache->downloads().setDownloadUrlAt(i, urlList->item(i)->text());
|
||||
}
|
||||
}
|
||||
|
||||
void DeckEditorSettingsPage::urlListChanged(const QModelIndex &, int, int, const QModelIndex &, int)
|
||||
{
|
||||
storeSettings();
|
||||
}
|
||||
|
||||
void DeckEditorSettingsPage::updateSpoilers()
|
||||
{
|
||||
// Disable the button so the user can only press it once at a time
|
||||
|
|
@ -603,14 +661,18 @@ void DeckEditorSettingsPage::setSpoilersEnabled(bool anInput)
|
|||
|
||||
void DeckEditorSettingsPage::retranslateUi()
|
||||
{
|
||||
mpGeneralGroupBox->setTitle(tr("URL Download Priority"));
|
||||
mpSpoilerGroupBox->setTitle(tr("Spoilers"));
|
||||
mcDownloadSpoilersCheckBox.setText(tr("Download Spoilers Automatically"));
|
||||
mcSpoilerSaveLabel.setText(tr("Spoiler Location:"));
|
||||
mcGeneralMessageLabel.setText(tr("Hey, something's here finally!"));
|
||||
lastUpdatedLabel.setText(tr("Last Updated") + ": " + getLastUpdateTime());
|
||||
infoOnSpoilersLabel.setText(tr("Spoilers download automatically on launch") + "\n" +
|
||||
tr("Press the button to manually update without relaunching") + "\n\n" +
|
||||
tr("Do not close settings until manual update complete"));
|
||||
picDownloadCheckBox.setText(tr("Download card pictures on the fly"));
|
||||
urlLinkLabel.setText(QString("<a href='%1'>%2</a>").arg(WIKI_CUSTOM_PIC_URL).arg(tr("How to add a custom URL")));
|
||||
clearDownloadedPicsButton.setText(tr("Delete Downloaded Images"));
|
||||
resetDownloadURLs.setText(tr("Reset Download URLs"));
|
||||
}
|
||||
|
||||
MessagesSettingsPage::MessagesSettingsPage()
|
||||
|
|
@ -649,7 +711,7 @@ MessagesSettingsPage::MessagesSettingsPage()
|
|||
connect(&roomHistory, SIGNAL(stateChanged(int)), settingsCache, SLOT(setRoomHistory(int)));
|
||||
|
||||
customAlertString = new QLineEdit();
|
||||
customAlertString->setPlaceholderText("Word1 Word2 Word3");
|
||||
customAlertString->setPlaceholderText(tr("Word1 Word2 Word3"));
|
||||
customAlertString->setText(settingsCache->getHighlightWords());
|
||||
connect(customAlertString, SIGNAL(textChanged(QString)), settingsCache, SLOT(setHighlightWords(QString)));
|
||||
|
||||
|
|
@ -689,12 +751,16 @@ MessagesSettingsPage::MessagesSettingsPage()
|
|||
|
||||
aAdd = new QAction(this);
|
||||
aAdd->setIcon(QPixmap("theme:icons/increment"));
|
||||
aAdd->setStatusTip(tr("Add New URL"));
|
||||
|
||||
connect(aAdd, SIGNAL(triggered()), this, SLOT(actAdd()));
|
||||
aEdit = new QAction(this);
|
||||
aEdit->setIcon(QPixmap("theme:icons/pencil"));
|
||||
aEdit->setStatusTip(tr("Edit URL"));
|
||||
connect(aEdit, SIGNAL(triggered()), this, SLOT(actEdit()));
|
||||
aRemove = new QAction(this);
|
||||
aRemove->setIcon(QPixmap("theme:icons/decrement"));
|
||||
aRemove->setStatusTip(tr("Remove URL"));
|
||||
connect(aRemove, SIGNAL(triggered()), this, SLOT(actRemove()));
|
||||
|
||||
auto *messageToolBar = new QToolBar;
|
||||
|
|
@ -798,7 +864,7 @@ void MessagesSettingsPage::actEdit()
|
|||
|
||||
void MessagesSettingsPage::actRemove()
|
||||
{
|
||||
if (messageList->currentItem()) {
|
||||
if (messageList->currentItem() != nullptr) {
|
||||
delete messageList->takeItem(messageList->currentRow());
|
||||
storeSettings();
|
||||
}
|
||||
|
|
@ -1000,7 +1066,7 @@ void DlgSettings::setTab(int index)
|
|||
|
||||
void DlgSettings::updateLanguage()
|
||||
{
|
||||
qApp->removeTranslator(translator);
|
||||
qApp->removeTranslator(translator); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
installNewTranslator();
|
||||
}
|
||||
|
||||
|
|
@ -1094,7 +1160,7 @@ void DlgSettings::retranslateUi()
|
|||
generalButton->setText(tr("General"));
|
||||
appearanceButton->setText(tr("Appearance"));
|
||||
userInterfaceButton->setText(tr("User Interface"));
|
||||
deckEditorButton->setText(tr("Deck Editor"));
|
||||
deckEditorButton->setText(tr("Card Sources"));
|
||||
messagesButton->setText(tr("Chat"));
|
||||
soundButton->setText(tr("Sound"));
|
||||
shortcutsButton->setText(tr("Shortcuts"));
|
||||
|
|
|
|||
|
|
@ -43,13 +43,9 @@ private slots:
|
|||
void deckPathButtonClicked();
|
||||
void replaysPathButtonClicked();
|
||||
void picsPathButtonClicked();
|
||||
void clearDownloadedPicsButtonClicked();
|
||||
void cardDatabasePathButtonClicked();
|
||||
void tokenDatabasePathButtonClicked();
|
||||
void languageBoxChanged(int index);
|
||||
void setEnabledStatus(bool);
|
||||
void defaultUrlRestoreButtonClicked();
|
||||
void fallbackUrlRestoreButtonClicked();
|
||||
|
||||
private:
|
||||
QStringList findQmFiles();
|
||||
|
|
@ -59,14 +55,12 @@ private:
|
|||
QLineEdit *picsPathEdit;
|
||||
QLineEdit *cardDatabasePathEdit;
|
||||
QLineEdit *tokenDatabasePathEdit;
|
||||
QLineEdit *defaultUrlEdit;
|
||||
QLineEdit *fallbackUrlEdit;
|
||||
QSpinBox pixmapCacheEdit;
|
||||
QGroupBox *personalGroupBox;
|
||||
QGroupBox *pathsGroupBox;
|
||||
QComboBox languageBox;
|
||||
QCheckBox picDownloadCheckBox;
|
||||
QCheckBox updateNotificationCheckBox;
|
||||
QCheckBox newVersionOracleCheckBox;
|
||||
QComboBox updateReleaseChannelBox;
|
||||
QLabel languageLabel;
|
||||
QLabel pixmapCacheLabel;
|
||||
|
|
@ -75,13 +69,7 @@ private:
|
|||
QLabel picsPathLabel;
|
||||
QLabel cardDatabasePathLabel;
|
||||
QLabel tokenDatabasePathLabel;
|
||||
QLabel defaultUrlLabel;
|
||||
QLabel fallbackUrlLabel;
|
||||
QLabel urlLinkLabel;
|
||||
QLabel updateReleaseChannelLabel;
|
||||
QPushButton clearDownloadedPicsButton;
|
||||
QPushButton defaultUrlRestoreButton;
|
||||
QPushButton fallbackUrlRestoreButton;
|
||||
QCheckBox showTipsOnStartup;
|
||||
};
|
||||
|
||||
|
|
@ -143,19 +131,30 @@ public:
|
|||
QString getLastUpdateTime();
|
||||
|
||||
private slots:
|
||||
void storeSettings();
|
||||
void urlListChanged(const QModelIndex &, int, int, const QModelIndex &, int);
|
||||
void setSpoilersEnabled(bool);
|
||||
void spoilerPathButtonClicked();
|
||||
void updateSpoilers();
|
||||
void unlockSettings();
|
||||
void actAddURL();
|
||||
void actRemoveURL();
|
||||
void actEditURL();
|
||||
void clearDownloadedPicsButtonClicked();
|
||||
void resetDownloadedURLsButtonClicked();
|
||||
|
||||
private:
|
||||
QPushButton clearDownloadedPicsButton;
|
||||
QPushButton resetDownloadURLs;
|
||||
QLabel urlLinkLabel;
|
||||
QCheckBox picDownloadCheckBox;
|
||||
QListWidget *urlList;
|
||||
QCheckBox mcDownloadSpoilersCheckBox;
|
||||
QLabel msDownloadSpoilersLabel;
|
||||
QGroupBox *mpGeneralGroupBox;
|
||||
QGroupBox *mpSpoilerGroupBox;
|
||||
QLineEdit *mpSpoilerSavePathLineEdit;
|
||||
QLabel mcSpoilerSaveLabel;
|
||||
QLabel mcGeneralMessageLabel;
|
||||
QLabel lastUpdatedLabel;
|
||||
QLabel infoOnSpoilersLabel;
|
||||
QPushButton *mpSpoilerPathButton;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
#define MIN_TIP_IMAGE_HEIGHT 200
|
||||
#define MIN_TIP_IMAGE_WIDTH 200
|
||||
#define MAX_TIP_IMAGE_HEIGHT 300
|
||||
#define MAX_TIP_IMAGE_WIDTH 300
|
||||
#define MAX_TIP_IMAGE_WIDTH 500
|
||||
|
||||
DlgTipOfTheDay::DlgTipOfTheDay(QWidget *parent) : QDialog(parent)
|
||||
{
|
||||
|
|
@ -149,9 +149,9 @@ void DlgTipOfTheDay::updateTip(int tipId)
|
|||
qDebug() << "Image failed to load from" << imagePath;
|
||||
imageLabel->clear();
|
||||
} else {
|
||||
int h = std::min(std::max(image->height(), MIN_TIP_IMAGE_HEIGHT), MAX_TIP_IMAGE_HEIGHT);
|
||||
int h = std::min(std::max(imageLabel->height(), MIN_TIP_IMAGE_HEIGHT), MAX_TIP_IMAGE_HEIGHT);
|
||||
int w = std::min(std::max(imageLabel->width(), MIN_TIP_IMAGE_WIDTH), MAX_TIP_IMAGE_WIDTH);
|
||||
imageLabel->setPixmap(image->scaled(h, w, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
imageLabel->setPixmap(image->scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
}
|
||||
|
||||
date->setText("<i>Tip added on: " + tip.getDate().toString("yyyy.MM.dd") + "</i>");
|
||||
|
|
@ -163,9 +163,7 @@ void DlgTipOfTheDay::updateTip(int tipId)
|
|||
|
||||
void DlgTipOfTheDay::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
int h = imageLabel->height();
|
||||
int w = imageLabel->width();
|
||||
imageLabel->setPixmap(image->scaled(w, h, Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
imageLabel->setPixmap(image->scaled(imageLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
|
||||
|
||||
QWidget::resizeEvent(event);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ FilterBuilder::FilterBuilder(QWidget *parent) : QWidget(parent)
|
|||
filterCombo = new QComboBox;
|
||||
filterCombo->setObjectName("filterCombo");
|
||||
for (int i = 0; i < CardFilter::AttrEnd; i++)
|
||||
filterCombo->addItem(tr(CardFilter::attrName(static_cast<CardFilter::Attr>(i))), QVariant(i));
|
||||
filterCombo->addItem(CardFilter::attrName(static_cast<CardFilter::Attr>(i)), QVariant(i));
|
||||
|
||||
typeCombo = new QComboBox;
|
||||
typeCombo->setObjectName("typeCombo");
|
||||
|
|
|
|||
|
|
@ -187,11 +187,8 @@ bool FilterItem::acceptColor(const CardInfoPtr info) const
|
|||
*/
|
||||
int match_count = 0;
|
||||
for (auto &it : converted_term) {
|
||||
for (auto i = info->getColors().constBegin(); i != info->getColors().constEnd(); i++) {
|
||||
if ((*i).contains(it, Qt::CaseInsensitive)) {
|
||||
match_count++;
|
||||
}
|
||||
}
|
||||
if (info->getColors().contains(it, Qt::CaseInsensitive))
|
||||
match_count++;
|
||||
}
|
||||
|
||||
return match_count == converted_term.length();
|
||||
|
|
@ -205,9 +202,9 @@ bool FilterItem::acceptText(const CardInfoPtr info) const
|
|||
bool FilterItem::acceptSet(const CardInfoPtr info) const
|
||||
{
|
||||
bool status = false;
|
||||
for (auto i = info->getSets().constBegin(); i != info->getSets().constEnd(); i++) {
|
||||
if ((*i)->getShortName().compare(term, Qt::CaseInsensitive) == 0 ||
|
||||
(*i)->getLongName().compare(term, Qt::CaseInsensitive) == 0) {
|
||||
for (const auto &set : info->getSets()) {
|
||||
if (set.getPtr()->getShortName().compare(term, Qt::CaseInsensitive) == 0 ||
|
||||
set.getPtr()->getLongName().compare(term, Qt::CaseInsensitive) == 0) {
|
||||
status = true;
|
||||
break;
|
||||
}
|
||||
|
|
@ -299,7 +296,7 @@ bool FilterItem::acceptRarity(const CardInfoPtr info) const
|
|||
|
||||
/*
|
||||
* The purpose of this loop is to only apply one of the replacement
|
||||
* policies and then escape. If we attempt to layer them ontop of
|
||||
* policies and then escape. If we attempt to layer them on top of
|
||||
* each other, we will get awkward results (i.e. comythic rare mythic rareon)
|
||||
* Conditional statement will exit once a case is successful in
|
||||
* replacement OR we go through all possible cases.
|
||||
|
|
@ -334,8 +331,8 @@ bool FilterItem::acceptRarity(const CardInfoPtr info) const
|
|||
}
|
||||
}
|
||||
|
||||
for (const QString &rareLevel : info->getRarities()) {
|
||||
if (rareLevel.compare(converted_term, Qt::CaseInsensitive) == 0) {
|
||||
for (const auto &set : info->getSets()) {
|
||||
if (set.getProperty("rarity").compare(converted_term, Qt::CaseInsensitive) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
|
||||
|
||||
#ifndef FILTERTREE_H
|
||||
#define FILTERTREE_H
|
||||
|
||||
#include "carddatabase.h"
|
||||
#include "cardfilter.h"
|
||||
#include <QList>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
|
||||
#include "carddatabase.h"
|
||||
#include "cardfilter.h"
|
||||
#include <utility>
|
||||
|
||||
class FilterTreeNode
|
||||
{
|
||||
|
|
@ -33,11 +35,11 @@ public:
|
|||
}
|
||||
virtual FilterTreeNode *parent() const
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
virtual FilterTreeNode *nodeAt(int /* i */) const
|
||||
{
|
||||
return NULL;
|
||||
return nullptr;
|
||||
}
|
||||
virtual void deleteAt(int /* i */)
|
||||
{
|
||||
|
|
@ -52,43 +54,39 @@ public:
|
|||
}
|
||||
virtual int index() const
|
||||
{
|
||||
return (parent() != NULL) ? parent()->childIndex(this) : -1;
|
||||
return (parent() != nullptr) ? parent()->childIndex(this) : -1;
|
||||
}
|
||||
virtual QString text() const
|
||||
virtual const QString text() const
|
||||
{
|
||||
return QString(textCStr());
|
||||
return QString("");
|
||||
}
|
||||
virtual bool isLeaf() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
virtual const char *textCStr() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
virtual void nodeChanged() const
|
||||
{
|
||||
if (parent() != NULL)
|
||||
if (parent() != nullptr)
|
||||
parent()->nodeChanged();
|
||||
}
|
||||
virtual void preInsertChild(const FilterTreeNode *p, int i) const
|
||||
{
|
||||
if (parent() != NULL)
|
||||
if (parent() != nullptr)
|
||||
parent()->preInsertChild(p, i);
|
||||
}
|
||||
virtual void postInsertChild(const FilterTreeNode *p, int i) const
|
||||
{
|
||||
if (parent() != NULL)
|
||||
if (parent() != nullptr)
|
||||
parent()->postInsertChild(p, i);
|
||||
}
|
||||
virtual void preRemoveChild(const FilterTreeNode *p, int i) const
|
||||
{
|
||||
if (parent() != NULL)
|
||||
if (parent() != nullptr)
|
||||
parent()->preRemoveChild(p, i);
|
||||
}
|
||||
virtual void postRemoveChild(const FilterTreeNode *p, int i) const
|
||||
{
|
||||
if (parent() != NULL)
|
||||
if (parent() != nullptr)
|
||||
parent()->postRemoveChild(p, i);
|
||||
}
|
||||
};
|
||||
|
|
@ -100,13 +98,13 @@ protected:
|
|||
|
||||
public:
|
||||
virtual ~FilterTreeBranch();
|
||||
FilterTreeNode *nodeAt(int i) const;
|
||||
void deleteAt(int i);
|
||||
int childCount() const
|
||||
FilterTreeNode *nodeAt(int i) const override;
|
||||
void deleteAt(int i) override;
|
||||
int childCount() const override
|
||||
{
|
||||
return childNodes.size();
|
||||
}
|
||||
int childIndex(const FilterTreeNode *node) const;
|
||||
int childIndex(const FilterTreeNode *node) const override;
|
||||
};
|
||||
|
||||
class FilterItemList;
|
||||
|
|
@ -125,8 +123,8 @@ public:
|
|||
}
|
||||
const FilterItemList *findTypeList(CardFilter::Type type) const;
|
||||
FilterItemList *typeList(CardFilter::Type type);
|
||||
FilterTreeNode *parent() const;
|
||||
const char *textCStr() const
|
||||
FilterTreeNode *parent() const override;
|
||||
const QString text() const override
|
||||
{
|
||||
return CardFilter::attrName(attr);
|
||||
}
|
||||
|
|
@ -148,21 +146,21 @@ public:
|
|||
{
|
||||
return p->attr;
|
||||
}
|
||||
FilterTreeNode *parent() const
|
||||
FilterTreeNode *parent() const override
|
||||
{
|
||||
return p;
|
||||
}
|
||||
int termIndex(const QString &term) const;
|
||||
FilterTreeNode *termNode(const QString &term);
|
||||
const char *textCStr() const
|
||||
const QString text() const override
|
||||
{
|
||||
return CardFilter::typeName(type);
|
||||
}
|
||||
|
||||
bool testTypeAnd(const CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool testTypeAndNot(const CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool testTypeOr(const CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool testTypeOrNot(const CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool testTypeAnd(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool testTypeAndNot(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool testTypeOr(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool testTypeOrNot(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
};
|
||||
|
||||
class FilterItem : public FilterTreeNode
|
||||
|
|
@ -173,10 +171,10 @@ private:
|
|||
public:
|
||||
const QString term;
|
||||
|
||||
FilterItem(QString trm, FilterItemList *parent) : p(parent), term(trm)
|
||||
FilterItem(QString trm, FilterItemList *parent) : p(parent), term(std::move(trm))
|
||||
{
|
||||
}
|
||||
virtual ~FilterItem(){};
|
||||
virtual ~FilterItem() = default;
|
||||
|
||||
CardFilter::Attr attr() const
|
||||
{
|
||||
|
|
@ -186,34 +184,30 @@ public:
|
|||
{
|
||||
return p->type;
|
||||
}
|
||||
FilterTreeNode *parent() const
|
||||
FilterTreeNode *parent() const override
|
||||
{
|
||||
return p;
|
||||
}
|
||||
QString text() const
|
||||
const QString text() const override
|
||||
{
|
||||
return term;
|
||||
}
|
||||
const char *textCStr() const
|
||||
{
|
||||
return term.toStdString().c_str();
|
||||
}
|
||||
bool isLeaf() const
|
||||
bool isLeaf() const override
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
bool acceptName(const CardInfoPtr info) const;
|
||||
bool acceptType(const CardInfoPtr info) const;
|
||||
bool acceptColor(const CardInfoPtr info) const;
|
||||
bool acceptText(const CardInfoPtr info) const;
|
||||
bool acceptSet(const CardInfoPtr info) const;
|
||||
bool acceptManaCost(const CardInfoPtr info) const;
|
||||
bool acceptCmc(const CardInfoPtr info) const;
|
||||
bool acceptPowerToughness(const CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool acceptLoyalty(const CardInfoPtr info) const;
|
||||
bool acceptRarity(const CardInfoPtr info) const;
|
||||
bool acceptCardAttr(const CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool acceptName(CardInfoPtr info) const;
|
||||
bool acceptType(CardInfoPtr info) const;
|
||||
bool acceptColor(CardInfoPtr info) const;
|
||||
bool acceptText(CardInfoPtr info) const;
|
||||
bool acceptSet(CardInfoPtr info) const;
|
||||
bool acceptManaCost(CardInfoPtr info) const;
|
||||
bool acceptCmc(CardInfoPtr info) const;
|
||||
bool acceptPowerToughness(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool acceptLoyalty(CardInfoPtr info) const;
|
||||
bool acceptRarity(CardInfoPtr info) const;
|
||||
bool acceptCardAttr(CardInfoPtr info, CardFilter::Attr attr) const;
|
||||
bool relationCheck(int cardInfo) const;
|
||||
};
|
||||
|
||||
|
|
@ -232,47 +226,47 @@ private:
|
|||
LogicMap *attrLogicMap(CardFilter::Attr attr);
|
||||
FilterItemList *attrTypeList(CardFilter::Attr attr, CardFilter::Type type);
|
||||
|
||||
bool testAttr(const CardInfoPtr info, const LogicMap *lm) const;
|
||||
bool testAttr(CardInfoPtr info, const LogicMap *lm) const;
|
||||
|
||||
void nodeChanged() const
|
||||
void nodeChanged() const override
|
||||
{
|
||||
emit changed();
|
||||
}
|
||||
void preInsertChild(const FilterTreeNode *p, int i) const
|
||||
void preInsertChild(const FilterTreeNode *p, int i) const override
|
||||
{
|
||||
emit preInsertRow(p, i);
|
||||
}
|
||||
void postInsertChild(const FilterTreeNode *p, int i) const
|
||||
void postInsertChild(const FilterTreeNode *p, int i) const override
|
||||
{
|
||||
emit postInsertRow(p, i);
|
||||
}
|
||||
void preRemoveChild(const FilterTreeNode *p, int i) const
|
||||
void preRemoveChild(const FilterTreeNode *p, int i) const override
|
||||
{
|
||||
emit preRemoveRow(p, i);
|
||||
}
|
||||
void postRemoveChild(const FilterTreeNode *p, int i) const
|
||||
void postRemoveChild(const FilterTreeNode *p, int i) const override
|
||||
{
|
||||
emit postRemoveRow(p, i);
|
||||
}
|
||||
|
||||
public:
|
||||
FilterTree();
|
||||
~FilterTree();
|
||||
~FilterTree() override;
|
||||
int findTermIndex(CardFilter::Attr attr, CardFilter::Type type, const QString &term);
|
||||
int findTermIndex(const CardFilter *f);
|
||||
FilterTreeNode *termNode(CardFilter::Attr attr, CardFilter::Type type, const QString &term);
|
||||
FilterTreeNode *termNode(const CardFilter *f);
|
||||
FilterTreeNode *attrTypeNode(CardFilter::Attr attr, CardFilter::Type type);
|
||||
const char *textCStr() const
|
||||
const QString text() const override
|
||||
{
|
||||
return "root";
|
||||
return QString("root");
|
||||
}
|
||||
int index() const
|
||||
int index() const override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool acceptsCard(const CardInfoPtr info) const;
|
||||
bool acceptsCard(CardInfoPtr info) const;
|
||||
void clear();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -128,10 +128,7 @@ QVariant FilterTreeModel::data(const QModelIndex &index, int role) const
|
|||
case Qt::ToolTipRole:
|
||||
case Qt::StatusTipRole:
|
||||
case Qt::WhatsThisRole:
|
||||
if (!node->isLeaf())
|
||||
return tr(node->textCStr());
|
||||
else
|
||||
return node->text();
|
||||
return node->text();
|
||||
case Qt::CheckStateRole:
|
||||
if (node->isEnabled())
|
||||
return Qt::Checked;
|
||||
|
|
|
|||
49
cockatrice/src/game_specific_terms.h
Normal file
49
cockatrice/src/game_specific_terms.h
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef GAME_SPECIFIC_TERMS_H
|
||||
#define GAME_SPECIFIC_TERMS_H
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QString>
|
||||
|
||||
/*
|
||||
* Collection of traslatable property names used in games,
|
||||
* so we can use Game::Property instead of hardcoding strings.
|
||||
* Note: Mtg = "Maybe that game"
|
||||
*/
|
||||
|
||||
namespace Mtg
|
||||
{
|
||||
QString const CardType("type");
|
||||
QString const ConvertedManaCost("cmc");
|
||||
QString const Colors("colors");
|
||||
QString const Loyalty("loyalty");
|
||||
QString const MainCardType("maintype");
|
||||
QString const ManaCost("manacost");
|
||||
QString const PowTough("pt");
|
||||
QString const Side("side");
|
||||
QString const Layout("layout");
|
||||
|
||||
inline static const QString getNicePropertyName(QString key)
|
||||
{
|
||||
if (key == CardType)
|
||||
return QCoreApplication::translate("Mtg", "Card type");
|
||||
if (key == ConvertedManaCost)
|
||||
return QCoreApplication::translate("Mtg", "Converted mana cost");
|
||||
if (key == Colors)
|
||||
return QCoreApplication::translate("Mtg", "Color(s)");
|
||||
if (key == Loyalty)
|
||||
return QCoreApplication::translate("Mtg", "Loyalty");
|
||||
if (key == MainCardType)
|
||||
return QCoreApplication::translate("Mtg", "Main card type");
|
||||
if (key == ManaCost)
|
||||
return QCoreApplication::translate("Mtg", "Mana cost");
|
||||
if (key == PowTough)
|
||||
return QCoreApplication::translate("Mtg", "P / T");
|
||||
if (key == Side)
|
||||
return QCoreApplication::translate("Mtg", "Side");
|
||||
if (key == Layout)
|
||||
return QCoreApplication::translate("Mtg", "Layout");
|
||||
return key;
|
||||
}
|
||||
}; // namespace Mtg
|
||||
|
||||
#endif
|
||||
|
|
@ -40,7 +40,7 @@ void GameScene::addPlayer(Player *player)
|
|||
players << player;
|
||||
addItem(player);
|
||||
connect(player, SIGNAL(sizeChanged()), this, SLOT(rearrange()));
|
||||
connect(player, SIGNAL(gameConceded()), this, SLOT(rearrange()));
|
||||
connect(player, SIGNAL(playerCountChanged()), this, SLOT(rearrange()));
|
||||
}
|
||||
|
||||
void GameScene::removePlayer(Player *player)
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ GameView::GameView(QGraphicsScene *scene, QWidget *parent) : QGraphicsView(scene
|
|||
|
||||
connect(aCloseMostRecentZoneView, SIGNAL(triggered()), scene, SLOT(closeMostRecentZoneView()));
|
||||
addAction(aCloseMostRecentZoneView);
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()), this, SLOT(refreshShortcuts()));
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||
refreshShortcuts();
|
||||
rubberBand = new QRubberBand(QRubberBand::Rectangle, this);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#include "handle_public_servers.h"
|
||||
#include "qt-json/json.h"
|
||||
#include "settingscache.h"
|
||||
#include <QJsonDocument>
|
||||
#include <QMessageBox>
|
||||
#include <QNetworkAccessManager>
|
||||
#include <QNetworkReply>
|
||||
|
|
@ -31,19 +31,16 @@ void HandlePublicServers::actFinishParsingDownloadedData()
|
|||
savedHostList = uci.getServerInfo();
|
||||
|
||||
// Downloaded data from GitHub
|
||||
bool jsonSuccessful;
|
||||
QString jsonData = QString(reply->readAll());
|
||||
|
||||
auto jsonMap = QtJson::Json::parse(jsonData, jsonSuccessful).toMap();
|
||||
|
||||
if (jsonSuccessful) {
|
||||
QJsonParseError parseError{};
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
|
||||
if (parseError.error == QJsonParseError::NoError) {
|
||||
QVariantMap jsonMap = jsonResponse.toVariant().toMap();
|
||||
updateServerINISettings(jsonMap);
|
||||
} else {
|
||||
qDebug() << "[PUBLIC SERVER HANDLER]"
|
||||
<< "JSON Parsing Error";
|
||||
<< "JSON Parsing Error:" << parseError.errorString();
|
||||
emit sigPublicServersDownloadedUnsuccessfully(errorCode);
|
||||
}
|
||||
|
||||
} else {
|
||||
qDebug() << "[PUBLIC SERVER HANDLER]"
|
||||
<< "Error Downloading Public Servers" << errorCode;
|
||||
|
|
@ -74,6 +71,10 @@ void HandlePublicServers::updateServerINISettings(QMap<QString, QVariant> jsonMa
|
|||
QString serverPort = serverMap["port"].toString();
|
||||
QString serverSite = serverMap["site"].toString();
|
||||
|
||||
if (serverMap.contains("websocketPort")) {
|
||||
serverPort = serverMap["websocketPort"].toString();
|
||||
}
|
||||
|
||||
bool serverFound = false;
|
||||
for (const auto &iter : savedHostList) {
|
||||
// If the URL/IP matches
|
||||
|
|
|
|||
|
|
@ -156,7 +156,7 @@ void MessageLogWidget::logAlwaysRevealTopCard(Player *player, CardZone *zone, bo
|
|||
|
||||
void MessageLogWidget::logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName)
|
||||
{
|
||||
appendHtmlServerMessage(QString("%1 attaches %2 to %3's %4.")
|
||||
appendHtmlServerMessage(tr("%1 attaches %2 to %3's %4.")
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg(cardLink(cardName))
|
||||
.arg(sanitizeHtml(targetPlayer->getName()))
|
||||
|
|
@ -169,6 +169,12 @@ void MessageLogWidget::logConcede(Player *player)
|
|||
appendHtmlServerMessage(tr("%1 has conceded the game.").arg(sanitizeHtml(player->getName())), true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logUnconcede(Player *player)
|
||||
{
|
||||
soundEngine->playSound("player_concede");
|
||||
appendHtmlServerMessage(tr("%1 has unconceded the game.").arg(sanitizeHtml(player->getName())), true);
|
||||
}
|
||||
|
||||
void MessageLogWidget::logConnectionStateChanged(Player *player, bool connectionState)
|
||||
{
|
||||
if (connectionState) {
|
||||
|
|
@ -341,7 +347,7 @@ void MessageLogWidget::logDrawCards(Player *player, int number)
|
|||
mulliganPlayer = player;
|
||||
else {
|
||||
soundEngine->playSound("draw_card");
|
||||
appendHtmlServerMessage(tr("%1 draws %2 card(s).")
|
||||
appendHtmlServerMessage(tr("%1 draws %2 card(s).", "", number)
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg("<font color=\"blue\">" + QString::number(number) + "</font>"));
|
||||
}
|
||||
|
|
@ -354,10 +360,11 @@ void MessageLogWidget::logDumpZone(Player *player, CardZone *zone, int numberCar
|
|||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg(zone->getTranslatedName(zone->getPlayer() == player, CaseLookAtZone)));
|
||||
else
|
||||
appendHtmlServerMessage(tr("%1 is looking at the top %2 card(s) %3.")
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg("<font color=\"blue\">" + QString::number(numberCards) + "</font>")
|
||||
.arg(zone->getTranslatedName(zone->getPlayer() == player, CaseTopCardsOfZone)));
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 is looking at the top %3 card(s) %2.", "top card for singular, top %3 cards for plural", numberCards)
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg(zone->getTranslatedName(zone->getPlayer() == player, CaseTopCardsOfZone))
|
||||
.arg("<font color=\"blue\">" + QString::number(numberCards) + "</font>"));
|
||||
}
|
||||
|
||||
void MessageLogWidget::logFlipCard(Player *player, QString cardName, bool faceDown)
|
||||
|
|
@ -456,9 +463,11 @@ void MessageLogWidget::logRevealCards(Player *player,
|
|||
int cardId,
|
||||
QString cardName,
|
||||
Player *otherPlayer,
|
||||
bool faceDown)
|
||||
bool faceDown,
|
||||
int amount)
|
||||
{
|
||||
QPair<QString, QString> temp = getFromStr(zone, cardName, cardId, false);
|
||||
// getFromStr uses cardname.empty() to check if it should contain the start zone, it's not actually used
|
||||
QPair<QString, QString> temp = getFromStr(zone, amount == 1 ? cardName : QString::number(amount), cardId, false);
|
||||
bool cardNameContainsStartZone = false;
|
||||
if (!temp.first.isEmpty()) {
|
||||
cardNameContainsStartZone = true;
|
||||
|
|
@ -467,52 +476,61 @@ void MessageLogWidget::logRevealCards(Player *player,
|
|||
QString fromStr = temp.second;
|
||||
|
||||
QString cardStr;
|
||||
if (cardNameContainsStartZone)
|
||||
if (cardNameContainsStartZone) {
|
||||
cardStr = cardName;
|
||||
else if (cardName.isEmpty())
|
||||
cardStr = tr("a card");
|
||||
else
|
||||
} else if (cardName.isEmpty()) {
|
||||
if (amount == 0) {
|
||||
cardStr = tr("cards", "an unknown amount of cards");
|
||||
} else {
|
||||
cardStr = tr("%1 card(s)", "a card for singular, %1 cards for plural", amount)
|
||||
.arg("<font color=\"blue\">" + QString::number(amount) + "</font>");
|
||||
}
|
||||
} else {
|
||||
cardStr = cardLink(cardName);
|
||||
|
||||
}
|
||||
if (cardId == -1) {
|
||||
if (otherPlayer)
|
||||
if (otherPlayer) {
|
||||
appendHtmlServerMessage(tr("%1 reveals %2 to %3.")
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseRevealZone))
|
||||
.arg(sanitizeHtml(otherPlayer->getName())));
|
||||
else
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 reveals %2.")
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg(zone->getTranslatedName(true, CaseRevealZone)));
|
||||
}
|
||||
} else if (cardId == -2) {
|
||||
if (otherPlayer)
|
||||
if (otherPlayer) {
|
||||
appendHtmlServerMessage(tr("%1 randomly reveals %2%3 to %4.")
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg(cardStr)
|
||||
.arg(fromStr)
|
||||
.arg(sanitizeHtml(otherPlayer->getName())));
|
||||
else
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 randomly reveals %2%3.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr));
|
||||
}
|
||||
} else {
|
||||
if (faceDown && player == otherPlayer) {
|
||||
if (cardName.isEmpty())
|
||||
if (cardName.isEmpty()) {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 peeks at face down card #%2.").arg(sanitizeHtml(player->getName())).arg(cardId));
|
||||
else
|
||||
} else {
|
||||
appendHtmlServerMessage(tr("%1 peeks at face down card #%2: %3.")
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg(cardId)
|
||||
.arg(cardStr));
|
||||
} else if (otherPlayer)
|
||||
}
|
||||
} else if (otherPlayer) {
|
||||
appendHtmlServerMessage(tr("%1 reveals %2%3 to %4.")
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg(cardStr)
|
||||
.arg(fromStr)
|
||||
.arg(sanitizeHtml(otherPlayer->getName())));
|
||||
else
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 reveals %2%3.").arg(sanitizeHtml(player->getName())).arg(cardStr).arg(fromStr));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -626,20 +644,20 @@ void MessageLogWidget::logSetCardCounter(Player *player, QString cardName, int c
|
|||
QString finalStr;
|
||||
int delta = abs(oldValue - value);
|
||||
if (value > oldValue)
|
||||
finalStr = tr("%1 places %2 %3 counter(s) on %4 (now %5).");
|
||||
finalStr = tr("%1 places %2 %3 on %4 (now %5).");
|
||||
else
|
||||
finalStr = tr("%1 removes %2 %3 counter(s) from %4 (now %5).");
|
||||
finalStr = tr("%1 removes %2 %3 from %4 (now %5).");
|
||||
|
||||
QString colorStr;
|
||||
switch (counterId) {
|
||||
case 0:
|
||||
colorStr = tr("red", "", delta);
|
||||
colorStr = tr("red counter(s)", "", delta);
|
||||
break;
|
||||
case 1:
|
||||
colorStr = tr("yellow", "", delta);
|
||||
colorStr = tr("yellow counter(s)", "", delta);
|
||||
break;
|
||||
case 2:
|
||||
colorStr = tr("green", "", delta);
|
||||
colorStr = tr("green counter(s)", "", delta);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
|
|
@ -676,13 +694,22 @@ void MessageLogWidget::logSetDoesntUntap(Player *player, CardItem *card, bool do
|
|||
|
||||
void MessageLogWidget::logSetPT(Player *player, CardItem *card, QString newPT)
|
||||
{
|
||||
if (currentContext == MessageContext_MoveCard)
|
||||
if (currentContext == MessageContext_MoveCard) {
|
||||
moveCardPT.insert(card, newPT);
|
||||
else
|
||||
appendHtmlServerMessage(tr("%1 sets PT of %2 to %3.")
|
||||
.arg(sanitizeHtml(player->getName()))
|
||||
.arg(cardLink(card->getName()))
|
||||
.arg(QString("<font color=\"blue\">%1</font>").arg(sanitizeHtml(newPT))));
|
||||
} else {
|
||||
QString name = card->getName();
|
||||
if (name.isEmpty()) {
|
||||
name = QString("<font color=\"blue\">card #%1</font>").arg(sanitizeHtml(QString::number(card->getId())));
|
||||
} else {
|
||||
name = cardLink(name);
|
||||
}
|
||||
if (newPT.isEmpty()) {
|
||||
appendHtmlServerMessage(tr("%1 removes the PT of %2.").arg(sanitizeHtml(player->getName())).arg(name));
|
||||
} else {
|
||||
appendHtmlServerMessage(
|
||||
tr("%1 sets PT of %2 to %3.").arg(sanitizeHtml(player->getName())).arg(name).arg(newPT));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageLogWidget::logSetSideboardLock(Player *player, bool locked)
|
||||
|
|
@ -786,8 +813,8 @@ void MessageLogWidget::connectToPlayer(Player *player)
|
|||
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(logUndoDraw(Player *, QString)), this, SLOT(logUndoDraw(Player *, QString)));
|
||||
connect(player, SIGNAL(logRevealCards(Player *, CardZone *, int, QString, Player *, bool)), this,
|
||||
SLOT(logRevealCards(Player *, CardZone *, int, QString, Player *, bool)));
|
||||
connect(player, SIGNAL(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int)), this,
|
||||
SLOT(logRevealCards(Player *, CardZone *, int, QString, Player *, bool, int)));
|
||||
connect(player, SIGNAL(logAlwaysRevealTopCard(Player *, CardZone *, bool)), this,
|
||||
SLOT(logAlwaysRevealTopCard(Player *, CardZone *, bool)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ private:
|
|||
const QString stackConstant() const;
|
||||
|
||||
QString sanitizeHtml(QString dirty) const;
|
||||
QString cardLink(const QString cardName) const;
|
||||
QString cardLink(QString cardName) const;
|
||||
QPair<QString, QString> getFromStr(CardZone *zone, QString cardName, int position, bool ownerChange) const;
|
||||
|
||||
public slots:
|
||||
|
|
@ -57,6 +57,7 @@ public slots:
|
|||
void logAlwaysRevealTopCard(Player *player, CardZone *zone, bool reveal);
|
||||
void logAttachCard(Player *player, QString cardName, Player *targetPlayer, QString targetCardName);
|
||||
void logConcede(Player *player);
|
||||
void logUnconcede(Player *player);
|
||||
void logConnectionStateChanged(Player *player, bool connectionState);
|
||||
void logCreateArrow(Player *player,
|
||||
Player *startPlayer,
|
||||
|
|
@ -83,8 +84,13 @@ public slots:
|
|||
void logMulligan(Player *player, int number);
|
||||
void logReplayStarted(int gameId);
|
||||
void logReadyStart(Player *player);
|
||||
void
|
||||
logRevealCards(Player *player, CardZone *zone, int cardId, QString cardName, Player *otherPlayer, bool faceDown);
|
||||
void logRevealCards(Player *player,
|
||||
CardZone *zone,
|
||||
int cardId,
|
||||
QString cardName,
|
||||
Player *otherPlayer,
|
||||
bool faceDown,
|
||||
int amount);
|
||||
void logRollDie(Player *player, int sides, int roll);
|
||||
void logSay(Player *player, QString message);
|
||||
void logSetActivePhase(int phase);
|
||||
|
|
@ -108,7 +114,7 @@ public:
|
|||
MessageLogWidget(const TabSupervisor *_tabSupervisor,
|
||||
const UserlistProxy *_userlistProxy,
|
||||
TabGame *_game,
|
||||
QWidget *parent = 0);
|
||||
QWidget *parent = nullptr);
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -24,14 +24,14 @@ PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_
|
|||
connect(activeAnimationTimer, SIGNAL(timeout()), this, SLOT(updateAnimation()));
|
||||
activeAnimationTimer->setSingleShot(false);
|
||||
} else
|
||||
activeAnimationCounter = 9.0;
|
||||
activeAnimationCounter = 9;
|
||||
|
||||
setCacheMode(DeviceCoordinateCache);
|
||||
}
|
||||
|
||||
QRectF PhaseButton::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, width, width);
|
||||
return {0, 0, width, width};
|
||||
}
|
||||
|
||||
void PhaseButton::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/)
|
||||
|
|
@ -39,21 +39,24 @@ void PhaseButton::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*op
|
|||
QRectF iconRect = boundingRect().adjusted(3, 3, -3, -3);
|
||||
QRectF translatedIconRect = painter->combinedTransform().mapRect(iconRect);
|
||||
qreal scaleFactor = translatedIconRect.width() / iconRect.width();
|
||||
QPixmap iconPixmap = PhasePixmapGenerator::generatePixmap(round(translatedIconRect.height()), name);
|
||||
QPixmap iconPixmap =
|
||||
PhasePixmapGenerator::generatePixmap(static_cast<int>(round(translatedIconRect.height())), name);
|
||||
|
||||
painter->setBrush(QColor(220 * (activeAnimationCounter / 10.0), 220 * (activeAnimationCounter / 10.0),
|
||||
220 * (activeAnimationCounter / 10.0)));
|
||||
painter->setBrush(QColor(static_cast<int>(220 * (activeAnimationCounter / 10.0)),
|
||||
static_cast<int>(220 * (activeAnimationCounter / 10.0)),
|
||||
static_cast<int>(220 * (activeAnimationCounter / 10.0))));
|
||||
painter->setPen(Qt::gray);
|
||||
painter->drawRect(0, 0, width - 1, width - 1);
|
||||
painter->drawRect(0, 0, static_cast<int>(width - 1), static_cast<int>(width - 1));
|
||||
painter->save();
|
||||
painter->resetTransform();
|
||||
painter->drawPixmap(iconPixmap.rect().translated(round(3 * scaleFactor), round(3 * scaleFactor)), iconPixmap,
|
||||
iconPixmap.rect());
|
||||
painter->drawPixmap(iconPixmap.rect().translated(static_cast<int>(round(3 * scaleFactor)),
|
||||
static_cast<int>(round(3 * scaleFactor))),
|
||||
iconPixmap, iconPixmap.rect());
|
||||
painter->restore();
|
||||
|
||||
painter->setBrush(QColor(0, 0, 0, 255 * ((10 - activeAnimationCounter) / 15.0)));
|
||||
painter->setBrush(QColor(0, 0, 0, static_cast<int>(255 * ((10 - activeAnimationCounter) / 15.0))));
|
||||
painter->setPen(Qt::gray);
|
||||
painter->drawRect(0, 0, width - 1, width - 1);
|
||||
painter->drawRect(0, 0, static_cast<int>(width - 1), static_cast<int>(width - 1));
|
||||
}
|
||||
|
||||
void PhaseButton::setWidth(double _width)
|
||||
|
|
@ -105,9 +108,9 @@ void PhaseButton::triggerDoubleClickAction()
|
|||
PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
|
||||
: QGraphicsItem(parent), width(100), height(100), ySpacing(1), symbolSize(8)
|
||||
{
|
||||
QAction *aUntapAll = new QAction(this);
|
||||
auto *aUntapAll = new QAction(this);
|
||||
connect(aUntapAll, SIGNAL(triggered()), this, SLOT(actUntapAll()));
|
||||
QAction *aDrawCard = new QAction(this);
|
||||
auto *aDrawCard = new QAction(this);
|
||||
connect(aDrawCard, SIGNAL(triggered()), this, SLOT(actDrawCard()));
|
||||
|
||||
PhaseButton *untapButton = new PhaseButton("untap", this, aUntapAll);
|
||||
|
|
@ -125,10 +128,10 @@ PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
|
|||
buttonList << untapButton << upkeepButton << drawButton << main1Button << combatStartButton << combatAttackersButton
|
||||
<< combatBlockersButton << combatDamageButton << combatEndButton << main2Button << cleanupButton;
|
||||
|
||||
for (int i = 0; i < buttonList.size(); ++i)
|
||||
connect(buttonList[i], SIGNAL(clicked()), this, SLOT(phaseButtonClicked()));
|
||||
for (auto &i : buttonList)
|
||||
connect(i, SIGNAL(clicked()), this, SLOT(phaseButtonClicked()));
|
||||
|
||||
nextTurnButton = new PhaseButton("nextturn", this, 0, false);
|
||||
nextTurnButton = new PhaseButton("nextturn", this, nullptr, false);
|
||||
connect(nextTurnButton, SIGNAL(clicked()), this, SLOT(actNextTurn()));
|
||||
|
||||
rearrangeButtons();
|
||||
|
|
@ -138,7 +141,7 @@ PhasesToolbar::PhasesToolbar(QGraphicsItem *parent)
|
|||
|
||||
QRectF PhasesToolbar::boundingRect() const
|
||||
{
|
||||
return QRectF(0, 0, width, height);
|
||||
return {0, 0, width, height};
|
||||
}
|
||||
|
||||
void PhasesToolbar::retranslateUi()
|
||||
|
|
@ -186,8 +189,8 @@ const double PhasesToolbar::marginSize = 3;
|
|||
|
||||
void PhasesToolbar::rearrangeButtons()
|
||||
{
|
||||
for (int i = 0; i < buttonList.size(); ++i)
|
||||
buttonList[i]->setWidth(symbolSize);
|
||||
for (auto &i : buttonList)
|
||||
i->setWidth(symbolSize);
|
||||
nextTurnButton->setWidth(symbolSize);
|
||||
|
||||
double y = marginSize;
|
||||
|
|
@ -208,7 +211,7 @@ void PhasesToolbar::rearrangeButtons()
|
|||
buttonList[10]->setPos(marginSize, y += symbolSize);
|
||||
y += ySpacing;
|
||||
y += ySpacing;
|
||||
nextTurnButton->setPos(marginSize, y += symbolSize);
|
||||
nextTurnButton->setPos(marginSize, y + symbolSize);
|
||||
}
|
||||
|
||||
void PhasesToolbar::setHeight(double _height)
|
||||
|
|
@ -232,14 +235,21 @@ void PhasesToolbar::setActivePhase(int phase)
|
|||
buttonList[i]->setActive(i == phase);
|
||||
}
|
||||
|
||||
void PhasesToolbar::triggerPhaseAction(int phase)
|
||||
{
|
||||
if (0 <= phase && phase < buttonList.size()) {
|
||||
buttonList[phase]->triggerDoubleClickAction();
|
||||
}
|
||||
}
|
||||
|
||||
void PhasesToolbar::phaseButtonClicked()
|
||||
{
|
||||
PhaseButton *button = qobject_cast<PhaseButton *>(sender());
|
||||
auto *button = qobject_cast<PhaseButton *>(sender());
|
||||
if (button->getActive())
|
||||
button->triggerDoubleClickAction();
|
||||
|
||||
Command_SetActivePhase cmd;
|
||||
cmd.set_phase(buttonList.indexOf(button));
|
||||
cmd.set_phase(static_cast<google::protobuf::uint32>(buttonList.indexOf(button)));
|
||||
|
||||
emit sendGameCommand(cmd, -1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,16 +27,16 @@ private:
|
|||
QAction *doubleClickAction;
|
||||
double width;
|
||||
|
||||
void updatePixmap(QPixmap &pixmap);
|
||||
// void updatePixmap(QPixmap &pixmap);
|
||||
private slots:
|
||||
void updateAnimation();
|
||||
|
||||
public:
|
||||
PhaseButton(const QString &_name,
|
||||
QGraphicsItem *parent = 0,
|
||||
QAction *_doubleClickAction = 0,
|
||||
bool _highlightable = true);
|
||||
QRectF boundingRect() const;
|
||||
explicit PhaseButton(const QString &_name,
|
||||
QGraphicsItem *parent = nullptr,
|
||||
QAction *_doubleClickAction = nullptr,
|
||||
bool _highlightable = true);
|
||||
QRectF boundingRect() const override;
|
||||
void setWidth(double _width);
|
||||
void setActive(bool _active);
|
||||
bool getActive() const
|
||||
|
|
@ -48,9 +48,9 @@ signals:
|
|||
void clicked();
|
||||
|
||||
protected:
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/);
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event);
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event);
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) override;
|
||||
void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||
};
|
||||
|
||||
class PhasesToolbar : public QObject, public QGraphicsItem
|
||||
|
|
@ -67,8 +67,8 @@ private:
|
|||
void rearrangeButtons();
|
||||
|
||||
public:
|
||||
PhasesToolbar(QGraphicsItem *parent = 0);
|
||||
QRectF boundingRect() const;
|
||||
explicit PhasesToolbar(QGraphicsItem *parent = nullptr);
|
||||
QRectF boundingRect() const override;
|
||||
void retranslateUi();
|
||||
void setHeight(double _height);
|
||||
double getWidth() const
|
||||
|
|
@ -82,6 +82,7 @@ public:
|
|||
QString getLongPhaseName(int phase) const;
|
||||
public slots:
|
||||
void setActivePhase(int phase);
|
||||
void triggerPhaseAction(int phase);
|
||||
private slots:
|
||||
void phaseButtonClicked();
|
||||
void actNextTurn();
|
||||
|
|
@ -91,7 +92,7 @@ signals:
|
|||
void sendGameCommand(const ::google::protobuf::Message &command, int playerId);
|
||||
|
||||
protected:
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/);
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem * /*option*/, QWidget * /*widget*/) override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -25,32 +25,14 @@
|
|||
// never cache more than 300 cards at once for a single deck
|
||||
#define CACHED_CARD_PER_DECK_MAX 300
|
||||
|
||||
class PictureToLoad::SetDownloadPriorityComparator
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Returns true if a has higher download priority than b
|
||||
* Enabled sets have priority over disabled sets
|
||||
* Both groups follows the user-defined order
|
||||
*/
|
||||
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
|
||||
{
|
||||
if (a->getEnabled()) {
|
||||
return !b->getEnabled() || a->getSortKey() < b->getSortKey();
|
||||
} else {
|
||||
return !b->getEnabled() && a->getSortKey() < b->getSortKey();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
PictureToLoad::PictureToLoad(CardInfoPtr _card) : card(std::move(_card))
|
||||
{
|
||||
/* #2479 will expand this into a list of Urls */
|
||||
urlTemplates.append(settingsCache->getPicUrl());
|
||||
urlTemplates.append(settingsCache->getPicUrlFallback());
|
||||
urlTemplates = settingsCache->downloads().getAllURLs();
|
||||
|
||||
if (card) {
|
||||
sortedSets = card->getSets();
|
||||
for (const auto &set : card->getSets()) {
|
||||
sortedSets << set.getPtr();
|
||||
}
|
||||
qSort(sortedSets.begin(), sortedSets.end(), SetDownloadPriorityComparator());
|
||||
// The first time called, nextSet will also populate the Urls for the first set.
|
||||
nextSet();
|
||||
|
|
@ -72,7 +54,7 @@ void PictureToLoad::populateSetUrls()
|
|||
}
|
||||
}
|
||||
|
||||
foreach (QString urlTemplate, urlTemplates) {
|
||||
for (const QString &urlTemplate : urlTemplates) {
|
||||
QString transformedUrl = transformUrl(urlTemplate);
|
||||
|
||||
if (!transformedUrl.isEmpty()) {
|
||||
|
|
@ -115,10 +97,8 @@ QString PictureToLoad::getSetName() const
|
|||
}
|
||||
}
|
||||
|
||||
QStringList PictureLoaderWorker::md5Blacklist = QStringList()
|
||||
<< "db0c48db407a907c16ade38de048a441"; // card back returned
|
||||
// by gatherer when
|
||||
// card is not found
|
||||
// Card back returned by gatherer when card is not found
|
||||
QStringList PictureLoaderWorker::md5Blacklist = QStringList() << "db0c48db407a907c16ade38de048a441";
|
||||
|
||||
PictureLoaderWorker::PictureLoaderWorker() : QObject(nullptr), downloadRunning(false), loadQueueRunning(false)
|
||||
{
|
||||
|
|
@ -145,12 +125,12 @@ PictureLoaderWorker::~PictureLoaderWorker()
|
|||
|
||||
void PictureLoaderWorker::processLoadQueue()
|
||||
{
|
||||
if (loadQueueRunning)
|
||||
if (loadQueueRunning) {
|
||||
return;
|
||||
}
|
||||
|
||||
loadQueueRunning = true;
|
||||
forever
|
||||
{
|
||||
while (true) {
|
||||
mutex.lock();
|
||||
if (loadQueue.isEmpty()) {
|
||||
mutex.unlock();
|
||||
|
|
@ -163,23 +143,26 @@ void PictureLoaderWorker::processLoadQueue()
|
|||
QString setName = cardBeingLoaded.getSetName();
|
||||
QString cardName = cardBeingLoaded.getCard()->getName();
|
||||
QString correctedCardName = cardBeingLoaded.getCard()->getCorrectedName();
|
||||
|
||||
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName << "]: Trying to load picture";
|
||||
|
||||
if (cardImageExistsOnDisk(setName, correctedCardName))
|
||||
if (cardImageExistsOnDisk(setName, correctedCardName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (picDownload) {
|
||||
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
|
||||
<< "]: Picture not found on disk, trying to download";
|
||||
cardsToDownload.append(cardBeingLoaded);
|
||||
cardBeingLoaded.clear();
|
||||
if (!downloadRunning)
|
||||
if (!downloadRunning) {
|
||||
startNextPicDownload();
|
||||
}
|
||||
} else {
|
||||
if (cardBeingLoaded.nextSet()) {
|
||||
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
|
||||
<< "]: Picture NOT found and download disabled, moving to next "
|
||||
"set (newset: "
|
||||
"set (new set: "
|
||||
<< setName << " card: " << cardName << ")";
|
||||
mutex.lock();
|
||||
loadQueue.prepend(cardBeingLoaded);
|
||||
|
|
@ -188,7 +171,7 @@ void PictureLoaderWorker::processLoadQueue()
|
|||
} else {
|
||||
qDebug() << "PictureLoader: [card: " << cardName << " set: " << setName
|
||||
<< "]: Picture NOT found, download disabled, no more sets to "
|
||||
"try: BAILING OUT (oldset: "
|
||||
"try: BAILING OUT (old set: "
|
||||
<< setName << " card: " << cardName << ")";
|
||||
imageLoaded(cardBeingLoaded.getCard(), QImage());
|
||||
}
|
||||
|
|
@ -221,22 +204,22 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
|
|||
// Iterates through the list of paths, searching for images with the desired
|
||||
// name with any QImageReader-supported
|
||||
// extension
|
||||
for (int i = 0; i < picsPaths.length(); i++) {
|
||||
imgReader.setFileName(picsPaths.at(i));
|
||||
for (const auto &picsPath : picsPaths) {
|
||||
imgReader.setFileName(picsPath);
|
||||
if (imgReader.read(&image)) {
|
||||
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
|
||||
<< "]: Picture found on disk.";
|
||||
imageLoaded(cardBeingLoaded.getCard(), image);
|
||||
return true;
|
||||
}
|
||||
imgReader.setFileName(picsPaths.at(i) + ".full");
|
||||
imgReader.setFileName(picsPath + ".full");
|
||||
if (imgReader.read(&image)) {
|
||||
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
|
||||
<< "]: Picture.full found on disk.";
|
||||
imageLoaded(cardBeingLoaded.getCard(), image);
|
||||
return true;
|
||||
}
|
||||
imgReader.setFileName(picsPaths.at(i) + ".xlhq");
|
||||
imgReader.setFileName(picsPath + ".xlhq");
|
||||
if (imgReader.read(&image)) {
|
||||
qDebug() << "PictureLoader: [card: " << correctedCardname << " set: " << setName
|
||||
<< "]: Picture.xlhq found on disk.";
|
||||
|
|
@ -248,7 +231,7 @@ bool PictureLoaderWorker::cardImageExistsOnDisk(QString &setName, QString &corre
|
|||
return false;
|
||||
}
|
||||
|
||||
QString PictureToLoad::transformUrl(QString urlTemplate) const
|
||||
QString PictureToLoad::transformUrl(const QString &urlTemplate) const
|
||||
{
|
||||
/* This function takes Url templates and substitutes actual card details
|
||||
into the url. This is used for making Urls with follow a predictable format
|
||||
|
|
@ -259,29 +242,53 @@ QString PictureToLoad::transformUrl(QString urlTemplate) const
|
|||
CardSetPtr set = getCurrentSet();
|
||||
|
||||
QMap<QString, QString> transformMap = QMap<QString, QString>();
|
||||
|
||||
// name
|
||||
transformMap["!name!"] = card->getName();
|
||||
transformMap["!name_lower!"] = card->getName().toLower();
|
||||
transformMap["!corrected_name!"] = card->getCorrectedName();
|
||||
transformMap["!corrected_name_lower!"] = card->getCorrectedName().toLower();
|
||||
|
||||
// card properties
|
||||
QRegExp rxCardProp("!prop:([^!]+)!");
|
||||
int pos = 0;
|
||||
while ((pos = rxCardProp.indexIn(transformedUrl, pos)) != -1) {
|
||||
QString propertyName = rxCardProp.cap(1);
|
||||
pos += rxCardProp.matchedLength();
|
||||
QString propertyValue = card->getProperty(propertyName);
|
||||
if (propertyValue.isEmpty()) {
|
||||
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
|
||||
<< "]: Requested property (" << propertyName << ") for Url template (" << urlTemplate
|
||||
<< ") is not available";
|
||||
return QString();
|
||||
} else {
|
||||
transformMap["!prop:" + propertyName + "!"] = propertyValue;
|
||||
}
|
||||
}
|
||||
|
||||
if (set) {
|
||||
transformMap["!cardid!"] = QString::number(card->getMuId(set->getShortName()));
|
||||
transformMap["!collectornumber!"] = card->getCollectorNumber(set->getShortName());
|
||||
transformMap["!setcode!"] = set->getShortName();
|
||||
transformMap["!setcode_lower!"] = set->getShortName().toLower();
|
||||
transformMap["!setname!"] = set->getLongName();
|
||||
transformMap["!setname_lower!"] = set->getLongName().toLower();
|
||||
} else {
|
||||
transformMap["!cardid!"] = QString();
|
||||
transformMap["!collectornumber!"] = QString();
|
||||
transformMap["!setcode!"] = QString();
|
||||
transformMap["!setcode_lower!"] = QString();
|
||||
transformMap["!setname!"] = QString();
|
||||
transformMap["!setname_lower!"] = QString();
|
||||
|
||||
QRegExp rxSetProp("!set:([^!]+)!");
|
||||
pos = 0; // Defined above
|
||||
while ((pos = rxSetProp.indexIn(transformedUrl, pos)) != -1) {
|
||||
QString propertyName = rxSetProp.cap(1);
|
||||
pos += rxSetProp.matchedLength();
|
||||
QString propertyValue = card->getSetProperty(set->getShortName(), propertyName);
|
||||
if (propertyValue.isEmpty()) {
|
||||
qDebug() << "PictureLoader: [card: " << card->getName() << " set: " << getSetName()
|
||||
<< "]: Requested set property (" << propertyName << ") for Url template (" << urlTemplate
|
||||
<< ") is not available";
|
||||
return QString();
|
||||
} else {
|
||||
transformMap["!set:" + propertyName + "!"] = propertyValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (QString prop, transformMap.keys()) {
|
||||
for (const QString &prop : transformMap.keys()) {
|
||||
if (transformedUrl.contains(prop)) {
|
||||
if (!transformMap[prop].isEmpty()) {
|
||||
transformedUrl.replace(prop, QUrl::toPercentEncoding(transformMap[prop]));
|
||||
|
|
@ -372,8 +379,8 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
|
|||
return;
|
||||
}
|
||||
|
||||
const QByteArray &picData = reply->peek(reply->size()); // peek is used to keep the data in the buffer
|
||||
// for use by QImageReader
|
||||
// peek is used to keep the data in the buffer for use by QImageReader
|
||||
const QByteArray &picData = reply->peek(reply->size());
|
||||
|
||||
if (imageIsBlackListed(picData)) {
|
||||
qDebug() << "PictureLoader: [card: " << cardBeingDownloaded.getCard()->getName()
|
||||
|
|
@ -395,8 +402,9 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
|
|||
// prior to reading the
|
||||
// QImageReader data
|
||||
// into a QImage object, as that wipes the QImageReader buffer
|
||||
if (extension == ".jpeg")
|
||||
if (extension == ".jpeg") {
|
||||
extension = ".jpg";
|
||||
}
|
||||
|
||||
if (imgReader.read(&testImage)) {
|
||||
QString setName = cardBeingDownloaded.getSetName();
|
||||
|
|
@ -410,8 +418,9 @@ void PictureLoaderWorker::picDownloadFinished(QNetworkReply *reply)
|
|||
|
||||
QFile newPic(picsPath + "/downloadedPics/" + setName + "/" +
|
||||
cardBeingDownloaded.getCard()->getCorrectedName() + extension);
|
||||
if (!newPic.open(QIODevice::WriteOnly))
|
||||
if (!newPic.open(QIODevice::WriteOnly)) {
|
||||
return;
|
||||
}
|
||||
newPic.write(picData);
|
||||
newPic.close();
|
||||
}
|
||||
|
|
@ -436,15 +445,16 @@ void PictureLoaderWorker::enqueueImageLoad(CardInfoPtr card)
|
|||
QMutexLocker locker(&mutex);
|
||||
|
||||
// avoid queueing the same card more than once
|
||||
if (!card || card == cardBeingLoaded.getCard() || card == cardBeingDownloaded.getCard())
|
||||
if (!card || card == cardBeingLoaded.getCard() || card == cardBeingDownloaded.getCard()) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (PictureToLoad pic, loadQueue) {
|
||||
for (const PictureToLoad &pic : loadQueue) {
|
||||
if (pic.getCard() == card)
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (PictureToLoad pic, cardsToDownload) {
|
||||
for (const PictureToLoad &pic : cardsToDownload) {
|
||||
if (pic.getCard() == card)
|
||||
return;
|
||||
}
|
||||
|
|
@ -466,7 +476,7 @@ void PictureLoaderWorker::picsPathChanged()
|
|||
customPicsPath = settingsCache->getCustomPicsPath();
|
||||
}
|
||||
|
||||
PictureLoader::PictureLoader() : QObject(0)
|
||||
PictureLoader::PictureLoader() : QObject(nullptr)
|
||||
{
|
||||
worker = new PictureLoaderWorker;
|
||||
connect(settingsCache, SIGNAL(picsPathChanged()), this, SLOT(picsPathChanged()));
|
||||
|
|
@ -493,20 +503,21 @@ void PictureLoader::getCardBackPixmap(QPixmap &pixmap, QSize size)
|
|||
|
||||
void PictureLoader::getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size)
|
||||
{
|
||||
if (card == nullptr)
|
||||
if (card == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// search for an exact size copy of the picure in cache
|
||||
// search for an exact size copy of the picture in cache
|
||||
QString key = card->getPixmapCacheKey();
|
||||
QString sizekey = key + QLatin1Char('_') + QString::number(size.width()) + QString::number(size.height());
|
||||
if (QPixmapCache::find(sizekey, &pixmap))
|
||||
QString sizeKey = key + QLatin1Char('_') + QString::number(size.width()) + QString::number(size.height());
|
||||
if (QPixmapCache::find(sizeKey, &pixmap))
|
||||
return;
|
||||
|
||||
// load the image and create a copy of the correct size
|
||||
QPixmap bigPixmap;
|
||||
if (QPixmapCache::find(key, &bigPixmap)) {
|
||||
pixmap = bigPixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
QPixmapCache::insert(sizekey, pixmap);
|
||||
QPixmapCache::insert(sizeKey, pixmap);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -532,8 +543,9 @@ void PictureLoader::imageLoaded(CardInfoPtr card, const QImage &image)
|
|||
|
||||
void PictureLoader::clearPixmapCache(CardInfoPtr card)
|
||||
{
|
||||
if (card)
|
||||
if (card) {
|
||||
QPixmapCache::remove(card->getPixmapCacheKey());
|
||||
}
|
||||
}
|
||||
|
||||
void PictureLoader::clearPixmapCache()
|
||||
|
|
@ -546,13 +558,15 @@ void PictureLoader::cacheCardPixmaps(QList<CardInfoPtr> cards)
|
|||
QPixmap tmp;
|
||||
int max = qMin(cards.size(), CACHED_CARD_PER_DECK_MAX);
|
||||
for (int i = 0; i < max; ++i) {
|
||||
CardInfoPtr card = cards.at(i);
|
||||
if (!card)
|
||||
const CardInfoPtr &card = cards.at(i);
|
||||
if (!card) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QString key = card->getPixmapCacheKey();
|
||||
if (QPixmapCache::find(key, &tmp))
|
||||
if (QPixmapCache::find(key, &tmp)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
getInstance().worker->enqueueImageLoad(card);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,23 @@ class QThread;
|
|||
class PictureToLoad
|
||||
{
|
||||
private:
|
||||
class SetDownloadPriorityComparator;
|
||||
class SetDownloadPriorityComparator
|
||||
{
|
||||
public:
|
||||
/*
|
||||
* Returns true if a has higher download priority than b
|
||||
* Enabled sets have priority over disabled sets
|
||||
* Both groups follows the user-defined order
|
||||
*/
|
||||
inline bool operator()(const CardSetPtr &a, const CardSetPtr &b) const
|
||||
{
|
||||
if (a->getEnabled()) {
|
||||
return !b->getEnabled() || a->getSortKey() < b->getSortKey();
|
||||
} else {
|
||||
return !b->getEnabled() && a->getSortKey() < b->getSortKey();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CardInfoPtr card;
|
||||
QList<CardSetPtr> sortedSets;
|
||||
|
|
@ -24,7 +40,8 @@ private:
|
|||
CardSetPtr currentSet;
|
||||
|
||||
public:
|
||||
PictureToLoad(CardInfoPtr _card = CardInfoPtr());
|
||||
explicit PictureToLoad(CardInfoPtr _card = CardInfoPtr());
|
||||
|
||||
CardInfoPtr getCard() const
|
||||
{
|
||||
return card;
|
||||
|
|
@ -42,7 +59,7 @@ public:
|
|||
return currentSet;
|
||||
}
|
||||
QString getSetName() const;
|
||||
QString transformUrl(QString urlTemplate) const;
|
||||
QString transformUrl(const QString &urlTemplate) const;
|
||||
bool nextSet();
|
||||
bool nextUrl();
|
||||
void populateSetUrls();
|
||||
|
|
@ -52,8 +69,8 @@ class PictureLoaderWorker : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
PictureLoaderWorker();
|
||||
~PictureLoaderWorker();
|
||||
explicit PictureLoaderWorker();
|
||||
~PictureLoaderWorker() override;
|
||||
|
||||
void enqueueImageLoad(CardInfoPtr card);
|
||||
|
||||
|
|
@ -70,8 +87,8 @@ private:
|
|||
PictureToLoad cardBeingDownloaded;
|
||||
bool picDownload, downloadRunning, loadQueueRunning;
|
||||
void startNextPicDownload();
|
||||
bool cardImageExistsOnDisk(QString &setName, QString &correctedCardname);
|
||||
bool imageIsBlackListed(const QByteArray &picData);
|
||||
bool cardImageExistsOnDisk(QString &, QString &);
|
||||
bool imageIsBlackListed(const QByteArray &);
|
||||
private slots:
|
||||
void picDownloadFinished(QNetworkReply *reply);
|
||||
void picDownloadFailed();
|
||||
|
|
@ -96,8 +113,8 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
PictureLoader();
|
||||
~PictureLoader();
|
||||
explicit PictureLoader();
|
||||
~PictureLoader() override;
|
||||
// Singleton - Don't implement copy constructor and assign operator
|
||||
PictureLoader(PictureLoader const &);
|
||||
void operator=(PictureLoader const &);
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -40,7 +40,7 @@ class CommandContainer;
|
|||
class GameCommand;
|
||||
class GameEvent;
|
||||
class GameEventContext;
|
||||
class Event_ConnectionStateChanged;
|
||||
// class Event_ConnectionStateChanged;
|
||||
class Event_GameSay;
|
||||
class Event_Shuffle;
|
||||
class Event_RollDie;
|
||||
|
|
@ -79,17 +79,17 @@ public:
|
|||
{
|
||||
Type = typeOther
|
||||
};
|
||||
int type() const
|
||||
int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
|
||||
PlayerArea(QGraphicsItem *parent = 0);
|
||||
QRectF boundingRect() const
|
||||
explicit PlayerArea(QGraphicsItem *parent = nullptr);
|
||||
QRectF boundingRect() const override
|
||||
{
|
||||
return bRect;
|
||||
}
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
|
||||
void setSize(qreal width, qreal height);
|
||||
};
|
||||
|
|
@ -127,12 +127,17 @@ signals:
|
|||
void logSetAnnotation(Player *player, CardItem *card, QString newAnnotation);
|
||||
void logDumpZone(Player *player, CardZone *zone, int numberCards);
|
||||
void logStopDumpZone(Player *player, CardZone *zone);
|
||||
void
|
||||
logRevealCards(Player *player, CardZone *zone, int cardId, QString cardName, Player *otherPlayer, bool faceDown);
|
||||
void logRevealCards(Player *player,
|
||||
CardZone *zone,
|
||||
int cardId,
|
||||
QString cardName,
|
||||
Player *otherPlayer,
|
||||
bool faceDown,
|
||||
int amount);
|
||||
void logAlwaysRevealTopCard(Player *player, CardZone *zone, bool reveal);
|
||||
|
||||
void sizeChanged();
|
||||
void gameConceded();
|
||||
void playerCountChanged();
|
||||
public slots:
|
||||
void actUntapAll();
|
||||
void actRollDie();
|
||||
|
|
@ -144,6 +149,8 @@ public slots:
|
|||
void actUndoDraw();
|
||||
void actMulligan();
|
||||
void actMoveTopCardToPlayFaceDown();
|
||||
void actMoveTopCardToGrave();
|
||||
void actMoveTopCardToExile();
|
||||
void actMoveTopCardsToGrave();
|
||||
void actMoveTopCardsToExile();
|
||||
void actMoveTopCardToBottom();
|
||||
|
|
@ -201,10 +208,10 @@ private:
|
|||
QAction *aMoveHandToTopLibrary, *aMoveHandToBottomLibrary, *aMoveHandToGrave, *aMoveHandToRfg,
|
||||
*aMoveGraveToTopLibrary, *aMoveGraveToBottomLibrary, *aMoveGraveToHand, *aMoveGraveToRfg, *aMoveRfgToTopLibrary,
|
||||
*aMoveRfgToBottomLibrary, *aMoveRfgToHand, *aMoveRfgToGrave, *aViewLibrary, *aViewTopCards,
|
||||
*aAlwaysRevealTopCard, *aOpenDeckInDeckEditor, *aMoveTopCardsToGrave, *aMoveTopCardsToExile,
|
||||
*aMoveTopCardToBottom, *aViewGraveyard, *aViewRfg, *aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw,
|
||||
*aMulligan, *aShuffle, *aMoveTopToPlayFaceDown, *aUntapAll, *aRollDie, *aCreateToken, *aCreateAnotherToken,
|
||||
*aCardMenu, *aMoveBottomCardToGrave;
|
||||
*aAlwaysRevealTopCard, *aOpenDeckInDeckEditor, *aMoveTopCardToGraveyard, *aMoveTopCardToExile,
|
||||
*aMoveTopCardsToGraveyard, *aMoveTopCardsToExile, *aMoveTopCardToBottom, *aViewGraveyard, *aViewRfg,
|
||||
*aViewSideboard, *aDrawCard, *aDrawCards, *aUndoDraw, *aMulligan, *aShuffle, *aMoveTopToPlayFaceDown,
|
||||
*aUntapAll, *aRollDie, *aCreateToken, *aCreateAnotherToken, *aCardMenu, *aMoveBottomCardToGrave;
|
||||
|
||||
QList<QAction *> aAddCounter, aSetCounter, aRemoveCounter;
|
||||
QAction *aPlay, *aPlayFacedown, *aHide, *aTap, *aDoesntUntap, *aAttach, *aUnattach, *aDrawArrow, *aSetPT, *aResetPT,
|
||||
|
|
@ -249,7 +256,6 @@ private:
|
|||
void createCard(const CardItem *sourceCard, const QString &dbCardName, bool attach = false);
|
||||
void createAttachedCard(const CardItem *sourceCard, const QString &dbCardName);
|
||||
bool createRelatedFromRelation(const CardItem *sourceCard, const CardRelation *cardRelation);
|
||||
QString dbNameFromTokenDisplayName(const QString &tokenName);
|
||||
|
||||
QRectF bRect;
|
||||
|
||||
|
|
@ -259,7 +265,7 @@ private:
|
|||
|
||||
void initSayMenu();
|
||||
|
||||
void eventConnectionStateChanged(const Event_ConnectionStateChanged &event);
|
||||
// void eventConnectionStateChanged(const Event_ConnectionStateChanged &event);
|
||||
void eventGameSay(const Event_GameSay &event);
|
||||
void eventShuffle(const Event_Shuffle &event);
|
||||
void eventRollDie(const Event_RollDie &event);
|
||||
|
|
@ -306,12 +312,12 @@ public:
|
|||
{
|
||||
Type = typeOther
|
||||
};
|
||||
int type() const
|
||||
int type() const override
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
QRectF boundingRect() const;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget);
|
||||
QRectF boundingRect() const override;
|
||||
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
|
||||
|
||||
void playCard(CardItem *c, bool faceDown, bool tapped);
|
||||
void addCard(CardItem *c);
|
||||
|
|
@ -334,7 +340,7 @@ public:
|
|||
}
|
||||
|
||||
Player(const ServerInfo_User &info, int _id, bool _local, TabGame *_parent);
|
||||
~Player();
|
||||
~Player() override;
|
||||
void retranslateUi();
|
||||
void clear();
|
||||
TabGame *getGame() const
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
#include "releasechannel.h"
|
||||
#include "qt-json/json.h"
|
||||
#include "version_string.h"
|
||||
|
||||
#include <QJsonArray>
|
||||
|
|
@ -93,21 +92,20 @@ QString StableReleaseChannel::getReleaseChannelUrl() const
|
|||
|
||||
void StableReleaseChannel::releaseListFinished()
|
||||
{
|
||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||
bool ok;
|
||||
QString tmp = QString(reply->readAll());
|
||||
auto *reply = static_cast<QNetworkReply *>(sender());
|
||||
QJsonParseError parseError{};
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
|
||||
reply->deleteLater();
|
||||
|
||||
QVariantMap resultMap = QtJson::Json::parse(tmp, ok).toMap();
|
||||
if (!ok) {
|
||||
qWarning() << "No reply received from the release update server:" << tmp;
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qWarning() << "No reply received from the release update server.";
|
||||
emit error(tr("No reply received from the release update server."));
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap resultMap = jsonResponse.toVariant().toMap();
|
||||
if (!(resultMap.contains("name") && resultMap.contains("html_url") && resultMap.contains("tag_name") &&
|
||||
resultMap.contains("published_at"))) {
|
||||
qWarning() << "Invalid received from the release update server:" << tmp;
|
||||
qWarning() << "Invalid received from the release update server.";
|
||||
emit error(tr("Invalid reply received from the release update server."));
|
||||
return;
|
||||
}
|
||||
|
|
@ -145,7 +143,7 @@ void StableReleaseChannel::releaseListFinished()
|
|||
QString myHash = QString(VERSION_COMMIT);
|
||||
qDebug() << "Current hash=" << myHash << "update hash=" << shortHash;
|
||||
|
||||
qDebug() << "Got reply from release server, size=" << tmp.size() << "name=" << lastRelease->getName()
|
||||
qDebug() << "Got reply from release server, name=" << lastRelease->getName()
|
||||
<< "desc=" << lastRelease->getDescriptionUrl() << "date=" << lastRelease->getPublishDate()
|
||||
<< "url=" << lastRelease->getDownloadUrl();
|
||||
|
||||
|
|
@ -158,26 +156,25 @@ void StableReleaseChannel::releaseListFinished()
|
|||
|
||||
void StableReleaseChannel::tagListFinished()
|
||||
{
|
||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||
bool ok;
|
||||
QString tmp = QString(reply->readAll());
|
||||
auto *reply = static_cast<QNetworkReply *>(sender());
|
||||
QJsonParseError parseError{};
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
|
||||
reply->deleteLater();
|
||||
|
||||
QVariantMap resultMap = QtJson::Json::parse(tmp, ok).toMap();
|
||||
if (!ok) {
|
||||
qWarning() << "No reply received from the tag update server:" << tmp;
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qWarning() << "No reply received from the tag update server.";
|
||||
emit error(tr("No reply received from the tag update server."));
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantMap resultMap = jsonResponse.toVariant().toMap();
|
||||
if (!(resultMap.contains("object") && resultMap["object"].toMap().contains("sha"))) {
|
||||
qWarning() << "Invalid received from the tag update server:" << tmp;
|
||||
qWarning() << "Invalid received from the tag update server.";
|
||||
emit error(tr("Invalid reply received from the tag update server."));
|
||||
return;
|
||||
}
|
||||
|
||||
lastRelease->setCommitHash(resultMap["object"].toMap()["sha"].toString());
|
||||
qDebug() << "Got reply from tag server, size=" << tmp.size() << "commit=" << lastRelease->getCommitHash();
|
||||
qDebug() << "Got reply from tag server, commit=" << lastRelease->getCommitHash();
|
||||
|
||||
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
|
||||
QString myHash = QString(VERSION_COMMIT);
|
||||
|
|
@ -190,7 +187,6 @@ void StableReleaseChannel::tagListFinished()
|
|||
void StableReleaseChannel::fileListFinished()
|
||||
{
|
||||
// Only implemented to satisfy interface
|
||||
return;
|
||||
}
|
||||
|
||||
QString BetaReleaseChannel::getManualDownloadUrl() const
|
||||
|
|
@ -210,7 +206,7 @@ QString BetaReleaseChannel::getReleaseChannelUrl() const
|
|||
|
||||
void BetaReleaseChannel::releaseListFinished()
|
||||
{
|
||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||
auto *reply = static_cast<QNetworkReply *>(sender());
|
||||
QByteArray jsonData = reply->readAll();
|
||||
reply->deleteLater();
|
||||
|
||||
|
|
@ -224,7 +220,7 @@ void BetaReleaseChannel::releaseListFinished()
|
|||
*/
|
||||
QVariantMap resultMap = array.at(0).toObject().toVariantMap();
|
||||
|
||||
if (array.size() == 0 || resultMap.size() == 0) {
|
||||
if (array.empty() || resultMap.empty()) {
|
||||
qWarning() << "No reply received from the release update server:" << QString(jsonData);
|
||||
emit error(tr("No reply received from the release update server."));
|
||||
return;
|
||||
|
|
@ -262,18 +258,17 @@ void BetaReleaseChannel::releaseListFinished()
|
|||
|
||||
void BetaReleaseChannel::fileListFinished()
|
||||
{
|
||||
QNetworkReply *reply = static_cast<QNetworkReply *>(sender());
|
||||
QByteArray jsonData = reply->readAll();
|
||||
auto *reply = static_cast<QNetworkReply *>(sender());
|
||||
QJsonParseError parseError{};
|
||||
QJsonDocument jsonResponse = QJsonDocument::fromJson(reply->readAll(), &parseError);
|
||||
reply->deleteLater();
|
||||
bool ok;
|
||||
|
||||
QVariantList resultList = QtJson::Json::parse(jsonData, ok).toList();
|
||||
if (!ok) {
|
||||
qWarning() << "No reply received from the file update server:" << QString(jsonData);
|
||||
if (parseError.error != QJsonParseError::NoError) {
|
||||
qWarning() << "No reply received from the file update server.";
|
||||
emit error(tr("No reply received from the file update server."));
|
||||
return;
|
||||
}
|
||||
|
||||
QVariantList resultList = jsonResponse.toVariant().toList();
|
||||
QString shortHash = lastRelease->getCommitHash().left(GIT_SHORT_HASH_LEN);
|
||||
QString myHash = QString(VERSION_COMMIT);
|
||||
qDebug() << "Current hash=" << myHash << "update hash=" << shortHash;
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
#include <QObject>
|
||||
#include <QString>
|
||||
#include <QVariantMap>
|
||||
#include <utility>
|
||||
|
||||
class QNetworkReply;
|
||||
class QNetworkAccessManager;
|
||||
|
|
@ -15,8 +16,8 @@ class Release
|
|||
friend class BetaReleaseChannel;
|
||||
|
||||
public:
|
||||
Release(){};
|
||||
~Release(){};
|
||||
Release() = default;
|
||||
~Release() = default;
|
||||
|
||||
private:
|
||||
QString name, descriptionUrl, downloadUrl, commitHash;
|
||||
|
|
@ -26,20 +27,20 @@ private:
|
|||
protected:
|
||||
void setName(QString _name)
|
||||
{
|
||||
name = _name;
|
||||
name = std::move(_name);
|
||||
}
|
||||
void setDescriptionUrl(QString _descriptionUrl)
|
||||
{
|
||||
descriptionUrl = _descriptionUrl;
|
||||
descriptionUrl = std::move(_descriptionUrl);
|
||||
}
|
||||
void setDownloadUrl(QString _downloadUrl)
|
||||
{
|
||||
downloadUrl = _downloadUrl;
|
||||
downloadUrl = std::move(_downloadUrl);
|
||||
compatibleVersionFound = true;
|
||||
}
|
||||
void setCommitHash(QString _commitHash)
|
||||
{
|
||||
commitHash = _commitHash;
|
||||
commitHash = std::move(_commitHash);
|
||||
}
|
||||
void setPublishDate(QDate _publishDate)
|
||||
{
|
||||
|
|
@ -78,7 +79,7 @@ class ReleaseChannel : public QObject
|
|||
Q_OBJECT
|
||||
public:
|
||||
ReleaseChannel();
|
||||
~ReleaseChannel();
|
||||
~ReleaseChannel() override;
|
||||
|
||||
protected:
|
||||
// shared by all instances
|
||||
|
|
@ -116,33 +117,41 @@ class StableReleaseChannel : public ReleaseChannel
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
StableReleaseChannel(){};
|
||||
~StableReleaseChannel(){};
|
||||
virtual QString getManualDownloadUrl() const;
|
||||
virtual QString getName() const;
|
||||
StableReleaseChannel() = default;
|
||||
~StableReleaseChannel() override = default;
|
||||
|
||||
QString getManualDownloadUrl() const override;
|
||||
|
||||
QString getName() const override;
|
||||
|
||||
protected:
|
||||
virtual QString getReleaseChannelUrl() const;
|
||||
QString getReleaseChannelUrl() const override;
|
||||
protected slots:
|
||||
virtual void releaseListFinished();
|
||||
|
||||
void releaseListFinished() override;
|
||||
void tagListFinished();
|
||||
virtual void fileListFinished();
|
||||
|
||||
void fileListFinished() override;
|
||||
};
|
||||
|
||||
class BetaReleaseChannel : public ReleaseChannel
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
BetaReleaseChannel(){};
|
||||
~BetaReleaseChannel(){};
|
||||
virtual QString getManualDownloadUrl() const;
|
||||
virtual QString getName() const;
|
||||
BetaReleaseChannel() = default;
|
||||
~BetaReleaseChannel() override = default;
|
||||
|
||||
QString getManualDownloadUrl() const override;
|
||||
|
||||
QString getName() const override;
|
||||
|
||||
protected:
|
||||
virtual QString getReleaseChannelUrl() const;
|
||||
QString getReleaseChannelUrl() const override;
|
||||
protected slots:
|
||||
virtual void releaseListFinished();
|
||||
virtual void fileListFinished();
|
||||
|
||||
void releaseListFinished() override;
|
||||
|
||||
void fileListFinished() override;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -18,12 +18,13 @@
|
|||
#include <QList>
|
||||
#include <QThread>
|
||||
#include <QTimer>
|
||||
#include <QWebSocket>
|
||||
|
||||
static const unsigned int protocolVersion = 14;
|
||||
|
||||
RemoteClient::RemoteClient(QObject *parent)
|
||||
: AbstractClient(parent), timeRunning(0), lastDataReceived(0), messageInProgress(false), handshakeStarted(false),
|
||||
messageLength(0)
|
||||
usingWebSocket(false), messageLength(0)
|
||||
{
|
||||
|
||||
clearNewClientFeatures();
|
||||
|
|
@ -38,6 +39,13 @@ RemoteClient::RemoteClient(QObject *parent)
|
|||
connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
|
||||
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this,
|
||||
SLOT(slotSocketError(QAbstractSocket::SocketError)));
|
||||
|
||||
websocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);
|
||||
connect(websocket, &QWebSocket::binaryMessageReceived, this, &RemoteClient::websocketMessageReceived);
|
||||
connect(websocket, &QWebSocket::connected, this, &RemoteClient::slotConnected);
|
||||
connect(websocket, SIGNAL(error(QAbstractSocket::SocketError)), this,
|
||||
SLOT(slotWebSocketError(QAbstractSocket::SocketError)));
|
||||
|
||||
connect(this, SIGNAL(serverIdentificationEventReceived(const Event_ServerIdentification &)), this,
|
||||
SLOT(processServerIdentificationEvent(const Event_ServerIdentification &)));
|
||||
connect(this, SIGNAL(connectionClosedEventReceived(Event_ConnectionClosed)), this,
|
||||
|
|
@ -69,15 +77,25 @@ void RemoteClient::slotSocketError(QAbstractSocket::SocketError /*error*/)
|
|||
emit socketError(errorString);
|
||||
}
|
||||
|
||||
void RemoteClient::slotWebSocketError(QAbstractSocket::SocketError /*error*/)
|
||||
{
|
||||
|
||||
QString errorString = websocket->errorString();
|
||||
doDisconnectFromServer();
|
||||
emit socketError(errorString);
|
||||
}
|
||||
|
||||
void RemoteClient::slotConnected()
|
||||
{
|
||||
timeRunning = lastDataReceived = 0;
|
||||
timer->start();
|
||||
|
||||
// dirty hack to be compatible with v14 server
|
||||
sendCommandContainer(CommandContainer());
|
||||
getNewCmdId();
|
||||
// end of hack
|
||||
if (!usingWebSocket) {
|
||||
// dirty hack to be compatible with v14 server
|
||||
sendCommandContainer(CommandContainer());
|
||||
getNewCmdId();
|
||||
// end of hack
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentification &event)
|
||||
|
|
@ -217,7 +235,7 @@ void RemoteClient::loginResponse(const Response &response)
|
|||
missingFeatures << QString::fromStdString(resp.missing_features(i));
|
||||
}
|
||||
emit loginError(response.response_code(), QString::fromStdString(resp.denied_reason_str()),
|
||||
resp.denied_end_time(), missingFeatures);
|
||||
static_cast<quint32>(resp.denied_end_time()), missingFeatures);
|
||||
setStatus(StatusDisconnecting);
|
||||
}
|
||||
}
|
||||
|
|
@ -236,7 +254,7 @@ void RemoteClient::registerResponse(const Response &response)
|
|||
break;
|
||||
default:
|
||||
emit registerError(response.response_code(), QString::fromStdString(resp.denied_reason_str()),
|
||||
resp.denied_end_time());
|
||||
static_cast<quint32>(resp.denied_end_time()));
|
||||
setStatus(StatusDisconnecting);
|
||||
doDisconnectFromServer();
|
||||
break;
|
||||
|
|
@ -301,21 +319,51 @@ void RemoteClient::readData()
|
|||
} while (!inputBuffer.isEmpty());
|
||||
}
|
||||
|
||||
void RemoteClient::websocketMessageReceived(const QByteArray &message)
|
||||
{
|
||||
lastDataReceived = timeRunning;
|
||||
ServerMessage newServerMessage;
|
||||
newServerMessage.ParseFromArray(message.data(), message.length());
|
||||
#ifdef QT_DEBUG
|
||||
qDebug() << "IN" << messageLength << QString::fromStdString(newServerMessage.ShortDebugString());
|
||||
#endif
|
||||
processProtocolItem(newServerMessage);
|
||||
}
|
||||
|
||||
void RemoteClient::sendCommandContainer(const CommandContainer &cont)
|
||||
{
|
||||
QByteArray buf;
|
||||
unsigned int size = cont.ByteSize();
|
||||
|
||||
auto size = static_cast<unsigned int>(cont.ByteSize());
|
||||
#ifdef QT_DEBUG
|
||||
qDebug() << "OUT" << size << QString::fromStdString(cont.ShortDebugString());
|
||||
#endif
|
||||
buf.resize(size + 4);
|
||||
cont.SerializeToArray(buf.data() + 4, size);
|
||||
buf.data()[3] = (unsigned char)size;
|
||||
buf.data()[2] = (unsigned char)(size >> 8);
|
||||
buf.data()[1] = (unsigned char)(size >> 16);
|
||||
buf.data()[0] = (unsigned char)(size >> 24);
|
||||
|
||||
socket->write(buf);
|
||||
QByteArray buf;
|
||||
if (usingWebSocket) {
|
||||
buf.resize(size);
|
||||
cont.SerializeToArray(buf.data(), size);
|
||||
websocket->sendBinaryMessage(buf);
|
||||
} else {
|
||||
buf.resize(size + 4);
|
||||
cont.SerializeToArray(buf.data() + 4, size);
|
||||
buf.data()[3] = (unsigned char)size;
|
||||
buf.data()[2] = (unsigned char)(size >> 8);
|
||||
buf.data()[1] = (unsigned char)(size >> 16);
|
||||
buf.data()[0] = (unsigned char)(size >> 24);
|
||||
|
||||
socket->write(buf);
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteClient::connectToHost(const QString &hostname, unsigned int port)
|
||||
{
|
||||
usingWebSocket = port == 443 || port == 80 || port == 4748 || port == 8080;
|
||||
if (usingWebSocket) {
|
||||
QUrl url(QString("%1://%2:%3/servatrice").arg(port == 443 ? "wss" : "ws").arg(hostname).arg(port));
|
||||
websocket->open(url);
|
||||
} else {
|
||||
socket->connectToHost(hostname, static_cast<quint16>(port));
|
||||
}
|
||||
}
|
||||
|
||||
void RemoteClient::doConnectToServer(const QString &hostname,
|
||||
|
|
@ -330,7 +378,7 @@ void RemoteClient::doConnectToServer(const QString &hostname,
|
|||
lastHostname = hostname;
|
||||
lastPort = port;
|
||||
|
||||
socket->connectToHost(hostname, port);
|
||||
connectToHost(hostname, port);
|
||||
setStatus(StatusConnecting);
|
||||
}
|
||||
|
||||
|
|
@ -354,7 +402,7 @@ void RemoteClient::doRegisterToServer(const QString &hostname,
|
|||
lastHostname = hostname;
|
||||
lastPort = port;
|
||||
|
||||
socket->connectToHost(hostname, port);
|
||||
connectToHost(hostname, port);
|
||||
setStatus(StatusRegistering);
|
||||
}
|
||||
|
||||
|
|
@ -364,7 +412,7 @@ void RemoteClient::doActivateToServer(const QString &_token)
|
|||
|
||||
token = _token;
|
||||
|
||||
socket->connectToHost(lastHostname, lastPort);
|
||||
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
|
||||
setStatus(StatusActivating);
|
||||
}
|
||||
|
||||
|
|
@ -377,17 +425,19 @@ void RemoteClient::doDisconnectFromServer()
|
|||
messageLength = 0;
|
||||
|
||||
QList<PendingCommand *> pc = pendingCommands.values();
|
||||
for (int i = 0; i < pc.size(); i++) {
|
||||
for (const auto &i : pc) {
|
||||
Response response;
|
||||
response.set_response_code(Response::RespNotConnected);
|
||||
response.set_cmd_id(pc[i]->getCommandContainer().cmd_id());
|
||||
pc[i]->processResponse(response);
|
||||
response.set_cmd_id(i->getCommandContainer().cmd_id());
|
||||
i->processResponse(response);
|
||||
|
||||
delete pc[i];
|
||||
delete i;
|
||||
}
|
||||
pendingCommands.clear();
|
||||
|
||||
setStatus(StatusDisconnected);
|
||||
if (websocket->isValid())
|
||||
websocket->close();
|
||||
socket->close();
|
||||
}
|
||||
|
||||
|
|
@ -508,7 +558,7 @@ void RemoteClient::doRequestForgotPasswordToServer(const QString &hostname, unsi
|
|||
lastHostname = hostname;
|
||||
lastPort = port;
|
||||
|
||||
socket->connectToHost(lastHostname, lastPort);
|
||||
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
|
||||
setStatus(StatusRequestingForgotPassword);
|
||||
}
|
||||
|
||||
|
|
@ -540,7 +590,7 @@ void RemoteClient::doSubmitForgotPasswordResetToServer(const QString &hostname,
|
|||
token = _token;
|
||||
password = _newpassword;
|
||||
|
||||
socket->connectToHost(lastHostname, lastPort);
|
||||
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
|
||||
setStatus(StatusSubmitForgotPasswordReset);
|
||||
}
|
||||
|
||||
|
|
@ -574,7 +624,7 @@ void RemoteClient::doSubmitForgotPasswordChallengeToServer(const QString &hostna
|
|||
lastPort = port;
|
||||
email = _email;
|
||||
|
||||
socket->connectToHost(lastHostname, lastPort);
|
||||
connectToHost(lastHostname, static_cast<unsigned int>(lastPort));
|
||||
setStatus(StatusSubmitForgotPasswordChallenge);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "abstractclient.h"
|
||||
#include <QTcpSocket>
|
||||
#include <QWebSocket>
|
||||
|
||||
class QTimer;
|
||||
|
||||
|
|
@ -17,7 +18,6 @@ signals:
|
|||
void activateError();
|
||||
void socketError(const QString &errorString);
|
||||
void protocolVersionMismatch(int clientVersion, int serverVersion);
|
||||
void protocolError();
|
||||
void
|
||||
sigConnectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password);
|
||||
void sigRegisterToServer(const QString &hostname,
|
||||
|
|
@ -25,7 +25,7 @@ signals:
|
|||
const QString &_userName,
|
||||
const QString &_password,
|
||||
const QString &_email,
|
||||
const int _gender,
|
||||
int _gender,
|
||||
const QString &_country,
|
||||
const QString &_realname);
|
||||
void sigActivateToServer(const QString &_token);
|
||||
|
|
@ -48,7 +48,9 @@ signals:
|
|||
private slots:
|
||||
void slotConnected();
|
||||
void readData();
|
||||
void websocketMessageReceived(const QByteArray &message);
|
||||
void slotSocketError(QAbstractSocket::SocketError error);
|
||||
void slotWebSocketError(QAbstractSocket::SocketError error);
|
||||
void ping();
|
||||
void processServerIdentificationEvent(const Event_ServerIdentification &event);
|
||||
void processConnectionClosedEvent(const Event_ConnectionClosed &event);
|
||||
|
|
@ -62,7 +64,7 @@ private slots:
|
|||
const QString &_userName,
|
||||
const QString &_password,
|
||||
const QString &_email,
|
||||
const int _gender,
|
||||
int _gender,
|
||||
const QString &_country,
|
||||
const QString &_realname);
|
||||
void doLogin();
|
||||
|
|
@ -85,28 +87,35 @@ private slots:
|
|||
private:
|
||||
static const int maxTimeout = 10;
|
||||
int timeRunning, lastDataReceived;
|
||||
|
||||
QByteArray inputBuffer;
|
||||
bool messageInProgress;
|
||||
bool handshakeStarted;
|
||||
bool newMissingFeatureFound(QString _serversMissingFeatures);
|
||||
void clearNewClientFeatures();
|
||||
bool usingWebSocket;
|
||||
int messageLength;
|
||||
|
||||
QTimer *timer;
|
||||
QTcpSocket *socket;
|
||||
QWebSocket *websocket;
|
||||
QString lastHostname;
|
||||
int lastPort;
|
||||
QString getSrvClientID(const QString _hostname);
|
||||
|
||||
QString getSrvClientID(QString _hostname);
|
||||
bool newMissingFeatureFound(QString _serversMissingFeatures);
|
||||
void clearNewClientFeatures();
|
||||
void connectToHost(const QString &hostname, unsigned int port);
|
||||
|
||||
protected slots:
|
||||
void sendCommandContainer(const CommandContainer &cont);
|
||||
void sendCommandContainer(const CommandContainer &cont) override;
|
||||
|
||||
public:
|
||||
RemoteClient(QObject *parent = 0);
|
||||
~RemoteClient();
|
||||
explicit RemoteClient(QObject *parent = nullptr);
|
||||
~RemoteClient() override;
|
||||
QString peerName() const
|
||||
{
|
||||
return socket->peerName();
|
||||
if (usingWebSocket) {
|
||||
return websocket->peerName();
|
||||
} else {
|
||||
return socket->peerName();
|
||||
}
|
||||
}
|
||||
void
|
||||
connectToServer(const QString &hostname, unsigned int port, const QString &_userName, const QString &_password);
|
||||
|
|
@ -115,7 +124,7 @@ public:
|
|||
const QString &_userName,
|
||||
const QString &_password,
|
||||
const QString &_email,
|
||||
const int _gender,
|
||||
int _gender,
|
||||
const QString &_country,
|
||||
const QString &_realname);
|
||||
void activateToServer(const QString &_token);
|
||||
|
|
|
|||
|
|
@ -1,20 +1,12 @@
|
|||
#include "sequenceedit.h"
|
||||
#include "../settingscache.h"
|
||||
#include <QEvent>
|
||||
#include <QHBoxLayout>
|
||||
#include <QKeyEvent>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QToolTip>
|
||||
#include <utility>
|
||||
|
||||
SequenceEdit::SequenceEdit(QString _shorcutName, QWidget *parent) : QWidget(parent)
|
||||
SequenceEdit::SequenceEdit(const QString &_shortcutName, QWidget *parent) : QWidget(parent), shortcutName(_shortcutName)
|
||||
{
|
||||
shorcutName = std::move(_shorcutName);
|
||||
currentKey = 0;
|
||||
keys = 0;
|
||||
valid = false;
|
||||
|
||||
lineEdit = new QLineEdit(this);
|
||||
clearButton = new QPushButton("", this);
|
||||
defaultButton = new QPushButton("", this);
|
||||
|
|
@ -42,20 +34,20 @@ SequenceEdit::SequenceEdit(QString _shorcutName, QWidget *parent) : QWidget(pare
|
|||
connect(defaultButton, SIGNAL(clicked()), this, SLOT(restoreDefault()));
|
||||
lineEdit->installEventFilter(this);
|
||||
|
||||
lineEdit->setText(settingsCache->shortcuts().getShortcutString(shorcutName));
|
||||
lineEdit->setText(settingsCache->shortcuts().getShortcutString(shortcutName));
|
||||
}
|
||||
|
||||
QString SequenceEdit::getSecuence()
|
||||
QString SequenceEdit::getSequence()
|
||||
{
|
||||
return lineEdit->text();
|
||||
}
|
||||
|
||||
void SequenceEdit::removeLastShortcut()
|
||||
{
|
||||
QString secuences = lineEdit->text();
|
||||
if (!secuences.isEmpty()) {
|
||||
if (secuences.lastIndexOf(";") > 0) {
|
||||
QString valid = secuences.left(secuences.lastIndexOf(";"));
|
||||
QString sequences = lineEdit->text();
|
||||
if (!sequences.isEmpty()) {
|
||||
if (sequences.lastIndexOf(";") > 0) {
|
||||
QString valid = sequences.left(sequences.lastIndexOf(";"));
|
||||
lineEdit->setText(valid);
|
||||
} else {
|
||||
lineEdit->clear();
|
||||
|
|
@ -67,18 +59,18 @@ void SequenceEdit::removeLastShortcut()
|
|||
|
||||
void SequenceEdit::restoreDefault()
|
||||
{
|
||||
lineEdit->setText(settingsCache->shortcuts().getDefaultShortcutString(shorcutName));
|
||||
lineEdit->setText(settingsCache->shortcuts().getDefaultShortcutString(shortcutName));
|
||||
updateSettings();
|
||||
}
|
||||
|
||||
void SequenceEdit::refreshShortcut()
|
||||
{
|
||||
lineEdit->setText(settingsCache->shortcuts().getShortcutString(shorcutName));
|
||||
lineEdit->setText(settingsCache->shortcuts().getShortcutString(shortcutName));
|
||||
}
|
||||
|
||||
void SequenceEdit::clear()
|
||||
{
|
||||
this->lineEdit->setText("");
|
||||
lineEdit->setText("");
|
||||
}
|
||||
|
||||
bool SequenceEdit::eventFilter(QObject *, QEvent *event)
|
||||
|
|
@ -142,8 +134,8 @@ void SequenceEdit::finishShortcut()
|
|||
QKeySequence sequence(keys);
|
||||
if (!sequence.isEmpty() && valid) {
|
||||
QString sequenceString = sequence.toString();
|
||||
if (settingsCache->shortcuts().isKeyAllowed(shorcutName, sequenceString)) {
|
||||
if (settingsCache->shortcuts().isValid(shorcutName, sequenceString)) {
|
||||
if (settingsCache->shortcuts().isKeyAllowed(shortcutName, sequenceString)) {
|
||||
if (settingsCache->shortcuts().isValid(shortcutName, sequenceString)) {
|
||||
if (!lineEdit->text().isEmpty()) {
|
||||
if (lineEdit->text().contains(sequenceString)) {
|
||||
return;
|
||||
|
|
@ -167,5 +159,5 @@ void SequenceEdit::finishShortcut()
|
|||
|
||||
void SequenceEdit::updateSettings()
|
||||
{
|
||||
settingsCache->shortcuts().setShortcuts(shorcutName, lineEdit->text());
|
||||
}
|
||||
settingsCache->shortcuts().setShortcuts(shortcutName, lineEdit->text());
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,19 +1,18 @@
|
|||
#ifndef SECUENCEEDIT_H
|
||||
#define SECUENCEEDIT_H
|
||||
#ifndef SEQUENCEEDIT_H
|
||||
#define SEQUENCEEDIT_H
|
||||
|
||||
#include <QEvent>
|
||||
#include <QKeySequence>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QWidget>
|
||||
|
||||
class QLineEdit;
|
||||
class QPushButton;
|
||||
class QEvent;
|
||||
|
||||
class SequenceEdit : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SequenceEdit(QString _shorcutName, QWidget *parent = nullptr);
|
||||
QString getSecuence();
|
||||
SequenceEdit(const QString &_shortcutName, QWidget *parent = nullptr);
|
||||
QString getSequence();
|
||||
void refreshShortcut();
|
||||
void clear();
|
||||
|
||||
|
|
@ -25,13 +24,13 @@ protected:
|
|||
bool eventFilter(QObject *, QEvent *event);
|
||||
|
||||
private:
|
||||
QString shorcutName;
|
||||
QString shortcutName;
|
||||
QLineEdit *lineEdit;
|
||||
QPushButton *clearButton;
|
||||
QPushButton *defaultButton;
|
||||
int keys;
|
||||
int currentKey;
|
||||
bool valid;
|
||||
int keys = 0;
|
||||
int currentKey = 0;
|
||||
bool valid = false;
|
||||
|
||||
void processKey(QKeyEvent *e);
|
||||
int translateModifiers(Qt::KeyboardModifiers state, const QString &text);
|
||||
|
|
@ -39,4 +38,4 @@ private:
|
|||
void updateSettings();
|
||||
};
|
||||
|
||||
#endif // SECUENCEEDIT_H
|
||||
#endif // SEQUENCEEDIT_H
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
56
cockatrice/src/settings/downloadsettings.cpp
Normal file
56
cockatrice/src/settings/downloadsettings.cpp
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
#include "downloadsettings.h"
|
||||
#include "settingsmanager.h"
|
||||
|
||||
DownloadSettings::DownloadSettings(const QString &settingPath, QObject *parent = nullptr)
|
||||
: SettingsManager(settingPath + "downloads.ini", parent)
|
||||
{
|
||||
downloadURLs = getValue("urls", "downloads").value<QStringList>();
|
||||
}
|
||||
|
||||
void DownloadSettings::setDownloadUrlAt(int index, const QString &url)
|
||||
{
|
||||
downloadURLs.insert(index, url);
|
||||
setValue(QVariant::fromValue(downloadURLs), "urls", "downloads");
|
||||
}
|
||||
|
||||
/**
|
||||
* If reset or first run, this method contains the default URLs we will populate
|
||||
*/
|
||||
QStringList DownloadSettings::getAllURLs()
|
||||
{
|
||||
// First run, these will be empty
|
||||
if (downloadURLs.count() == 0) {
|
||||
populateDefaultURLs();
|
||||
}
|
||||
|
||||
return downloadURLs;
|
||||
}
|
||||
|
||||
void DownloadSettings::populateDefaultURLs()
|
||||
{
|
||||
downloadURLs.clear();
|
||||
downloadURLs.append("https://api.scryfall.com/cards/!set:uuid!?format=image&face=!prop:side!");
|
||||
downloadURLs.append("https://api.scryfall.com/cards/multiverse/!set:muid!?format=image");
|
||||
downloadURLs.append("http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!set:muid!&type=card");
|
||||
downloadURLs.append("http://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card");
|
||||
setValue(QVariant::fromValue(downloadURLs), "urls", "downloads");
|
||||
}
|
||||
|
||||
QString DownloadSettings::getDownloadUrlAt(int index)
|
||||
{
|
||||
if (0 <= index && index < downloadURLs.size()) {
|
||||
return downloadURLs[index];
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
int DownloadSettings::getCount()
|
||||
{
|
||||
return downloadURLs.size();
|
||||
}
|
||||
|
||||
void DownloadSettings::clear()
|
||||
{
|
||||
downloadURLs.clear();
|
||||
}
|
||||
28
cockatrice/src/settings/downloadsettings.h
Normal file
28
cockatrice/src/settings/downloadsettings.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef COCKATRICE_DOWNLOADSETTINGS_H
|
||||
#define COCKATRICE_DOWNLOADSETTINGS_H
|
||||
|
||||
#include "settingsmanager.h"
|
||||
#include <QObject>
|
||||
|
||||
class DownloadSettings : public SettingsManager
|
||||
{
|
||||
Q_OBJECT
|
||||
friend class SettingsCache;
|
||||
|
||||
public:
|
||||
explicit DownloadSettings(const QString &, QObject *);
|
||||
|
||||
QStringList getAllURLs();
|
||||
QString getDownloadUrlAt(int);
|
||||
void setDownloadUrlAt(int, const QString &);
|
||||
int getCount();
|
||||
void clear();
|
||||
|
||||
private:
|
||||
QStringList downloadURLs;
|
||||
|
||||
private:
|
||||
void populateDefaultURLs();
|
||||
};
|
||||
|
||||
#endif // COCKATRICE_DOWNLOADSETTINGS_H
|
||||
|
|
@ -164,6 +164,7 @@ SettingsCache::SettingsCache()
|
|||
messageSettings = new MessageSettings(settingsPath, this);
|
||||
gameFiltersSettings = new GameFiltersSettings(settingsPath, this);
|
||||
layoutsSettings = new LayoutsSettings(settingsPath, this);
|
||||
downloadSettings = new DownloadSettings(settingsPath, this);
|
||||
|
||||
if (!QFile(settingsPath + "global.ini").exists())
|
||||
translateLegacySettings();
|
||||
|
|
@ -176,6 +177,7 @@ SettingsCache::SettingsCache()
|
|||
mbDownloadSpoilers = settings->value("personal/downloadspoilers", false).toBool();
|
||||
|
||||
notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
|
||||
notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool();
|
||||
updateReleaseChannel = settings->value("personal/updatereleasechannel", 0).toInt();
|
||||
|
||||
lang = settings->value("personal/lang").toString();
|
||||
|
|
@ -220,9 +222,6 @@ SettingsCache::SettingsCache()
|
|||
|
||||
picDownload = settings->value("personal/picturedownload", true).toBool();
|
||||
|
||||
picUrl = settings->value("personal/picUrl", PIC_URL_DEFAULT).toString();
|
||||
picUrlFallback = settings->value("personal/picUrlFallback", PIC_URL_FALLBACK).toString();
|
||||
|
||||
mainWindowGeometry = settings->value("interface/main_window_geometry").toByteArray();
|
||||
tokenDialogGeometry = settings->value("interface/token_dialog_geometry").toByteArray();
|
||||
notificationsEnabled = settings->value("interface/notificationsenabled", true).toBool();
|
||||
|
|
@ -234,7 +233,7 @@ SettingsCache::SettingsCache()
|
|||
displayCardNames = settings->value("cards/displaycardnames", true).toBool();
|
||||
horizontalHand = settings->value("hand/horizontal", true).toBool();
|
||||
invertVerticalCoordinate = settings->value("table/invert_vertical", false).toBool();
|
||||
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 5).toInt();
|
||||
minPlayersForMultiColumnLayout = settings->value("interface/min_players_multicolumn", 4).toInt();
|
||||
tapAnimation = settings->value("cards/tapanimation", true).toBool();
|
||||
chatMention = settings->value("chat/mention", true).toBool();
|
||||
chatMentionCompleter = settings->value("chat/mentioncompleter", true).toBool();
|
||||
|
|
@ -277,6 +276,7 @@ SettingsCache::SettingsCache()
|
|||
spectatorsCanSeeEverything = settings->value("game/spectatorscanseeeverything", false).toBool();
|
||||
rememberGameSettings = settings->value("game/remembergamesettings", true).toBool();
|
||||
clientID = settings->value("personal/clientid", "notset").toString();
|
||||
clientVersion = settings->value("personal/clientversion", "notset").toString();
|
||||
knownMissingFeatures = settings->value("interface/knownmissingfeatures", "").toString();
|
||||
}
|
||||
|
||||
|
|
@ -415,18 +415,6 @@ void SettingsCache::setPicDownload(int _picDownload)
|
|||
emit picDownloadChanged();
|
||||
}
|
||||
|
||||
void SettingsCache::setPicUrl(const QString &_picUrl)
|
||||
{
|
||||
picUrl = _picUrl;
|
||||
settings->setValue("personal/picUrl", picUrl);
|
||||
}
|
||||
|
||||
void SettingsCache::setPicUrlFallback(const QString &_picUrlFallback)
|
||||
{
|
||||
picUrlFallback = _picUrlFallback;
|
||||
settings->setValue("personal/picUrlFallback", picUrlFallback);
|
||||
}
|
||||
|
||||
void SettingsCache::setNotificationsEnabled(int _notificationsEnabled)
|
||||
{
|
||||
notificationsEnabled = static_cast<bool>(_notificationsEnabled);
|
||||
|
|
@ -603,6 +591,12 @@ void SettingsCache::setClientID(QString _clientID)
|
|||
settings->setValue("personal/clientid", clientID);
|
||||
}
|
||||
|
||||
void SettingsCache::setClientVersion(QString _clientVersion)
|
||||
{
|
||||
clientVersion = std::move(_clientVersion);
|
||||
settings->setValue("personal/clientversion", clientVersion);
|
||||
}
|
||||
|
||||
QStringList SettingsCache::getCountries() const
|
||||
{
|
||||
static QStringList countries = QStringList() << "ad"
|
||||
|
|
@ -924,6 +918,12 @@ void SettingsCache::setNotifyAboutUpdate(int _notifyaboutupdate)
|
|||
settings->setValue("personal/updatenotification", notifyAboutUpdates);
|
||||
}
|
||||
|
||||
void SettingsCache::setNotifyAboutNewVersion(int _notifyaboutnewversion)
|
||||
{
|
||||
notifyAboutNewVersion = static_cast<bool>(_notifyaboutnewversion);
|
||||
settings->setValue("personal/newversionnotification", notifyAboutNewVersion);
|
||||
}
|
||||
|
||||
void SettingsCache::setDownloadSpoilerStatus(bool _spoilerStatus)
|
||||
{
|
||||
mbDownloadSpoilers = _spoilerStatus;
|
||||
|
|
@ -941,4 +941,4 @@ void SettingsCache::setMaxFontSize(int _max)
|
|||
{
|
||||
maxFontSize = _max;
|
||||
settings->setValue("game/maxfontsize", maxFontSize);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
#define SETTINGSCACHE_H
|
||||
|
||||
#include "settings/carddatabasesettings.h"
|
||||
#include "settings/downloadsettings.h"
|
||||
#include "settings/gamefilterssettings.h"
|
||||
#include "settings/layoutssettings.h"
|
||||
#include "settings/messagesettings.h"
|
||||
|
|
@ -13,9 +14,6 @@
|
|||
|
||||
class ReleaseChannel;
|
||||
|
||||
// the falbacks are used for cards without a muid
|
||||
#define PIC_URL_DEFAULT "http://gatherer.wizards.com/Handlers/Image.ashx?multiverseid=!cardid!&type=card"
|
||||
#define PIC_URL_FALLBACK "http://gatherer.wizards.com/Handlers/Image.ashx?name=!name!&type=card"
|
||||
// size should be a multiple of 64
|
||||
#define PIXMAPCACHE_SIZE_DEFAULT 2047
|
||||
#define PIXMAPCACHE_SIZE_MIN 64
|
||||
|
|
@ -60,6 +58,7 @@ private:
|
|||
MessageSettings *messageSettings;
|
||||
GameFiltersSettings *gameFiltersSettings;
|
||||
LayoutsSettings *layoutsSettings;
|
||||
DownloadSettings *downloadSettings;
|
||||
|
||||
QByteArray mainWindowGeometry;
|
||||
QByteArray tokenDialogGeometry;
|
||||
|
|
@ -67,6 +66,7 @@ private:
|
|||
QString deckPath, replaysPath, picsPath, customPicsPath, cardDatabasePath, customCardDatabasePath,
|
||||
spoilerDatabasePath, tokenDatabasePath, themeName;
|
||||
bool notifyAboutUpdates;
|
||||
bool notifyAboutNewVersion;
|
||||
bool showTipsOnStartup;
|
||||
QList<int> seenTips;
|
||||
bool mbDownloadSpoilers;
|
||||
|
|
@ -98,6 +98,7 @@ private:
|
|||
QString picUrl;
|
||||
QString picUrlFallback;
|
||||
QString clientID;
|
||||
QString clientVersion;
|
||||
QString knownMissingFeatures;
|
||||
int pixmapCacheSize;
|
||||
bool scaleCards;
|
||||
|
|
@ -201,6 +202,10 @@ public:
|
|||
{
|
||||
return notifyAboutUpdates;
|
||||
}
|
||||
bool getNotifyAboutNewVersion() const
|
||||
{
|
||||
return notifyAboutNewVersion;
|
||||
}
|
||||
bool getShowTipsOnStartup() const
|
||||
{
|
||||
return showTipsOnStartup;
|
||||
|
|
@ -302,14 +307,6 @@ public:
|
|||
{
|
||||
return ignoreUnregisteredUserMessages;
|
||||
}
|
||||
QString getPicUrl() const
|
||||
{
|
||||
return picUrl;
|
||||
}
|
||||
QString getPicUrlFallback() const
|
||||
{
|
||||
return picUrlFallback;
|
||||
}
|
||||
int getPixmapCacheSize() const
|
||||
{
|
||||
return pixmapCacheSize;
|
||||
|
|
@ -396,11 +393,16 @@ public:
|
|||
return maxFontSize;
|
||||
}
|
||||
void setClientID(QString clientID);
|
||||
void setClientVersion(QString clientVersion);
|
||||
void setKnownMissingFeatures(QString _knownMissingFeatures);
|
||||
QString getClientID()
|
||||
{
|
||||
return clientID;
|
||||
}
|
||||
QString getClientVersion()
|
||||
{
|
||||
return clientVersion;
|
||||
}
|
||||
QString getKnownMissingFeatures()
|
||||
{
|
||||
return knownMissingFeatures;
|
||||
|
|
@ -429,6 +431,10 @@ public:
|
|||
{
|
||||
return *layoutsSettings;
|
||||
}
|
||||
DownloadSettings &downloads() const
|
||||
{
|
||||
return *downloadSettings;
|
||||
}
|
||||
bool getIsPortableBuild() const
|
||||
{
|
||||
return isPortableBuild;
|
||||
|
|
@ -477,8 +483,6 @@ public slots:
|
|||
void setSoundThemeName(const QString &_soundThemeName);
|
||||
void setIgnoreUnregisteredUsers(int _ignoreUnregisteredUsers);
|
||||
void setIgnoreUnregisteredUserMessages(int _ignoreUnregisteredUserMessages);
|
||||
void setPicUrl(const QString &_picUrl);
|
||||
void setPicUrlFallback(const QString &_picUrlFallback);
|
||||
void setPixmapCacheSize(const int _pixmapCacheSize);
|
||||
void setCardScaling(const int _scaleCards);
|
||||
void setShowMessagePopups(const int _showMessagePopups);
|
||||
|
|
@ -499,6 +503,7 @@ public slots:
|
|||
void setSpectatorsCanSeeEverything(const bool _spectatorsCanSeeEverything);
|
||||
void setRememberGameSettings(const bool _rememberGameSettings);
|
||||
void setNotifyAboutUpdate(int _notifyaboutupdate);
|
||||
void setNotifyAboutNewVersion(int _notifyaboutnewversion);
|
||||
void setUpdateReleaseChannel(int _updateReleaseChannel);
|
||||
void setMaxFontSize(int _max);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,19 +4,18 @@
|
|||
#include <QStringList>
|
||||
#include <utility>
|
||||
|
||||
ShortcutsSettings::ShortcutsSettings(QString settingsPath, QObject *parent) : QObject(parent)
|
||||
ShortcutsSettings::ShortcutsSettings(const QString &settingsPath, QObject *parent) : QObject(parent)
|
||||
{
|
||||
this->settingsFilePath = std::move(settingsPath);
|
||||
this->settingsFilePath.append("shortcuts.ini");
|
||||
fillDefaultShorcuts();
|
||||
shortCuts = QMap<QString, QList<QKeySequence>>(defaultShortCuts);
|
||||
shortCuts = defaultShortCuts;
|
||||
settingsFilePath = settingsPath;
|
||||
settingsFilePath.append("shortcuts.ini");
|
||||
|
||||
bool exists = QFile(settingsFilePath).exists();
|
||||
|
||||
QSettings shortCutsFile(settingsFilePath, QSettings::IniFormat);
|
||||
|
||||
if (exists) {
|
||||
shortCutsFile.beginGroup("Custom");
|
||||
shortCutsFile.beginGroup(custom);
|
||||
const QStringList customKeys = shortCutsFile.allKeys();
|
||||
|
||||
QMap<QString, QString> invalidItems;
|
||||
|
|
@ -55,114 +54,123 @@ ShortcutsSettings::ShortcutsSettings(QString settingsPath, QObject *parent) : QO
|
|||
}
|
||||
}
|
||||
|
||||
QList<QKeySequence> ShortcutsSettings::getShortcut(QString name)
|
||||
QList<QKeySequence> ShortcutsSettings::getDefaultShortcut(const QString &name) const
|
||||
{
|
||||
return defaultShortCuts.value(name, QList<QKeySequence>());
|
||||
}
|
||||
|
||||
QList<QKeySequence> ShortcutsSettings::getShortcut(const QString &name) const
|
||||
{
|
||||
if (shortCuts.contains(name)) {
|
||||
return shortCuts.value(name);
|
||||
}
|
||||
|
||||
return defaultShortCuts.value(name, QList<QKeySequence>());
|
||||
return getDefaultShortcut(name);
|
||||
}
|
||||
|
||||
QKeySequence ShortcutsSettings::getSingleShortcut(QString name)
|
||||
QKeySequence ShortcutsSettings::getSingleShortcut(const QString &name) const
|
||||
{
|
||||
return getShortcut(std::move(name)).at(0);
|
||||
return getShortcut(name).at(0);
|
||||
}
|
||||
|
||||
QString ShortcutsSettings::getDefaultShortcutString(QString name)
|
||||
QString ShortcutsSettings::getDefaultShortcutString(const QString &name) const
|
||||
{
|
||||
return stringifySequence(defaultShortCuts.value(name));
|
||||
return stringifySequence(getDefaultShortcut(name));
|
||||
}
|
||||
|
||||
QString ShortcutsSettings::getShortcutString(QString name)
|
||||
QString ShortcutsSettings::getShortcutString(const QString &name) const
|
||||
{
|
||||
return stringifySequence(shortCuts.value(name));
|
||||
return stringifySequence(getShortcut(name));
|
||||
}
|
||||
|
||||
QString ShortcutsSettings::stringifySequence(QList<QKeySequence> Sequence) const
|
||||
QString ShortcutsSettings::stringifySequence(const QList<QKeySequence> &Sequence) const
|
||||
{
|
||||
QString stringSequence;
|
||||
for (int i = 0; i < Sequence.size(); ++i) {
|
||||
stringSequence.append(Sequence.at(i).toString(QKeySequence::PortableText));
|
||||
if (i < Sequence.size() - 1) {
|
||||
stringSequence.append(";");
|
||||
}
|
||||
QStringList stringSequence;
|
||||
for (const auto &i : Sequence) {
|
||||
stringSequence.append(i.toString(QKeySequence::PortableText));
|
||||
}
|
||||
|
||||
return stringSequence;
|
||||
return stringSequence.join(sep);
|
||||
}
|
||||
|
||||
QList<QKeySequence> ShortcutsSettings::parseSequenceString(QString stringSequence)
|
||||
QList<QKeySequence> ShortcutsSettings::parseSequenceString(const QString &stringSequence) const
|
||||
{
|
||||
QStringList Sequences = stringSequence.split(";");
|
||||
QList<QKeySequence> SequenceList;
|
||||
for (QStringList::const_iterator ss = Sequences.constBegin(); ss != Sequences.constEnd(); ++ss) {
|
||||
SequenceList.append(QKeySequence(*ss, QKeySequence::PortableText));
|
||||
for (const QString &shortcut : stringSequence.split(sep)) {
|
||||
SequenceList.append(QKeySequence(shortcut, QKeySequence::PortableText));
|
||||
}
|
||||
|
||||
return SequenceList;
|
||||
}
|
||||
|
||||
void ShortcutsSettings::setShortcuts(QString name, QList<QKeySequence> Sequence)
|
||||
void ShortcutsSettings::setShortcuts(const QString &name, const QList<QKeySequence> &Sequence)
|
||||
{
|
||||
shortCuts[name] = Sequence;
|
||||
|
||||
QSettings shortCutsFile(settingsFilePath, QSettings::IniFormat);
|
||||
shortCutsFile.beginGroup("Custom");
|
||||
QString stringSequence = stringifySequence(Sequence);
|
||||
shortCutsFile.setValue(name, stringSequence);
|
||||
shortCutsFile.beginGroup(custom);
|
||||
shortCutsFile.setValue(name, stringifySequence(Sequence));
|
||||
shortCutsFile.endGroup();
|
||||
emit shortCutchanged();
|
||||
emit shortCutChanged();
|
||||
}
|
||||
|
||||
void ShortcutsSettings::setShortcuts(QString name, QKeySequence Sequence)
|
||||
void ShortcutsSettings::setShortcuts(const QString &name, const QKeySequence &Sequence)
|
||||
{
|
||||
setShortcuts(std::move(name), QList<QKeySequence>() << Sequence);
|
||||
setShortcuts(name, QList<QKeySequence>{Sequence});
|
||||
}
|
||||
|
||||
void ShortcutsSettings::setShortcuts(QString name, QString Sequences)
|
||||
void ShortcutsSettings::setShortcuts(const QString &name, const QString &Sequences)
|
||||
{
|
||||
setShortcuts(std::move(name), parseSequenceString(std::move(Sequences)));
|
||||
setShortcuts(name, parseSequenceString(Sequences));
|
||||
}
|
||||
|
||||
bool ShortcutsSettings::isKeyAllowed(QString name, QString Sequences)
|
||||
void ShortcutsSettings::resetAllShortcuts()
|
||||
{
|
||||
shortCuts = defaultShortCuts;
|
||||
QSettings shortCutsFile(settingsFilePath, QSettings::IniFormat);
|
||||
shortCutsFile.beginGroup(custom);
|
||||
shortCutsFile.remove("");
|
||||
shortCutsFile.endGroup();
|
||||
emit shortCutChanged();
|
||||
emit allShortCutsReset();
|
||||
}
|
||||
|
||||
void ShortcutsSettings::clearAllShortcuts()
|
||||
{
|
||||
QSettings shortCutsFile(settingsFilePath, QSettings::IniFormat);
|
||||
shortCutsFile.beginGroup(custom);
|
||||
for (auto it = shortCuts.begin(); it != shortCuts.end(); ++it) {
|
||||
it.value() = parseSequenceString("");
|
||||
shortCutsFile.setValue(it.key(), "");
|
||||
}
|
||||
shortCutsFile.endGroup();
|
||||
emit shortCutChanged();
|
||||
emit allShortCutsClear();
|
||||
}
|
||||
|
||||
bool ShortcutsSettings::isKeyAllowed(const QString &name, const QString &Sequences) const
|
||||
{
|
||||
// if the shortcut is not to be used in deck-editor then it doesn't matter
|
||||
if (name.startsWith("Player")) {
|
||||
return true;
|
||||
}
|
||||
QString checkSequence = Sequences.split(";").last();
|
||||
QStringList forbiddenKeys = (QStringList() << "Del"
|
||||
<< "Backspace"
|
||||
<< "Down"
|
||||
<< "Up"
|
||||
<< "Left"
|
||||
<< "Right"
|
||||
<< "Return"
|
||||
<< "Enter"
|
||||
<< "Menu"
|
||||
<< "Ctrl+Alt+-"
|
||||
<< "Ctrl+Alt+="
|
||||
<< "Ctrl+Alt+["
|
||||
<< "Ctrl+Alt+]"
|
||||
<< "Tab"
|
||||
<< "Space"
|
||||
<< "Shift+S"
|
||||
<< "Shift+Left"
|
||||
<< "Shift+Right");
|
||||
QString checkSequence = Sequences.split(sep).last();
|
||||
QStringList forbiddenKeys{"Del", "Backspace", "Down", "Up", "Left", "Right",
|
||||
"Return", "Enter", "Menu", "Ctrl+Alt+-", "Ctrl+Alt+=", "Ctrl+Alt+[",
|
||||
"Ctrl+Alt+]", "Tab", "Space", "Shift+S", "Shift+Left", "Shift+Right"};
|
||||
return !forbiddenKeys.contains(checkSequence);
|
||||
}
|
||||
|
||||
bool ShortcutsSettings::isValid(QString name, QString Sequences)
|
||||
bool ShortcutsSettings::isValid(const QString &name, const QString &Sequences) const
|
||||
{
|
||||
QString checkSequence = Sequences.split(";").last();
|
||||
QString checkSequence = Sequences.split(sep).last();
|
||||
QString checkKey = name.left(name.indexOf("/"));
|
||||
|
||||
QList<QString> allKeys = shortCuts.keys();
|
||||
for (const auto &key : allKeys) {
|
||||
if (key.startsWith(checkKey) || key.startsWith("MainWindow") || checkKey.startsWith("MainWindow")) {
|
||||
QString storedSequence = stringifySequence(shortCuts.value(key));
|
||||
QStringList stringSequences = storedSequence.split(";");
|
||||
QStringList stringSequences = storedSequence.split(sep);
|
||||
if (stringSequences.contains(checkSequence)) {
|
||||
return false;
|
||||
}
|
||||
|
|
@ -170,161 +178,3 @@ bool ShortcutsSettings::isValid(QString name, QString Sequences)
|
|||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ShortcutsSettings::resetAllShortcuts()
|
||||
{
|
||||
for (auto it = defaultShortCuts.begin(); it != defaultShortCuts.end(); ++it) {
|
||||
setShortcuts(it.key(), it.value());
|
||||
}
|
||||
emit allShortCutsReset();
|
||||
}
|
||||
|
||||
void ShortcutsSettings::clearAllShortcuts()
|
||||
{
|
||||
for (auto it = shortCuts.begin(); it != shortCuts.end(); ++it) {
|
||||
setShortcuts(it.key(), "");
|
||||
}
|
||||
emit allShortCutsClear();
|
||||
}
|
||||
|
||||
void ShortcutsSettings::fillDefaultShorcuts()
|
||||
{
|
||||
defaultShortCuts["MainWindow/aCheckCardUpdates"] = parseSequenceString("");
|
||||
defaultShortCuts["MainWindow/aConnect"] = parseSequenceString("Ctrl+L");
|
||||
defaultShortCuts["MainWindow/aDeckEditor"] = parseSequenceString("");
|
||||
defaultShortCuts["MainWindow/aDisconnect"] = parseSequenceString("");
|
||||
defaultShortCuts["MainWindow/aExit"] = parseSequenceString("");
|
||||
defaultShortCuts["MainWindow/aFullScreen"] = parseSequenceString("Ctrl+F");
|
||||
defaultShortCuts["MainWindow/aRegister"] = parseSequenceString("");
|
||||
defaultShortCuts["MainWindow/aSettings"] = parseSequenceString("");
|
||||
defaultShortCuts["MainWindow/aSinglePlayer"] = parseSequenceString("");
|
||||
defaultShortCuts["MainWindow/aWatchReplay"] = parseSequenceString("");
|
||||
|
||||
defaultShortCuts["TabDeckEditor/aAnalyzeDeck"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aClearFilterAll"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aClearFilterOne"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aClose"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aDecrement"] = parseSequenceString("-");
|
||||
defaultShortCuts["TabDeckEditor/aManageSets"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aEditTokens"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aExportDeckDecklist"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aIncrement"] = parseSequenceString("+");
|
||||
defaultShortCuts["TabDeckEditor/aLoadDeck"] = parseSequenceString("Ctrl+O");
|
||||
defaultShortCuts["TabDeckEditor/aLoadDeckFromClipboard"] = parseSequenceString("Ctrl+Shift+V");
|
||||
defaultShortCuts["TabDeckEditor/aNewDeck"] = parseSequenceString("Ctrl+N");
|
||||
defaultShortCuts["TabDeckEditor/aOpenCustomFolder"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aPrintDeck"] = parseSequenceString("Ctrl+P");
|
||||
defaultShortCuts["TabDeckEditor/aRemoveCard"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aResetLayout"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aSaveDeck"] = parseSequenceString("Ctrl+S");
|
||||
defaultShortCuts["TabDeckEditor/aSaveDeckAs"] = parseSequenceString("");
|
||||
defaultShortCuts["TabDeckEditor/aSaveDeckToClipboard"] = parseSequenceString("Ctrl+Shift+C");
|
||||
defaultShortCuts["TabDeckEditor/aSaveDeckToClipboardRaw"] = parseSequenceString("Ctrl+Shift+R");
|
||||
|
||||
defaultShortCuts["DeckViewContainer/loadLocalButton"] = parseSequenceString("Ctrl+O");
|
||||
defaultShortCuts["DeckViewContainer/loadRemoteButton"] = parseSequenceString("Ctrl+Alt+O");
|
||||
|
||||
defaultShortCuts["Player/aDec"] = parseSequenceString("F11");
|
||||
defaultShortCuts["Player/aInc"] = parseSequenceString("F12");
|
||||
defaultShortCuts["Player/aSet"] = parseSequenceString("Ctrl+L");
|
||||
defaultShortCuts["Player/aCloseMostRecentZoneView"] = parseSequenceString("Esc");
|
||||
defaultShortCuts["Player/IncP"] = parseSequenceString("Ctrl++");
|
||||
defaultShortCuts["Player/aAlwaysRevealTopCard"] = parseSequenceString("Ctrl+N");
|
||||
defaultShortCuts["Player/aAttach"] = parseSequenceString("Ctrl+Alt+A");
|
||||
defaultShortCuts["Player/aCCGreen"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aCCRed"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aCCYellow"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aClone"] = parseSequenceString("Ctrl+J");
|
||||
defaultShortCuts["Player/aCreateAnotherToken"] = parseSequenceString("Ctrl+G");
|
||||
defaultShortCuts["Player/aCreateToken"] = parseSequenceString("Ctrl+T");
|
||||
defaultShortCuts["Player/aCreateRelatedTokens"] = parseSequenceString("Ctrl+Shift+T");
|
||||
defaultShortCuts["Player/aDecP"] = parseSequenceString("Ctrl+-");
|
||||
defaultShortCuts["Player/aDecPT"] = parseSequenceString("Ctrl+Alt+-");
|
||||
defaultShortCuts["Player/aDecT"] = parseSequenceString("Alt+-");
|
||||
defaultShortCuts["Player/aDoesntUntap"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aDrawArrow"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aDrawCard"] = parseSequenceString("Ctrl+D");
|
||||
defaultShortCuts["Player/aDrawCards"] = parseSequenceString("Ctrl+E");
|
||||
defaultShortCuts["Player/aFlip"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aIncPT"] = parseSequenceString("Ctrl+Alt++");
|
||||
defaultShortCuts["Player/aIncT"] = parseSequenceString("Alt++");
|
||||
defaultShortCuts["Player/aMoveToBottomLibrary"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aMoveToExile"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aMoveToGraveyard"] = parseSequenceString("Ctrl+Del");
|
||||
defaultShortCuts["Player/aMoveToHand"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aMoveToTopLibrary"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aMulligan"] = parseSequenceString("Ctrl+M");
|
||||
defaultShortCuts["Player/aPeek"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aPlay"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aRCGreen"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aRCRed"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aRCYellow"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aRollDie"] = parseSequenceString("Ctrl+I");
|
||||
defaultShortCuts["Player/aSCGreen"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSCRed"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSCYellow"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSetAnnotation"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSetPT"] = parseSequenceString("Ctrl+P");
|
||||
defaultShortCuts["Player/aResetPT"] = parseSequenceString("Ctrl+Alt+0");
|
||||
defaultShortCuts["Player/aShuffle"] = parseSequenceString("Ctrl+S");
|
||||
defaultShortCuts["Player/aTap"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aUnattach"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aUndoDraw"] = parseSequenceString("Ctrl+Shift+D");
|
||||
defaultShortCuts["Player/aUntapAll"] = parseSequenceString("Ctrl+U");
|
||||
defaultShortCuts["Player/aViewGraveyard"] = parseSequenceString("F4");
|
||||
defaultShortCuts["Player/aViewLibrary"] = parseSequenceString("F3");
|
||||
defaultShortCuts["Player/aViewRfg"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aViewSideboard"] = parseSequenceString("Ctrl+F3");
|
||||
defaultShortCuts["Player/aViewTopCards"] = parseSequenceString("Ctrl+W");
|
||||
defaultShortCuts["Player/aConcede"] = parseSequenceString("F2");
|
||||
defaultShortCuts["Player/aLeaveGame"] = parseSequenceString("Ctrl+Q");
|
||||
defaultShortCuts["Player/aNextPhase"] = parseSequenceString("Ctrl+Space;Tab");
|
||||
defaultShortCuts["Player/aNextTurn"] = parseSequenceString("Ctrl+Return;Ctrl+Enter");
|
||||
defaultShortCuts["Player/aRemoveLocalArrows"] = parseSequenceString("Ctrl+R");
|
||||
defaultShortCuts["Player/aRotateViewCCW"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aRotateViewCW"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/phase0"] = parseSequenceString("F5");
|
||||
defaultShortCuts["Player/phase1"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/phase10"] = parseSequenceString("F10");
|
||||
defaultShortCuts["Player/phase2"] = parseSequenceString("F6");
|
||||
defaultShortCuts["Player/phase3"] = parseSequenceString("F7");
|
||||
defaultShortCuts["Player/phase4"] = parseSequenceString("F8");
|
||||
defaultShortCuts["Player/phase5"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/phase6"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/phase7"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/phase8"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/phase9"] = parseSequenceString("F9");
|
||||
|
||||
defaultShortCuts["Player/aIncCounter_w"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aDecCounter_w"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSetCounter_w"] = parseSequenceString("");
|
||||
|
||||
defaultShortCuts["Player/aIncCounter_u"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aDecCounter_u"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSetCounter_u"] = parseSequenceString("");
|
||||
|
||||
defaultShortCuts["Player/aIncCounter_b"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aDecCounter_b"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSetCounter_b"] = parseSequenceString("");
|
||||
|
||||
defaultShortCuts["Player/aIncCounter_r"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aDecCounter_r"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSetCounter_r"] = parseSequenceString("");
|
||||
|
||||
defaultShortCuts["Player/aIncCounter_g"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aDecCounter_g"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSetCounter_g"] = parseSequenceString("");
|
||||
|
||||
defaultShortCuts["Player/aIncCounter_x"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aDecCounter_x"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSetCounter_x"] = parseSequenceString("");
|
||||
|
||||
defaultShortCuts["Player/aIncCounter_storm"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aDecCounter_storm"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aSetCounter_storm"] = parseSequenceString("");
|
||||
|
||||
defaultShortCuts["tab_room/aClearChat"] = parseSequenceString("F12");
|
||||
defaultShortCuts["DlgLoadDeckFromClipboard/refreshButton"] = parseSequenceString("F5");
|
||||
defaultShortCuts["Player/aResetLayout"] = parseSequenceString("");
|
||||
defaultShortCuts["Player/aMoveTopToPlayFaceDown"] = parseSequenceString("Ctrl+Shift+E");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
#ifndef SHORTCUTSSETTINGS_H
|
||||
#define SHORTCUTSSETTINGS_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QKeySequence>
|
||||
#include <QMap>
|
||||
#include <QObject>
|
||||
#include <QSettings>
|
||||
|
||||
|
|
@ -10,37 +10,186 @@ class ShortcutsSettings : public QObject
|
|||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
ShortcutsSettings(QString settingsFilePath, QObject *parent = nullptr);
|
||||
ShortcutsSettings(const QString &settingsFilePath, QObject *parent = nullptr);
|
||||
|
||||
QList<QKeySequence> getShortcut(QString name);
|
||||
QKeySequence getSingleShortcut(QString name);
|
||||
QList<QKeySequence> getDefaultShortcut(const QString &name) const;
|
||||
QList<QKeySequence> getShortcut(const QString &name) const;
|
||||
QKeySequence getSingleShortcut(const QString &name) const;
|
||||
QString getDefaultShortcutString(const QString &name) const;
|
||||
QString getShortcutString(const QString &name) const;
|
||||
|
||||
QString getDefaultShortcutString(QString name);
|
||||
QString getShortcutString(QString name);
|
||||
void setShortcuts(const QString &name, const QList<QKeySequence> &Sequence);
|
||||
void setShortcuts(const QString &name, const QKeySequence &Sequence);
|
||||
void setShortcuts(const QString &name, const QString &Sequences);
|
||||
|
||||
void setShortcuts(QString name, QList<QKeySequence> Sequence);
|
||||
void setShortcuts(QString name, QKeySequence Sequence);
|
||||
void setShortcuts(QString name, QString Sequences);
|
||||
|
||||
bool isKeyAllowed(QString name, QString Sequences);
|
||||
bool isValid(QString name, QString Sequences);
|
||||
bool isKeyAllowed(const QString &name, const QString &Sequences) const;
|
||||
bool isValid(const QString &name, const QString &Sequences) const;
|
||||
|
||||
void resetAllShortcuts();
|
||||
void clearAllShortcuts();
|
||||
|
||||
signals:
|
||||
void shortCutchanged();
|
||||
void shortCutChanged();
|
||||
void allShortCutsReset();
|
||||
void allShortCutsClear();
|
||||
|
||||
private:
|
||||
const QChar sep = ';';
|
||||
const QString custom = "Custom";
|
||||
QString settingsFilePath;
|
||||
QMap<QString, QList<QKeySequence>> shortCuts;
|
||||
QMap<QString, QList<QKeySequence>> defaultShortCuts;
|
||||
void fillDefaultShorcuts();
|
||||
QHash<QString, QList<QKeySequence>> shortCuts;
|
||||
|
||||
QString stringifySequence(QList<QKeySequence> Sequence) const;
|
||||
QList<QKeySequence> parseSequenceString(QString stringSequence);
|
||||
QString stringifySequence(const QList<QKeySequence> &Sequence) const;
|
||||
QList<QKeySequence> parseSequenceString(const QString &stringSequence) const;
|
||||
|
||||
const QHash<QString, QList<QKeySequence>> defaultShortCuts{
|
||||
{"MainWindow/aCheckCardUpdates", parseSequenceString("")},
|
||||
{"MainWindow/aConnect", parseSequenceString("Ctrl+L")},
|
||||
{"MainWindow/aDeckEditor", parseSequenceString("")},
|
||||
{"MainWindow/aDisconnect", parseSequenceString("")},
|
||||
{"MainWindow/aExit", parseSequenceString("")},
|
||||
{"MainWindow/aFullScreen", parseSequenceString("Ctrl+F")},
|
||||
{"MainWindow/aRegister", parseSequenceString("")},
|
||||
{"MainWindow/aSettings", parseSequenceString("")},
|
||||
{"MainWindow/aSinglePlayer", parseSequenceString("")},
|
||||
{"MainWindow/aWatchReplay", parseSequenceString("")},
|
||||
|
||||
{"TabDeckEditor/aAnalyzeDeck", parseSequenceString("")},
|
||||
{"TabDeckEditor/aClearFilterAll", parseSequenceString("")},
|
||||
{"TabDeckEditor/aClearFilterOne", parseSequenceString("")},
|
||||
{"TabDeckEditor/aClose", parseSequenceString("")},
|
||||
{"TabDeckEditor/aDecrement", parseSequenceString("-")},
|
||||
{"TabDeckEditor/aManageSets", parseSequenceString("")},
|
||||
{"TabDeckEditor/aEditTokens", parseSequenceString("")},
|
||||
{"TabDeckEditor/aExportDeckDecklist", parseSequenceString("")},
|
||||
{"TabDeckEditor/aIncrement", parseSequenceString("+")},
|
||||
{"TabDeckEditor/aLoadDeck", parseSequenceString("Ctrl+O")},
|
||||
{"TabDeckEditor/aLoadDeckFromClipboard", parseSequenceString("Ctrl+Shift+V")},
|
||||
{"TabDeckEditor/aNewDeck", parseSequenceString("Ctrl+N")},
|
||||
{"TabDeckEditor/aOpenCustomFolder", parseSequenceString("")},
|
||||
{"TabDeckEditor/aPrintDeck", parseSequenceString("Ctrl+P")},
|
||||
{"TabDeckEditor/aRemoveCard", parseSequenceString("")},
|
||||
{"TabDeckEditor/aResetLayout", parseSequenceString("")},
|
||||
{"TabDeckEditor/aSaveDeck", parseSequenceString("Ctrl+S")},
|
||||
{"TabDeckEditor/aSaveDeckAs", parseSequenceString("")},
|
||||
{"TabDeckEditor/aSaveDeckToClipboard", parseSequenceString("Ctrl+Shift+C")},
|
||||
{"TabDeckEditor/aSaveDeckToClipboardRaw", parseSequenceString("Ctrl+Shift+R")},
|
||||
|
||||
{"DeckViewContainer/loadLocalButton", parseSequenceString("Ctrl+O")},
|
||||
{"DeckViewContainer/loadRemoteButton", parseSequenceString("Ctrl+Alt+O")},
|
||||
|
||||
{"Player/aSet", parseSequenceString("Ctrl+L")},
|
||||
{"Player/aAlwaysRevealTopCard", parseSequenceString("Ctrl+N")},
|
||||
{"Player/aCloseMostRecentZoneView", parseSequenceString("Esc")},
|
||||
{"Player/aDrawCard", parseSequenceString("Ctrl+D")},
|
||||
{"Player/aDrawCards", parseSequenceString("Ctrl+E")},
|
||||
{"Player/aDec", parseSequenceString("F11")},
|
||||
{"Player/aInc", parseSequenceString("F12")},
|
||||
{"Player/aMoveTopCardToGraveyard", parseSequenceString("")},
|
||||
{"Player/aMoveTopCardsToGraveyard", parseSequenceString("Ctrl+Shift+M")},
|
||||
{"Player/aMoveTopCardToExile", parseSequenceString("")},
|
||||
{"Player/aMoveTopCardsToExile", parseSequenceString("")},
|
||||
{"Player/aMoveTopToPlayFaceDown", parseSequenceString("Ctrl+Shift+E")},
|
||||
{"Player/aMulligan", parseSequenceString("Ctrl+M")},
|
||||
{"Player/aPeek", parseSequenceString("")},
|
||||
{"Player/aPlay", parseSequenceString("")},
|
||||
{"Player/aResetLayout", parseSequenceString("")},
|
||||
{"Player/aRollDie", parseSequenceString("Ctrl+I")},
|
||||
{"Player/aShuffle", parseSequenceString("Ctrl+S")},
|
||||
{"Player/aUndoDraw", parseSequenceString("Ctrl+Shift+D")},
|
||||
{"Player/aUntapAll", parseSequenceString("Ctrl+U")},
|
||||
{"Player/aViewGraveyard", parseSequenceString("F4")},
|
||||
{"Player/aViewLibrary", parseSequenceString("F3")},
|
||||
{"Player/aViewRfg", parseSequenceString("")},
|
||||
{"Player/aViewSideboard", parseSequenceString("Ctrl+F3")},
|
||||
{"Player/aViewTopCards", parseSequenceString("Ctrl+W")},
|
||||
|
||||
{"Player/aAttach", parseSequenceString("Ctrl+Alt+A")},
|
||||
{"Player/aClone", parseSequenceString("Ctrl+J")},
|
||||
{"Player/aCreateAnotherToken", parseSequenceString("Ctrl+G")},
|
||||
{"Player/aCreateToken", parseSequenceString("Ctrl+T")},
|
||||
{"Player/aCreateRelatedTokens", parseSequenceString("Ctrl+Shift+T")},
|
||||
{"Player/aDoesntUntap", parseSequenceString("")},
|
||||
{"Player/aDrawArrow", parseSequenceString("")},
|
||||
{"Player/aFlip", parseSequenceString("")},
|
||||
{"Player/aMoveToBottomLibrary", parseSequenceString("")},
|
||||
{"Player/aMoveToExile", parseSequenceString("")},
|
||||
{"Player/aMoveToGraveyard", parseSequenceString("Ctrl+Del")},
|
||||
{"Player/aMoveToHand", parseSequenceString("")},
|
||||
{"Player/aMoveToTopLibrary", parseSequenceString("")},
|
||||
{"Player/aSetAnnotation", parseSequenceString("")},
|
||||
{"Player/aTap", parseSequenceString("")},
|
||||
{"Player/aUnattach", parseSequenceString("")},
|
||||
|
||||
{"Player/aCCGreen", parseSequenceString("")},
|
||||
{"Player/aCCRed", parseSequenceString("")},
|
||||
{"Player/aCCYellow", parseSequenceString("")},
|
||||
{"Player/aRCGreen", parseSequenceString("")},
|
||||
{"Player/aRCRed", parseSequenceString("")},
|
||||
{"Player/aRCYellow", parseSequenceString("")},
|
||||
{"Player/aSCGreen", parseSequenceString("")},
|
||||
{"Player/aSCRed", parseSequenceString("")},
|
||||
{"Player/aSCYellow", parseSequenceString("")},
|
||||
|
||||
{"Player/aDecP", parseSequenceString("Ctrl+-")},
|
||||
{"Player/aDecPT", parseSequenceString("Ctrl+Alt+-")},
|
||||
{"Player/aDecT", parseSequenceString("Alt+-")},
|
||||
{"Player/aIncP", parseSequenceString("Ctrl++")},
|
||||
{"Player/aIncPT", parseSequenceString("Ctrl+Alt++")},
|
||||
{"Player/aIncT", parseSequenceString("Alt++")},
|
||||
{"Player/aSetPT", parseSequenceString("Ctrl+P")},
|
||||
{"Player/aResetPT", parseSequenceString("Ctrl+Alt+0")},
|
||||
|
||||
{"Player/aConcede", parseSequenceString("F2")},
|
||||
{"Player/aLeaveGame", parseSequenceString("Ctrl+Q")},
|
||||
{"Player/aNextPhase", parseSequenceString("Ctrl+Space;Tab")},
|
||||
{"Player/aNextPhaseAction", parseSequenceString("Shift+Tab")},
|
||||
{"Player/aNextTurn", parseSequenceString("Ctrl+Return;Ctrl+Enter")},
|
||||
{"Player/aRemoveLocalArrows", parseSequenceString("Ctrl+R")},
|
||||
{"Player/aRotateViewCCW", parseSequenceString("")},
|
||||
{"Player/aRotateViewCW", parseSequenceString("")},
|
||||
{"Player/phase0", parseSequenceString("F5")},
|
||||
{"Player/phase1", parseSequenceString("")},
|
||||
{"Player/phase10", parseSequenceString("F10")},
|
||||
{"Player/phase2", parseSequenceString("F6")},
|
||||
{"Player/phase3", parseSequenceString("F7")},
|
||||
{"Player/phase4", parseSequenceString("F8")},
|
||||
{"Player/phase5", parseSequenceString("")},
|
||||
{"Player/phase6", parseSequenceString("")},
|
||||
{"Player/phase7", parseSequenceString("")},
|
||||
{"Player/phase8", parseSequenceString("")},
|
||||
{"Player/phase9", parseSequenceString("F9")},
|
||||
|
||||
{"Player/aDecCounter_w", parseSequenceString("")},
|
||||
{"Player/aIncCounter_w", parseSequenceString("")},
|
||||
{"Player/aSetCounter_w", parseSequenceString("")},
|
||||
|
||||
{"Player/aDecCounter_u", parseSequenceString("")},
|
||||
{"Player/aIncCounter_u", parseSequenceString("")},
|
||||
{"Player/aSetCounter_u", parseSequenceString("")},
|
||||
|
||||
{"Player/aDecCounter_b", parseSequenceString("")},
|
||||
{"Player/aIncCounter_b", parseSequenceString("")},
|
||||
{"Player/aSetCounter_b", parseSequenceString("")},
|
||||
|
||||
{"Player/aDecCounter_r", parseSequenceString("")},
|
||||
{"Player/aIncCounter_r", parseSequenceString("")},
|
||||
{"Player/aSetCounter_r", parseSequenceString("")},
|
||||
|
||||
{"Player/aDecCounter_g", parseSequenceString("")},
|
||||
{"Player/aIncCounter_g", parseSequenceString("")},
|
||||
{"Player/aSetCounter_g", parseSequenceString("")},
|
||||
|
||||
{"Player/aDecCounter_x", parseSequenceString("")},
|
||||
{"Player/aIncCounter_x", parseSequenceString("")},
|
||||
{"Player/aSetCounter_x", parseSequenceString("")},
|
||||
|
||||
{"Player/aDecCounter_storm", parseSequenceString("")},
|
||||
{"Player/aIncCounter_storm", parseSequenceString("")},
|
||||
{"Player/aSetCounter_storm", parseSequenceString("")},
|
||||
|
||||
{"tab_room/aClearChat", parseSequenceString("F12")},
|
||||
{"DlgLoadDeckFromClipboard/refreshButton", parseSequenceString("F5")}};
|
||||
};
|
||||
|
||||
#endif // SHORTCUTSSETTINGS_H
|
||||
|
|
|
|||
|
|
@ -590,7 +590,7 @@ TabDeckEditor::TabDeckEditor(TabSupervisor *_tabSupervisor, QWidget *parent)
|
|||
this->installEventFilter(this);
|
||||
|
||||
retranslateUi();
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()), this, SLOT(refreshShortcuts()));
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||
refreshShortcuts();
|
||||
|
||||
QTimer::singleShot(0, this, SLOT(loadLayout()));
|
||||
|
|
|
|||
|
|
@ -95,7 +95,7 @@ void ToggleButton::setState(bool _state)
|
|||
}
|
||||
|
||||
DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
||||
: QWidget(0), parentGame(parent), playerId(_playerId)
|
||||
: QWidget(nullptr), parentGame(parent), playerId(_playerId)
|
||||
{
|
||||
loadLocalButton = new QPushButton;
|
||||
loadRemoteButton = new QPushButton;
|
||||
|
|
@ -112,7 +112,7 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
|||
connect(sideboardLockButton, SIGNAL(clicked()), this, SLOT(sideboardLockButtonClicked()));
|
||||
connect(sideboardLockButton, SIGNAL(stateChanged()), this, SLOT(updateSideboardLockButtonText()));
|
||||
|
||||
QHBoxLayout *buttonHBox = new QHBoxLayout;
|
||||
auto *buttonHBox = new QHBoxLayout;
|
||||
buttonHBox->addWidget(loadLocalButton);
|
||||
buttonHBox->addWidget(loadRemoteButton);
|
||||
buttonHBox->addWidget(readyStartButton);
|
||||
|
|
@ -123,14 +123,14 @@ DeckViewContainer::DeckViewContainer(int _playerId, TabGame *parent)
|
|||
connect(deckView, SIGNAL(newCardAdded(AbstractCardItem *)), this, SIGNAL(newCardAdded(AbstractCardItem *)));
|
||||
connect(deckView, SIGNAL(sideboardPlanChanged()), this, SLOT(sideboardPlanChanged()));
|
||||
|
||||
QVBoxLayout *deckViewLayout = new QVBoxLayout;
|
||||
auto *deckViewLayout = new QVBoxLayout;
|
||||
deckViewLayout->addLayout(buttonHBox);
|
||||
deckViewLayout->addWidget(deckView);
|
||||
deckViewLayout->setContentsMargins(0, 0, 0, 0);
|
||||
setLayout(deckViewLayout);
|
||||
|
||||
retranslateUi();
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()), this, SLOT(refreshShortcuts()));
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||
refreshShortcuts();
|
||||
}
|
||||
|
||||
|
|
@ -209,6 +209,9 @@ void TabGame::refreshShortcuts()
|
|||
if (aNextPhase) {
|
||||
aNextPhase->setShortcuts(settingsCache->shortcuts().getShortcut("Player/aNextPhase"));
|
||||
}
|
||||
if (aNextPhaseAction) {
|
||||
aNextPhaseAction->setShortcuts(settingsCache->shortcuts().getShortcut("Player/aNextPhaseAction"));
|
||||
}
|
||||
if (aNextTurn) {
|
||||
aNextTurn->setShortcuts(settingsCache->shortcuts().getShortcut("Player/aNextTurn"));
|
||||
}
|
||||
|
|
@ -299,8 +302,8 @@ void DeckViewContainer::sideboardPlanChanged()
|
|||
{
|
||||
Command_SetSideboardPlan cmd;
|
||||
const QList<MoveCard_ToZone> &newPlan = deckView->getSideboardPlan();
|
||||
for (int i = 0; i < newPlan.size(); ++i)
|
||||
cmd.add_move_list()->CopyFrom(newPlan.at(i));
|
||||
for (const auto &i : newPlan)
|
||||
cmd.add_move_list()->CopyFrom(i);
|
||||
parentGame->sendGameCommand(cmd, playerId);
|
||||
}
|
||||
|
||||
|
|
@ -330,7 +333,8 @@ void DeckViewContainer::setDeck(const DeckLoader &deck)
|
|||
TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
||||
: Tab(_tabSupervisor), secondsElapsed(0), hostId(-1), localPlayerId(-1),
|
||||
isLocalGame(_tabSupervisor->getIsLocalGame()), spectator(true), gameStateKnown(false), resuming(false),
|
||||
currentPhase(-1), activeCard(0), gameClosed(false), replay(_replay), currentReplayStep(0), sayLabel(0), sayEdit(0)
|
||||
currentPhase(-1), activeCard(nullptr), gameClosed(false), replay(_replay), currentReplayStep(0),
|
||||
sayLabel(nullptr), sayEdit(nullptr)
|
||||
{
|
||||
// THIS CTOR IS USED ON REPLAY
|
||||
gameInfo.CopyFrom(replay->game_info());
|
||||
|
|
@ -375,7 +379,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor, GameReplay *_replay)
|
|||
createReplayMenuItems();
|
||||
createViewMenuItems();
|
||||
retranslateUi();
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()), this, SLOT(refreshShortcuts()));
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||
refreshShortcuts();
|
||||
messageLog->logReplayStarted(gameInfo.game_id());
|
||||
|
||||
|
|
@ -389,8 +393,8 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
|
|||
const QMap<int, QString> &_roomGameTypes)
|
||||
: Tab(_tabSupervisor), clients(_clients), gameInfo(event.game_info()), roomGameTypes(_roomGameTypes),
|
||||
hostId(event.host_id()), localPlayerId(event.player_id()), isLocalGame(_tabSupervisor->getIsLocalGame()),
|
||||
spectator(event.spectator()), gameStateKnown(false), resuming(event.resuming()), currentPhase(-1), activeCard(0),
|
||||
gameClosed(false), replay(0), replayDock(0)
|
||||
spectator(event.spectator()), gameStateKnown(false), resuming(event.resuming()), currentPhase(-1),
|
||||
activeCard(nullptr), gameClosed(false), replay(nullptr), replayDock(nullptr)
|
||||
{
|
||||
// THIS CTOR IS USED ON GAMES
|
||||
gameInfo.set_started(false);
|
||||
|
|
@ -414,7 +418,7 @@ TabGame::TabGame(TabSupervisor *_tabSupervisor,
|
|||
createMenuItems();
|
||||
createViewMenuItems();
|
||||
retranslateUi();
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()), this, SLOT(refreshShortcuts()));
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||
refreshShortcuts();
|
||||
|
||||
// append game to rooms game list for others to see
|
||||
|
|
@ -486,6 +490,9 @@ void TabGame::retranslateUi()
|
|||
if (aNextPhase) {
|
||||
aNextPhase->setText(tr("Next &phase"));
|
||||
}
|
||||
if (aNextPhaseAction) {
|
||||
aNextPhaseAction->setText(tr("Next phase with &action"));
|
||||
}
|
||||
if (aNextTurn) {
|
||||
aNextTurn->setText(tr("Next &turn"));
|
||||
}
|
||||
|
|
@ -554,7 +561,7 @@ void TabGame::closeRequest()
|
|||
|
||||
void TabGame::replayNextEvent()
|
||||
{
|
||||
processGameEventContainer(replay->event_list(timelineWidget->getCurrentEvent()), 0);
|
||||
processGameEventContainer(replay->event_list(timelineWidget->getCurrentEvent()), nullptr);
|
||||
}
|
||||
|
||||
void TabGame::replayFinished()
|
||||
|
|
@ -620,11 +627,23 @@ void TabGame::actGameInfo()
|
|||
|
||||
void TabGame::actConcede()
|
||||
{
|
||||
if (QMessageBox::question(this, tr("Concede"), tr("Are you sure you want to concede this game?"),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes)
|
||||
Player *player = players.value(localPlayerId, nullptr);
|
||||
if (player == nullptr)
|
||||
return;
|
||||
if (!player->getConceded()) {
|
||||
if (QMessageBox::question(this, tr("Concede"), tr("Are you sure you want to concede this game?"),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
sendGameCommand(Command_Concede());
|
||||
sendGameCommand(Command_Concede());
|
||||
} else {
|
||||
if (QMessageBox::question(this, tr("Unconcede"),
|
||||
tr("You have already conceded. Do you want to return to this game?"),
|
||||
QMessageBox::Yes | QMessageBox::No, QMessageBox::No) != QMessageBox::Yes)
|
||||
return;
|
||||
|
||||
sendGameCommand(Command_Unconcede());
|
||||
}
|
||||
}
|
||||
|
||||
void TabGame::actLeaveGame()
|
||||
|
|
@ -659,7 +678,7 @@ void TabGame::actPhaseAction()
|
|||
{
|
||||
int phase = phaseActions.indexOf(static_cast<QAction *>(sender()));
|
||||
Command_SetActivePhase cmd;
|
||||
cmd.set_phase(phase);
|
||||
cmd.set_phase(static_cast<google::protobuf::uint32>(phase));
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
|
|
@ -669,10 +688,29 @@ void TabGame::actNextPhase()
|
|||
if (++phase >= phasesToolbar->phaseCount())
|
||||
phase = 0;
|
||||
Command_SetActivePhase cmd;
|
||||
cmd.set_phase(phase);
|
||||
cmd.set_phase(static_cast<google::protobuf::uint32>(phase));
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
void TabGame::actNextPhaseAction()
|
||||
{
|
||||
int phase = currentPhase + 1;
|
||||
if (phase >= phasesToolbar->phaseCount()) {
|
||||
phase = 0;
|
||||
}
|
||||
|
||||
if (phase == 0) {
|
||||
Command_NextTurn cmd;
|
||||
sendGameCommand(cmd);
|
||||
} else {
|
||||
Command_SetActivePhase cmd;
|
||||
cmd.set_phase(static_cast<google::protobuf::uint32>(phase));
|
||||
sendGameCommand(cmd);
|
||||
}
|
||||
|
||||
phasesToolbar->triggerPhaseAction(phase);
|
||||
}
|
||||
|
||||
void TabGame::actNextTurn()
|
||||
{
|
||||
sendGameCommand(Command_NextTurn());
|
||||
|
|
@ -713,7 +751,7 @@ void TabGame::actCompleterChanged()
|
|||
Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info)
|
||||
{
|
||||
bool local = ((clients.size() > 1) || (playerId == localPlayerId));
|
||||
Player *newPlayer = new Player(info, playerId, local, this);
|
||||
auto *newPlayer = new Player(info, playerId, local, this);
|
||||
connect(newPlayer, SIGNAL(openDeckEditor(const DeckLoader *)), this, SIGNAL(openDeckEditor(const DeckLoader *)));
|
||||
QString newPlayerName = "@" + newPlayer->getName();
|
||||
if (sayEdit && !autocompleteUserList.contains(newPlayerName)) {
|
||||
|
|
@ -729,7 +767,7 @@ Player *TabGame::addPlayer(int playerId, const ServerInfo_User &info)
|
|||
if (clients.size() == 1)
|
||||
newPlayer->setShortcutsActive();
|
||||
|
||||
DeckViewContainer *deckView = new DeckViewContainer(playerId, this);
|
||||
auto *deckView = new DeckViewContainer(playerId, this);
|
||||
connect(deckView, SIGNAL(newCardAdded(AbstractCardItem *)), this, SLOT(newCardAdded(AbstractCardItem *)));
|
||||
deckViewContainers.insert(playerId, deckView);
|
||||
deckViewContainerLayout->addWidget(deckView);
|
||||
|
|
@ -750,7 +788,7 @@ void TabGame::processGameEventContainer(const GameEventContainer &cont, Abstract
|
|||
for (int i = 0; i < eventListSize; ++i) {
|
||||
const GameEvent &event = cont.event_list(i);
|
||||
const int playerId = event.player_id();
|
||||
const GameEvent::GameEventType eventType = static_cast<GameEvent::GameEventType>(getPbExtension(event));
|
||||
const auto eventType = static_cast<GameEvent::GameEventType>(getPbExtension(event));
|
||||
if (spectators.contains(playerId)) {
|
||||
switch (eventType) {
|
||||
case GameEvent::GAME_SAY:
|
||||
|
|
@ -822,7 +860,7 @@ AbstractClient *TabGame::getClientForPlayer(int playerId) const
|
|||
|
||||
return clients.at(playerId);
|
||||
} else if (clients.isEmpty())
|
||||
return 0;
|
||||
return nullptr;
|
||||
else
|
||||
return clients.first();
|
||||
}
|
||||
|
|
@ -859,7 +897,7 @@ void TabGame::commandFinished(const Response &response)
|
|||
PendingCommand *TabGame::prepareGameCommand(const ::google::protobuf::Message &cmd)
|
||||
{
|
||||
CommandContainer cont;
|
||||
cont.set_game_id(gameInfo.game_id());
|
||||
cont.set_game_id(static_cast<google::protobuf::uint32>(gameInfo.game_id()));
|
||||
GameCommand *c = cont.add_game_command();
|
||||
c->GetReflection()->MutableMessage(c, cmd.GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(cmd);
|
||||
return new PendingCommand(cont);
|
||||
|
|
@ -868,13 +906,11 @@ PendingCommand *TabGame::prepareGameCommand(const ::google::protobuf::Message &c
|
|||
PendingCommand *TabGame::prepareGameCommand(const QList<const ::google::protobuf::Message *> &cmdList)
|
||||
{
|
||||
CommandContainer cont;
|
||||
cont.set_game_id(gameInfo.game_id());
|
||||
for (int i = 0; i < cmdList.size(); ++i) {
|
||||
cont.set_game_id(static_cast<google::protobuf::uint32>(gameInfo.game_id()));
|
||||
for (auto i : cmdList) {
|
||||
GameCommand *c = cont.add_game_command();
|
||||
c->GetReflection()
|
||||
->MutableMessage(c, cmdList[i]->GetDescriptor()->FindExtensionByName("ext"))
|
||||
->CopyFrom(*cmdList[i]);
|
||||
delete cmdList[i];
|
||||
c->GetReflection()->MutableMessage(c, i->GetDescriptor()->FindExtensionByName("ext"))->CopyFrom(*i);
|
||||
delete i;
|
||||
}
|
||||
return new PendingCommand(cont);
|
||||
}
|
||||
|
|
@ -1028,8 +1064,7 @@ void TabGame::eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged &
|
|||
const ServerInfo_PlayerProperties &prop = event.player_properties();
|
||||
playerListWidget->updatePlayerProperties(prop, eventPlayerId);
|
||||
|
||||
const GameEventContext::ContextType contextType =
|
||||
static_cast<GameEventContext::ContextType>(getPbExtension(context));
|
||||
const auto contextType = static_cast<GameEventContext::ContextType>(getPbExtension(context));
|
||||
switch (contextType) {
|
||||
case GameEventContext::READY_START: {
|
||||
bool ready = prop.ready_start();
|
||||
|
|
@ -1051,6 +1086,16 @@ void TabGame::eventPlayerPropertiesChanged(const Event_PlayerPropertiesChanged &
|
|||
|
||||
break;
|
||||
}
|
||||
case GameEventContext::UNCONCEDE: {
|
||||
messageLog->logUnconcede(player);
|
||||
player->setConceded(false);
|
||||
|
||||
QMapIterator<int, Player *> playerIterator(players);
|
||||
while (playerIterator.hasNext())
|
||||
playerIterator.next().value()->updateZones();
|
||||
|
||||
break;
|
||||
}
|
||||
case GameEventContext::DECK_SELECT: {
|
||||
Context_DeckSelect deckSelect = context.GetExtension(Context_DeckSelect::ext);
|
||||
messageLog->logDeckSelect(player, QString::fromStdString(deckSelect.deck_hash()),
|
||||
|
|
@ -1173,7 +1218,7 @@ Player *TabGame::setActivePlayer(int id)
|
|||
{
|
||||
Player *player = players.value(id, 0);
|
||||
if (!player)
|
||||
return 0;
|
||||
return nullptr;
|
||||
activePlayer = id;
|
||||
playerListWidget->setActivePlayer(id);
|
||||
QMapIterator<int, Player *> i(players);
|
||||
|
|
@ -1237,11 +1282,11 @@ CardItem *TabGame::getCard(int playerId, const QString &zoneName, int cardId) co
|
|||
{
|
||||
Player *player = players.value(playerId, 0);
|
||||
if (!player)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
CardZone *zone = player->getZones().value(zoneName, 0);
|
||||
if (!zone)
|
||||
return 0;
|
||||
return nullptr;
|
||||
|
||||
return zone->getCard(cardId, QString());
|
||||
}
|
||||
|
|
@ -1249,7 +1294,7 @@ CardItem *TabGame::getCard(int playerId, const QString &zoneName, int cardId) co
|
|||
QString TabGame::getTabText() const
|
||||
{
|
||||
QString gameTypeInfo;
|
||||
if (gameTypes.size() != 0) {
|
||||
if (!gameTypes.empty()) {
|
||||
gameTypeInfo = gameTypes.at(0);
|
||||
if (gameTypes.size() > 1)
|
||||
gameTypeInfo.append("...");
|
||||
|
|
@ -1290,7 +1335,7 @@ Player *TabGame::getActiveLocalPlayer() const
|
|||
return temp;
|
||||
}
|
||||
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void TabGame::updateCardMenu(AbstractCardItem *card)
|
||||
|
|
@ -1307,6 +1352,8 @@ void TabGame::createMenuItems()
|
|||
{
|
||||
aNextPhase = new QAction(this);
|
||||
connect(aNextPhase, SIGNAL(triggered()), this, SLOT(actNextPhase()));
|
||||
aNextPhaseAction = new QAction(this);
|
||||
connect(aNextPhaseAction, SIGNAL(triggered()), this, SLOT(actNextPhaseAction()));
|
||||
aNextTurn = new QAction(this);
|
||||
connect(aNextTurn, SIGNAL(triggered()), this, SLOT(actNextTurn()));
|
||||
aRemoveLocalArrows = new QAction(this);
|
||||
|
|
@ -1321,7 +1368,7 @@ void TabGame::createMenuItems()
|
|||
connect(aConcede, SIGNAL(triggered()), this, SLOT(actConcede()));
|
||||
aLeaveGame = new QAction(this);
|
||||
connect(aLeaveGame, SIGNAL(triggered()), this, SLOT(actLeaveGame()));
|
||||
aCloseReplay = 0;
|
||||
aCloseReplay = nullptr;
|
||||
|
||||
phasesMenu = new QMenu(this);
|
||||
for (int i = 0; i < phasesToolbar->phaseCount(); ++i) {
|
||||
|
|
@ -1333,6 +1380,7 @@ void TabGame::createMenuItems()
|
|||
|
||||
phasesMenu->addSeparator();
|
||||
phasesMenu->addAction(aNextPhase);
|
||||
phasesMenu->addAction(aNextPhaseAction);
|
||||
|
||||
gameMenu = new QMenu(this);
|
||||
playersSeparator = gameMenu->addSeparator();
|
||||
|
|
@ -1351,19 +1399,20 @@ void TabGame::createMenuItems()
|
|||
|
||||
void TabGame::createReplayMenuItems()
|
||||
{
|
||||
aNextPhase = 0;
|
||||
aNextTurn = 0;
|
||||
aRemoveLocalArrows = 0;
|
||||
aRotateViewCW = 0;
|
||||
aRotateViewCCW = 0;
|
||||
aResetLayout = 0;
|
||||
aGameInfo = 0;
|
||||
aConcede = 0;
|
||||
aLeaveGame = 0;
|
||||
aNextPhase = nullptr;
|
||||
aNextPhaseAction = nullptr;
|
||||
aNextTurn = nullptr;
|
||||
aRemoveLocalArrows = nullptr;
|
||||
aRotateViewCW = nullptr;
|
||||
aRotateViewCCW = nullptr;
|
||||
aResetLayout = nullptr;
|
||||
aGameInfo = nullptr;
|
||||
aConcede = nullptr;
|
||||
aLeaveGame = nullptr;
|
||||
aCloseReplay = new QAction(this);
|
||||
connect(aCloseReplay, SIGNAL(triggered()), this, SLOT(actLeaveGame()));
|
||||
|
||||
phasesMenu = 0;
|
||||
phasesMenu = nullptr;
|
||||
gameMenu = new QMenu(this);
|
||||
gameMenu->addAction(aCloseReplay);
|
||||
addTabMenu(gameMenu);
|
||||
|
|
@ -1637,7 +1686,7 @@ void TabGame::createCardInfoDock(bool bReplay)
|
|||
void TabGame::createPlayerListDock(bool bReplay)
|
||||
{
|
||||
if (bReplay) {
|
||||
playerListWidget = new PlayerListWidget(0, 0, this);
|
||||
playerListWidget = new PlayerListWidget(nullptr, nullptr, this);
|
||||
} else {
|
||||
playerListWidget = new PlayerListWidget(tabSupervisor, clients.first(), this);
|
||||
connect(playerListWidget, SIGNAL(openMessageDialog(QString, bool)), this,
|
||||
|
|
|
|||
|
|
@ -163,8 +163,8 @@ private:
|
|||
QAction *playersSeparator;
|
||||
QMenu *gameMenu, *phasesMenu, *viewMenu, *cardInfoDockMenu, *messageLayoutDockMenu, *playerListDockMenu,
|
||||
*replayDockMenu;
|
||||
QAction *aGameInfo, *aConcede, *aLeaveGame, *aCloseReplay, *aNextPhase, *aNextTurn, *aRemoveLocalArrows,
|
||||
*aRotateViewCW, *aRotateViewCCW, *aResetLayout, *aResetReplayLayout;
|
||||
QAction *aGameInfo, *aConcede, *aLeaveGame, *aCloseReplay, *aNextPhase, *aNextPhaseAction, *aNextTurn,
|
||||
*aRemoveLocalArrows, *aRotateViewCW, *aRotateViewCCW, *aResetLayout, *aResetReplayLayout;
|
||||
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aMessageLayoutDockVisible, *aMessageLayoutDockFloating,
|
||||
*aPlayerListDockVisible, *aPlayerListDockFloating, *aReplayDockVisible, *aReplayDockFloating;
|
||||
QList<QAction *> phaseActions;
|
||||
|
|
@ -233,6 +233,7 @@ private slots:
|
|||
void actSay();
|
||||
void actPhaseAction();
|
||||
void actNextPhase();
|
||||
void actNextPhaseAction();
|
||||
void actNextTurn();
|
||||
|
||||
void addMentionTag(QString value);
|
||||
|
|
@ -246,7 +247,7 @@ private slots:
|
|||
void actResetLayout();
|
||||
void freeDocksSize();
|
||||
|
||||
bool eventFilter(QObject *o, QEvent *e);
|
||||
bool eventFilter(QObject *o, QEvent *e) override;
|
||||
void dockVisibleTriggered();
|
||||
void dockFloatingTriggered();
|
||||
void dockTopLevelChanged(bool topLevel);
|
||||
|
|
@ -257,10 +258,10 @@ public:
|
|||
const Event_GameJoined &event,
|
||||
const QMap<int, QString> &_roomGameTypes);
|
||||
TabGame(TabSupervisor *_tabSupervisor, GameReplay *replay);
|
||||
~TabGame();
|
||||
void retranslateUi();
|
||||
~TabGame() override;
|
||||
void retranslateUi() override;
|
||||
void updatePlayerListDockTitle();
|
||||
void closeRequest();
|
||||
void closeRequest() override;
|
||||
const QMap<int, Player *> &getPlayers() const
|
||||
{
|
||||
return players;
|
||||
|
|
@ -278,7 +279,7 @@ public:
|
|||
{
|
||||
return gameInfo.game_id();
|
||||
}
|
||||
QString getTabText() const;
|
||||
QString getTabText() const override;
|
||||
bool getSpectator() const
|
||||
{
|
||||
return spectator;
|
||||
|
|
|
|||
|
|
@ -299,16 +299,17 @@ void MainWindow::actAbout()
|
|||
QMessageBox::NoIcon, tr("About Cockatrice"),
|
||||
QString("<font size=\"8\"><b>Cockatrice</b></font> (" + QString::fromStdString(BUILD_ARCHITECTURE) + ")<br>" +
|
||||
tr("Version") + QString(" %1").arg(VERSION_STRING) + "<br><br><b><a href='" + GITHUB_PAGES_URL + "'>" +
|
||||
tr("Cockatrice Webpage") + "</a></b><br>" + "<br><br><b>" + tr("Project Manager:") +
|
||||
"</b><br>Gavin Bisesi<br><br>" + "<b>" + tr("Past Project Managers:") +
|
||||
"</b><br>Max-Wilhelm Bruker<br>Marcus Schütz<br><br>" + "<b>" + tr("Developers:") + "</b><br>" +
|
||||
"<a href='" + GITHUB_CONTRIBUTORS_URL + "'>" + tr("Our Developers") + "</a><br>" + "<a href='" +
|
||||
GITHUB_CONTRIBUTE_URL + "'>" + tr("Help Develop!") + "</a><br><br>" + "<b>" + tr("Translators:") +
|
||||
"</b><br>" + "<a href='" + GITHUB_TRANSIFEX_TRANSLATORS_URL + "'>" + tr("Our Translators") +
|
||||
"</a><br>" + "<a href='" + GITHUB_TRANSLATOR_FAQ_URL + "'>" + tr("Help Translate!") + "</a><br><br>" +
|
||||
"<b>" + tr("Support:") + "</b><br>" + "<a href='" + GITHUB_ISSUES_URL + "'>" + tr("Report an Issue") +
|
||||
"</a><br>" + "<a href='" + GITHUB_TROUBLESHOOTING_URL + "'>" + tr("Troubleshooting") + "</a><br>" +
|
||||
"<a href='" + GITHUB_FAQ_URL + "'>" + tr("F.A.Q.") + "</a><br>"),
|
||||
tr("Cockatrice Webpage") + "</a></b><br>" + "<br><b>" + tr("Project Manager:") +
|
||||
"</b><br>Zach Halpern<br><br>" + "<b>" + tr("Past Project Managers:") +
|
||||
"</b><br>Gavin Bisesi<br>Max-Wilhelm Bruker<br>Marcus Schütz<br><br>" + "<b>" + tr("Developers:") +
|
||||
"</b><br>" + "<a href='" + GITHUB_CONTRIBUTORS_URL + "'>" + tr("Our Developers") + "</a><br>" +
|
||||
"<a href='" + GITHUB_CONTRIBUTE_URL + "'>" + tr("Help Develop!") + "</a><br><br>" + "<b>" +
|
||||
tr("Translators:") + "</b><br>" + "<a href='" + GITHUB_TRANSIFEX_TRANSLATORS_URL + "'>" +
|
||||
tr("Our Translators") + "</a><br>" + "<a href='" + GITHUB_TRANSLATOR_FAQ_URL + "'>" +
|
||||
tr("Help Translate!") + "</a><br><br>" + "<b>" + tr("Support:") + "</b><br>" + "<a href='" +
|
||||
GITHUB_ISSUES_URL + "'>" + tr("Report an Issue") + "</a><br>" + "<a href='" +
|
||||
GITHUB_TROUBLESHOOTING_URL + "'>" + tr("Troubleshooting") + "</a><br>" + "<a href='" + GITHUB_FAQ_URL +
|
||||
"'>" + tr("F.A.Q.") + "</a><br>"),
|
||||
QMessageBox::Ok, this);
|
||||
mb.setIconPixmap(QPixmap("theme:cockatrice").scaled(64, 64));
|
||||
mb.setTextInteractionFlags(Qt::TextBrowserInteraction);
|
||||
|
|
@ -317,9 +318,9 @@ void MainWindow::actAbout()
|
|||
|
||||
void MainWindow::actTips()
|
||||
{
|
||||
if (tip != NULL) {
|
||||
if (tip != nullptr) {
|
||||
delete tip;
|
||||
tip = NULL;
|
||||
tip = nullptr;
|
||||
}
|
||||
tip = new DlgTipOfTheDay();
|
||||
if (tip->successfulInit) {
|
||||
|
|
@ -705,15 +706,33 @@ void MainWindow::createActions()
|
|||
aExit->setMenuRole(QAction::QuitRole);
|
||||
aAbout->setMenuRole(QAction::AboutRole);
|
||||
|
||||
char const *foo; // avoid "warning: expression result unused" under clang
|
||||
foo = QT_TRANSLATE_NOOP("QMenuBar", "Services");
|
||||
foo = QT_TRANSLATE_NOOP("QMenuBar", "Hide %1");
|
||||
foo = QT_TRANSLATE_NOOP("QMenuBar", "Hide Others");
|
||||
foo = QT_TRANSLATE_NOOP("QMenuBar", "Show All");
|
||||
foo = QT_TRANSLATE_NOOP("QMenuBar", "Preferences...");
|
||||
foo = QT_TRANSLATE_NOOP("QMenuBar", "Quit %1");
|
||||
foo = QT_TRANSLATE_NOOP("QMenuBar", "About %1");
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QMenuBar", "Services"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QMenuBar", "Hide %1"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QMenuBar", "Hide Others"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QMenuBar", "Show All"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QMenuBar", "Preferences..."));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QMenuBar", "Quit %1"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QMenuBar", "About %1"));
|
||||
#endif
|
||||
// translate Qt's dialogs "default button text"; list taken from QPlatformTheme::defaultStandardButtonText()
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "OK"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Save"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Save All"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Open"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "&Yes"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Yes to &All"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "&No"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "N&o to All"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Abort"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Retry"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Ignore"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Close"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Cancel"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Discard"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Help"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Apply"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Reset"));
|
||||
Q_UNUSED(QT_TRANSLATE_NOOP("QPlatformTheme", "Restore Defaults"));
|
||||
}
|
||||
|
||||
void MainWindow::createMenus()
|
||||
|
|
@ -811,7 +830,7 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
createTrayIcon();
|
||||
}
|
||||
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutchanged()), this, SLOT(refreshShortcuts()));
|
||||
connect(&settingsCache->shortcuts(), SIGNAL(shortCutChanged()), this, SLOT(refreshShortcuts()));
|
||||
refreshShortcuts();
|
||||
|
||||
connect(db, SIGNAL(cardDatabaseLoadingFailed()), this, SLOT(cardDatabaseLoadingFailed()));
|
||||
|
|
@ -828,13 +847,30 @@ MainWindow::MainWindow(QWidget *parent)
|
|||
if (tip->successfulInit && settingsCache->getShowTipsOnStartup() && tip->newTipsAvailable) {
|
||||
tip->show();
|
||||
}
|
||||
|
||||
// Only run the check updater if the user wants it (defaults to on)
|
||||
if (settingsCache->getNotifyAboutNewVersion()) {
|
||||
auto versionUpdater = new MainUpdateHelper();
|
||||
connect(versionUpdater, SIGNAL(newVersionDetected(QString)), this, SLOT(alertForcedOracleRun(QString)));
|
||||
QtConcurrent::run(versionUpdater, &MainUpdateHelper::testForNewVersion);
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::alertForcedOracleRun(const QString &newVersion)
|
||||
{
|
||||
settingsCache->setClientVersion(newVersion);
|
||||
QMessageBox::information(this, tr("New Version"),
|
||||
tr("Congratulations on updating to Cockatrice %1!\n"
|
||||
"Oracle will now launch to update your card database.")
|
||||
.arg(newVersion));
|
||||
actCheckCardUpdates();
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
if (tip != NULL) {
|
||||
if (tip != nullptr) {
|
||||
delete tip;
|
||||
tip = NULL;
|
||||
tip = nullptr;
|
||||
}
|
||||
if (trayIcon) {
|
||||
trayIcon->hide();
|
||||
|
|
@ -1271,3 +1307,10 @@ void MainWindow::promptForgotPasswordReset()
|
|||
dlg.getPlayerName(), dlg.getToken(), dlg.getPassword());
|
||||
}
|
||||
}
|
||||
|
||||
void MainUpdateHelper::testForNewVersion()
|
||||
{
|
||||
if (settingsCache->getClientVersion() != VERSION_STRING) {
|
||||
emit newVersionDetected(VERSION_STRING);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,6 +101,8 @@ private slots:
|
|||
void actManageSets();
|
||||
void actEditTokens();
|
||||
|
||||
void alertForcedOracleRun(const QString &);
|
||||
|
||||
private:
|
||||
static const QString appName;
|
||||
static const QStringList fileNameFilters;
|
||||
|
|
@ -146,4 +148,17 @@ protected:
|
|||
QString extractInvalidUsernameMessage(QString &in);
|
||||
};
|
||||
|
||||
class MainUpdateHelper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
signals:
|
||||
void newVersionDetected(QString);
|
||||
|
||||
public:
|
||||
explicit MainUpdateHelper() = default;
|
||||
~MainUpdateHelper() override = default;
|
||||
void testForNewVersion();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -127,21 +127,32 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
|||
labNotes->setOpenExternalLinks(true);
|
||||
labNotes->setText(
|
||||
"<b>" + tr("Deck Editor") + ":</b> " +
|
||||
tr("Only cards in enabled sets will appear in the deck editor card list") + "<br><b>" + tr("Card Art") +
|
||||
":</b> " + tr("Image priority is decided in the following order") + "<ol><li>" + tr("The") +
|
||||
"<a "
|
||||
"href='https://github.com/Cockatrice/Cockatrice/wiki/"
|
||||
tr("Only cards in enabled sets will appear in the deck editor card list") + "<br><br>" + "<b>" +
|
||||
tr("Card Art") + ":</b> " + tr("Image priority is decided in the following order") + "<ol><li>" + tr("The") +
|
||||
"<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'> " +
|
||||
tr("CUSTOM Folder") + "</a></li><li>" + tr("Enabled Sets (Top to Bottom)") + "</li><li>" +
|
||||
tr("Disabled Sets (Top to Bottom)") + "</li></ol>");
|
||||
|
||||
sortWarning = new QLabel;
|
||||
sortWarning->setWordWrap(true);
|
||||
sortWarning->setText(
|
||||
"<b>" + tr("Warning: ") + "</b><br>" +
|
||||
tr("While the set list is sorted by any of the columns, custom art priority setting is disabled.") + "<br>" +
|
||||
tr("To disable sorting click on the same column header again until this message disappears."));
|
||||
sortWarning->setStyleSheet("QLabel { background-color:red;}");
|
||||
QGridLayout *hintsGrid = new QGridLayout;
|
||||
hintsGrid->addWidget(labNotes, 0, 0);
|
||||
hintsGroupBox = new QGroupBox(tr("Hints"));
|
||||
hintsGroupBox->setLayout(hintsGrid);
|
||||
|
||||
sortWarning = new QGroupBox(tr("Note"));
|
||||
QGridLayout *sortWarningLayout = new QGridLayout;
|
||||
sortWarningText = new QLabel;
|
||||
sortWarningText->setWordWrap(true);
|
||||
sortWarningText->setText(tr("Sorting by column allows you to find a set while not changing set priority.") + " " +
|
||||
tr("To enable ordering again, click the column header until this message disappears."));
|
||||
sortWarningLayout->addWidget(sortWarningText, 0, 0, 1, 2);
|
||||
sortWarningButton = new QPushButton;
|
||||
sortWarningButton->setText(tr("Use the current sorting as the set priority instead"));
|
||||
sortWarningButton->setToolTip(tr("Sorts the set priority using the same column"));
|
||||
sortWarningButton->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
connect(sortWarningButton, SIGNAL(released()), this, SLOT(actIgnoreWarning()));
|
||||
sortWarningLayout->addWidget(sortWarningButton, 1, 0);
|
||||
sortWarning->setLayout(sortWarningLayout);
|
||||
sortWarning->setVisible(false);
|
||||
|
||||
buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
|
|
@ -157,7 +168,7 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
|
|||
mainLayout->addWidget(enableSomeButton, 2, 1);
|
||||
mainLayout->addWidget(disableSomeButton, 2, 2);
|
||||
mainLayout->addWidget(sortWarning, 3, 1, 1, 2);
|
||||
mainLayout->addWidget(labNotes, 4, 1, 1, 2);
|
||||
mainLayout->addWidget(hintsGroupBox, 4, 1, 1, 2);
|
||||
mainLayout->addWidget(buttonBox, 5, 1, 1, 2);
|
||||
mainLayout->setColumnStretch(1, 1);
|
||||
mainLayout->setColumnStretch(2, 1);
|
||||
|
|
@ -250,6 +261,17 @@ void WndSets::actSort(int index)
|
|||
}
|
||||
}
|
||||
|
||||
void WndSets::actIgnoreWarning()
|
||||
{
|
||||
if (sortIndex < 0) {
|
||||
return;
|
||||
}
|
||||
model->sort(sortIndex, sortOrder);
|
||||
view->header()->setSortIndicator(SORT_RESET, Qt::DescendingOrder);
|
||||
sortIndex = -1;
|
||||
sortWarning->setVisible(false);
|
||||
}
|
||||
|
||||
void WndSets::actDisableSortButtons(int index)
|
||||
{
|
||||
if (index != SORT_RESET) {
|
||||
|
|
|
|||
|
|
@ -8,13 +8,14 @@
|
|||
#include <QMainWindow>
|
||||
#include <QSet>
|
||||
|
||||
class CardDatabase;
|
||||
class QGroupBox;
|
||||
class QItemSelection;
|
||||
class QPushButton;
|
||||
class QTreeView;
|
||||
class SetsDisplayModel;
|
||||
class SetsModel;
|
||||
class SetsProxyModel;
|
||||
class SetsDisplayModel;
|
||||
class QPushButton;
|
||||
class CardDatabase;
|
||||
class QItemSelection;
|
||||
class QTreeView;
|
||||
|
||||
class WndSets : public QMainWindow
|
||||
{
|
||||
|
|
@ -22,6 +23,7 @@ class WndSets : public QMainWindow
|
|||
private:
|
||||
SetsModel *model;
|
||||
SetsDisplayModel *displayModel;
|
||||
QGroupBox *hintsGroupBox;
|
||||
QTreeView *view;
|
||||
QPushButton *toggleAllButton, *toggleSelectedButton;
|
||||
QPushButton *enableAllButton, *disableAllButton, *enableSomeButton, *disableSomeButton;
|
||||
|
|
@ -29,7 +31,10 @@ private:
|
|||
QAction *aUp, *aDown, *aBottom, *aTop;
|
||||
QToolBar *setsEditToolBar;
|
||||
QDialogButtonBox *buttonBox;
|
||||
QLabel *labNotes, *searchLabel, *sortWarning;
|
||||
QLabel *labNotes, *searchLabel;
|
||||
QGroupBox *sortWarning;
|
||||
QLabel *sortWarningText;
|
||||
QPushButton *sortWarningButton;
|
||||
QLineEdit *searchField;
|
||||
QGridLayout *mainLayout;
|
||||
QHBoxLayout *filterBox;
|
||||
|
|
@ -65,6 +70,7 @@ private slots:
|
|||
void actRestoreOriginalOrder();
|
||||
void actDisableResetButton(const QString &filterText);
|
||||
void actSort(int index);
|
||||
void actIgnoreWarning();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -193,22 +193,22 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa
|
|||
<message>
|
||||
<location filename="../src/releasechannel.cpp" line="207"/>
|
||||
<source>Beta Releases</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>version bêta</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/releasechannel.cpp" line="233"/>
|
||||
<source>No reply received from the release update server.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Le serveur de mise à jour ne répond pas.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/releasechannel.cpp" line="242"/>
|
||||
<source>Invalid reply received from the release update server.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Réponse reçue du serveur de mise à jour de version invalide .</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/releasechannel.cpp" line="277"/>
|
||||
<source>No reply received from the file update server.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Le serveur de mise à jour de fichier ne répond pas.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -442,47 +442,47 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa
|
|||
<location filename="../src/dlg_settings.cpp" line="511"/>
|
||||
<location filename="../src/dlg_settings.cpp" line="561"/>
|
||||
<source>Update Spoilers</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>mettre à jour les spoilers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="550"/>
|
||||
<source>Updating...</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Mise à jours</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="580"/>
|
||||
<source>Choose path</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Choisir le chemin</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="606"/>
|
||||
<source>Spoilers</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Spoilers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="607"/>
|
||||
<source>Download Spoilers Automatically</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Télécharger automatiquement les spoilers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="608"/>
|
||||
<source>Spoiler Location:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Emplacement des spoilers:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="609"/>
|
||||
<source>Hey, something's here finally!</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Hey, quelque chose est enfin là!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="610"/>
|
||||
<source>Last Updated</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>dernière mise à jour</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="611"/>
|
||||
<source>Spoilers download automatically on launch</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>spoilers téléchargé automatiquement au lancement</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="612"/>
|
||||
|
|
@ -585,7 +585,7 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa
|
|||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="28"/>
|
||||
<source>Refresh the server list with known public servers</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Actualiser la liste de serveurs avec des serveurs publics connus</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="40"/>
|
||||
|
|
@ -625,33 +625,33 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa
|
|||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="78"/>
|
||||
<source>If you have any trouble connecting or registering then contact the server staff for help!</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Si vous rencontrez des difficultés pour vous connecter ou vous inscrire, contactez le personnel du serveur pour obtenir de l'aide!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="80"/>
|
||||
<location filename="../src/dlg_connect.cpp" line="262"/>
|
||||
<source>Webpage</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>page internet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="90"/>
|
||||
<source>Forgot Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Mot de passe oublié</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="94"/>
|
||||
<source>&Connect</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>&Connexion </translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="136"/>
|
||||
<source>Server Contact</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Contact du serveur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="149"/>
|
||||
<source>Connect to Server</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Connecter au serveur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="117"/>
|
||||
|
|
@ -686,7 +686,7 @@ Cette information sera consultable uniquement par les modérateurs et ne sera pa
|
|||
<message>
|
||||
<location filename="../src/dlg_connect.h" line="76"/>
|
||||
<source>Downloading...</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Téléchargement</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -1041,7 +1041,8 @@ Pour enlever votre avatar actuel, confirmez sans choisir une nouvelle image.</tr
|
|||
<location filename="../src/dlg_edit_tokens.cpp" line="150"/>
|
||||
<source>The chosen name conflicts with an existing card or token.
|
||||
Make sure to enable the 'Token' set in the "Manage sets" dialog to display them correctly.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Le nom choisi est en conflit avec une carte ou un jeton existant.
|
||||
Assurez-vous d'activer les set de 'jeton' dans le menu "gérer les sets" afin de les afficher correctement.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -1536,17 +1537,17 @@ Voulez vous changer les paramètres d'emplacement de base de données ?</tr
|
|||
<message>
|
||||
<location filename="../src/dlg_tip_of_the_day.cpp" line="67"/>
|
||||
<source>Next</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>suivant</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_tip_of_the_day.cpp" line="68"/>
|
||||
<source>Previous</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>précédent</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_tip_of_the_day.cpp" line="90"/>
|
||||
<source>Tip of the Day</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Conseil du jour</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -1637,7 +1638,7 @@ Please visit the download page to update manually.</source>
|
|||
<location filename="../src/dlg_update.cpp" line="147"/>
|
||||
<location filename="../src/dlg_update.cpp" line="158"/>
|
||||
<source>Released</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Sortie</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_update.cpp" line="148"/>
|
||||
|
|
@ -1715,7 +1716,7 @@ Vous devez compiler les sources vous-même.</translation>
|
|||
<message>
|
||||
<location filename="../src/dlg_viewlog.cpp" line="18"/>
|
||||
<source>Clear log when closing</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Effacer le journal lors de la fermeture</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_viewlog.cpp" line="25"/>
|
||||
|
|
@ -1728,7 +1729,7 @@ Vous devez compiler les sources vous-même.</translation>
|
|||
<message>
|
||||
<location filename="../src/filterbuilder.cpp" line="28"/>
|
||||
<source>Type your filter here</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Tapez votre filtre ici</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -2041,7 +2042,7 @@ Vous devez compiler les sources vous-même.</translation>
|
|||
<message>
|
||||
<location filename="../src/dlg_settings.cpp" line="317"/>
|
||||
<source>Show tips on startup</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Afficher les astuces au démarrage</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -2589,7 +2590,7 @@ La version locale est %1, la nouvelle version est %2.</translation>
|
|||
<message>
|
||||
<location filename="../src/window_main.cpp" line="641"/>
|
||||
<source>&Tip of the Day</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>&Conseil du jour</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_main.cpp" line="642"/>
|
||||
|
|
@ -2764,14 +2765,14 @@ Cockatrice va maintenant recharger de nouveau la base de données de cartes.</tr
|
|||
<message>
|
||||
<location filename="../src/window_main.cpp" line="637"/>
|
||||
<source>&Manage sets...</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>&Gérer les sets...</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_main.cpp" line="983"/>
|
||||
<source>Hi! It seems like you're running this version of Cockatrice for the first time.
|
||||
All the sets in the card database have been enabled.
|
||||
Read more about changing the set order or disabling specific sets and consequent effects in the "Manage Sets" dialog.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Salut! On dirait que vous utilisez cette version de Cockatrice pour la première fois. Tous les sets de la base de données de cartes ont été activés. Pour plus d'informations sur la modification de l'ordre des sets ou la désactivation de sets spécifiques et de leurs effets, consultez le menu "Gérer les sets".</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_main.cpp" line="1098"/>
|
||||
|
|
@ -2920,12 +2921,12 @@ Cockactrice va maintenant recharger la base de données de cartes.</translation>
|
|||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="366"/>
|
||||
<source>%1 turns %2 face-down.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 tourner %2 face cachée.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="368"/>
|
||||
<source>%1 turns %2 face-up.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>%1 tourner %2 face visible.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="402"/>
|
||||
|
|
@ -3862,7 +3863,7 @@ Cockactrice va maintenant recharger la base de données de cartes.</translation>
|
|||
<message>
|
||||
<location filename="../src/player.cpp" line="2722"/>
|
||||
<source>View related cards</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Voir les cartes associées</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/player.cpp" line="2750"/>
|
||||
|
|
@ -3890,7 +3891,7 @@ Cockactrice va maintenant recharger la base de données de cartes.</translation>
|
|||
<location filename="../src/player.cpp" line="690"/>
|
||||
<source>T&urn Over</source>
|
||||
<extracomment>Turn face up/face down</extracomment>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Retourner</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/player.cpp" line="713"/>
|
||||
|
|
@ -4148,7 +4149,7 @@ Cockactrice va maintenant recharger la base de données de cartes.</translation>
|
|||
<message>
|
||||
<location filename="../src/sequenceEdit/sequenceedit.cpp" line="158"/>
|
||||
<source>Invalid key</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Clé invalide</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -4185,13 +4186,14 @@ Cockactrice va maintenant recharger la base de données de cartes.</translation>
|
|||
<location filename="../src/shortcutssettings.cpp" line="40"/>
|
||||
<source>Your configuration file contained invalid shortcuts.
|
||||
Please check your shortcut settings!</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Votre fichier de configuration contenait des raccourcis invalides. Merci de vérifier vos paramètres de raccourci !</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/shortcutssettings.cpp" line="42"/>
|
||||
<source>The following shortcuts have been set to default:
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Les raccourcis suivants ont été définis par défaut:
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -4268,48 +4270,48 @@ Please check your shortcut settings!</source>
|
|||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="99"/>
|
||||
<source>Spoilers season has ended</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>La saison des spoilers est terminée</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="99"/>
|
||||
<source>Deleting spoiler.xml. Please run Oracle</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Suppression de spoiler.xml. S'il vous plaît exécuter Oracle</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="109"/>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="116"/>
|
||||
<source>Spoilers download failed</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Échec du téléchargement des spoilers</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="109"/>
|
||||
<source>No internet connection</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Pas de connexion Internet</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="116"/>
|
||||
<source>Error</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Erreur</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="137"/>
|
||||
<source>Spoilers already up to date</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Spoilers déjà à jour</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="137"/>
|
||||
<source>No new spoilers added</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Aucun nouveau spoilers ajouté</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="178"/>
|
||||
<source>Spoilers have been updated!</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Les spoilers ont été mis à jour!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="178"/>
|
||||
<source>Last change:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Dernier changement:</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -4317,7 +4319,7 @@ Please check your shortcut settings!</source>
|
|||
<message>
|
||||
<location filename="../src/releasechannel.cpp" line="90"/>
|
||||
<source>Stable Releases</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Version stable</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/releasechannel.cpp" line="108"/>
|
||||
|
|
@ -4438,57 +4440,57 @@ Please check your shortcut settings!</source>
|
|||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="347"/>
|
||||
<source>Search by card name</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Rechercher par nom de carte</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="453"/>
|
||||
<source>Add to Deck</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ajouter au Deck</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="454"/>
|
||||
<source>Add to Sideboard</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ajouter à la réserve</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="459"/>
|
||||
<source>Show Related cards</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Afficher les cartes associées</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="623"/>
|
||||
<source>Save deck to clipboard</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Enregistrer le deck dans le presse-papier</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="624"/>
|
||||
<source>Annotated</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Annoté</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="625"/>
|
||||
<source>Not Annotated</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>sans annotation</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="629"/>
|
||||
<source>&Send deck to online service</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>& Envoyer le Deck au service en ligne</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="630"/>
|
||||
<source>Create decklist (decklist.org)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Créer une liste de deck (decklist.org)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="631"/>
|
||||
<source>Analyze deck (deckstats.net)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Analyser le Deck (deckstats.net)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="632"/>
|
||||
<source>Analyze deck (tappedout.net)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Analyser le deck (tappedout.net)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="634"/>
|
||||
|
|
@ -4619,12 +4621,12 @@ Vérifiez que le répertoire ne soit pas en lecture seule et réessayez.</transl
|
|||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="877"/>
|
||||
<source>There are no cards in your deck to be exported</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Il n'y a pas de cartes dans le deck à exporter</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_deck_editor.cpp" line="889"/>
|
||||
<source>No deck was selected to be saved.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Aucun deck n'a été sélectionné pour être sauvegardé.</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -5077,7 +5079,7 @@ Plus vous entrez d'informations, meilleurs seront les résultats.</translat
|
|||
<message>
|
||||
<location filename="../src/tab_message.cpp" line="148"/>
|
||||
<source>Private message from</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Message privé de</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_message.cpp" line="165"/>
|
||||
|
|
@ -5350,13 +5352,15 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre
|
|||
<location filename="../src/tip_of_the_day.cpp" line="25"/>
|
||||
<source>File does not exist.
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Le fichier n'existe pas.
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tip_of_the_day.cpp" line="28"/>
|
||||
<source>Failed to open file.
|
||||
</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Échec de l'ouverture du fichier.
|
||||
</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -5810,17 +5814,17 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre
|
|||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="61"/>
|
||||
<source>Search by set name, code, or type</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Rechercher par ensemble de nom, code ou type</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="66"/>
|
||||
<source>Default order</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Ordre par défaut</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="67"/>
|
||||
<source>Restore original art priority order</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Restaurer l'ordre originale de priorité artistique</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="107"/>
|
||||
|
|
@ -5885,22 +5889,22 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre
|
|||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="139"/>
|
||||
<source>Warning: </source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Attention:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="140"/>
|
||||
<source>While the set list is sorted by any of the columns, custom art priority setting is disabled.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>lorsque la liste est triée dans une des colonnes, la priorité personnalisée est désactivée.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="141"/>
|
||||
<source>To disable sorting click on the same column header again until this message disappears.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Pour désactiver le tri, cliquez à nouveau sur la même en-tête de colonne jusqu'à ce que ce message disparaisse.</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="170"/>
|
||||
<source>Manage sets</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Gérer les sets</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="204"/>
|
||||
|
|
@ -6330,22 +6334,22 @@ Merci de ne pas recommencer ou d'autres mesures peuvent être prises contre
|
|||
<message>
|
||||
<location filename="../src/sequenceEdit/ui_shortcutstab.h" line="1764"/>
|
||||
<source>Manage sets</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Gérer les sets</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/sequenceEdit/ui_shortcutstab.h" line="1770"/>
|
||||
<source>Export deck</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Exporter le Deck</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/sequenceEdit/ui_shortcutstab.h" line="1774"/>
|
||||
<source>Save deck (clip)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Sauvegarder le Deck (du presse-papier)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/sequenceEdit/ui_shortcutstab.h" line="1776"/>
|
||||
<source>Save deck (clip; no annotations)</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>Enregistrer le Deck (du presse papier; sans annotations)</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/sequenceEdit/ui_shortcutstab.h" line="1855"/>
|
||||
|
|
|
|||
|
|
@ -267,7 +267,7 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
|
|||
<message>
|
||||
<location filename="../src/cardinfotext.cpp" line="123"/>
|
||||
<source>Unknown card:</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>謎のカード:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/cardinfotext.cpp" line="131"/>
|
||||
|
|
@ -585,7 +585,7 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
|
|||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="28"/>
|
||||
<source>Refresh the server list with known public servers</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>デフォルトの公開サーバーリストに更新します</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="40"/>
|
||||
|
|
@ -625,33 +625,33 @@ This is only saved for moderators and cannot be seen by the banned person.</sour
|
|||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="78"/>
|
||||
<source>If you have any trouble connecting or registering then contact the server staff for help!</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>接続や登録に問題がある場合は、サーバー管理者にお問い合わせください。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="80"/>
|
||||
<location filename="../src/dlg_connect.cpp" line="262"/>
|
||||
<source>Webpage</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>ウェブページ</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="90"/>
|
||||
<source>Forgot Password</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>パスワード忘れちゃった</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="94"/>
|
||||
<source>&Connect</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>接続</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="136"/>
|
||||
<source>Server Contact</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>サーバーの連絡先</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="149"/>
|
||||
<source>Connect to Server</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>サーバーに接続</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_connect.cpp" line="117"/>
|
||||
|
|
@ -1030,7 +1030,7 @@ To remove your current avatar, confirm without choosing a new image.</source>
|
|||
<message>
|
||||
<location filename="../src/dlg_edit_tokens.cpp" line="145"/>
|
||||
<source>Please enter the name of the token:</source>
|
||||
<translation>トークン名を入力してください:</translation>
|
||||
<translation>トークン名を入力:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/dlg_edit_tokens.cpp" line="149"/>
|
||||
|
|
@ -1771,7 +1771,7 @@ You may have to build from source yourself.</source>
|
|||
<message>
|
||||
<location filename="../src/gameselector.cpp" line="169"/>
|
||||
<source>The game does not exist any more.</source>
|
||||
<translation>このゲームは既に存在しません。</translation>
|
||||
<translation>このゲームはすでに存在しません。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/gameselector.cpp" line="172"/>
|
||||
|
|
@ -2818,12 +2818,12 @@ Cockatrice will now reload the card database.</source>
|
|||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="391"/>
|
||||
<source>%1 is now watching the game.</source>
|
||||
<translation>%1が観戦に参加した。</translation>
|
||||
<translation>%1 が観戦に参加した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="251"/>
|
||||
<source>%1 has loaded a deck (%2).</source>
|
||||
<translation>%1はデッキをロードした。ハッシュ:%2</translation>
|
||||
<translation>%1 はデッキをロードした。ハッシュ:%2</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="253"/>
|
||||
|
|
@ -2889,57 +2889,57 @@ Cockatrice will now reload the card database.</source>
|
|||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="290"/>
|
||||
<source>%1 gives %2 control over %3.</source>
|
||||
<translation>%1は、%2に《%3》のコントロールを渡した。</translation>
|
||||
<translation>%1 は %2 に %3 のコントロールを渡した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="302"/>
|
||||
<source>%1 puts %2 into play tapped%3.</source>
|
||||
<translation>%1は《%2》を%3タップ状態でプレイした。</translation>
|
||||
<translation>%1 は %2 を%3タップ状態でプレイした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="304"/>
|
||||
<source>%1 puts %2 into play%3.</source>
|
||||
<translation>%1は《%2》を%3プレイした。</translation>
|
||||
<translation>%1 は %2 を%3プレイした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="308"/>
|
||||
<source>%1 exiles %2%3.</source>
|
||||
<translation>%1は《%2》を%3追放した。</translation>
|
||||
<translation>%1 は %2 を%3追放した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="321"/>
|
||||
<source>%1 puts %2%3 into their library %4 cards from the top.</source>
|
||||
<translation>%1は《%2》を%3ライブラリーの一番上から%4枚目に置いた。</translation>
|
||||
<translation>%1 は %2 を%3ライブラリーの一番上から%4枚目に置いた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="324"/>
|
||||
<source>%1 moves %2%3 to sideboard.</source>
|
||||
<translation>%1は《%2》を%3サイドボードに置いた。</translation>
|
||||
<translation>%1 は %2 を%3サイドボードに置いた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="327"/>
|
||||
<source>%1 plays %2%3.</source>
|
||||
<translation>%1は《%2》を%3プレイした。</translation>
|
||||
<translation>%1 は %2 を%3プレイした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="366"/>
|
||||
<source>%1 turns %2 face-down.</source>
|
||||
<translation>%1は《%2》を裏向きにした。</translation>
|
||||
<translation>%1 は %2 を裏向きにした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="368"/>
|
||||
<source>%1 turns %2 face-up.</source>
|
||||
<translation>%1は《%2》を表向きにした。</translation>
|
||||
<translation>%1 は %2 を表向きにした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="402"/>
|
||||
<source>%1 has left the game (%2).</source>
|
||||
<translation>%1はゲームから離脱した(%2)。</translation>
|
||||
<translation>%1 はゲームから離脱した(%2)。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="410"/>
|
||||
<source>%1 is not watching the game any more (%2).</source>
|
||||
<translation>%1が観戦から離脱した(%2)。</translation>
|
||||
<translation>%1 が観戦から離脱した(%2)。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="546"/>
|
||||
|
|
@ -3004,7 +3004,7 @@ Cockatrice will now reload the card database.</source>
|
|||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="612"/>
|
||||
<source>%1's turn.</source>
|
||||
<translation>■%1のターン■</translation>
|
||||
<translation>■ %1 のターン■</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="../src/messagelogwidget.cpp" line="636"/>
|
||||
|
|
@ -3024,12 +3024,12 @@ Cockatrice will now reload the card database.</source>
|
|||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="151"/>
|
||||
<source>%1 is now keeping the top card %2 revealed.</source>
|
||||
<translation>%1は、%2一番上のカードを公開した状態でゲームをプレイしている。</translation>
|
||||
<translation>%1 は%2一番上のカードを公開した状態でゲームをプレイしている。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="152"/>
|
||||
<source>%1 is not revealing the top card %2 any longer.</source>
|
||||
<translation>%1は、%2一番上のカードの公開を終えた。</translation>
|
||||
<translation>%1 は%2一番上のカードの公開を終えた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="446"/>
|
||||
|
|
@ -3039,47 +3039,47 @@ Cockatrice will now reload the card database.</source>
|
|||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="385"/>
|
||||
<source>%1 has joined the game.</source>
|
||||
<translation>%1がゲームに参加した。</translation>
|
||||
<translation>%1 がゲームに参加した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="451"/>
|
||||
<source>%1 is ready to start the game.</source>
|
||||
<translation>%1はゲーム開始の準備が完了した!!</translation>
|
||||
<translation>%1 はゲーム開始の準備が完了した!!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="415"/>
|
||||
<source>%1 is not ready to start the game any more.</source>
|
||||
<translation>%1は準備完了を解除した。</translation>
|
||||
<translation>%1 は準備完了を解除した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="691"/>
|
||||
<source>%1 has locked their sideboard.</source>
|
||||
<translation>%1はサイドボードをロックした。</translation>
|
||||
<translation>%1 はサイドボードをロックした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="693"/>
|
||||
<source>%1 has unlocked their sideboard.</source>
|
||||
<translation>%1はサイドボードを解禁した。</translation>
|
||||
<translation>%1 はサイドボードを解禁した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="169"/>
|
||||
<source>%1 has conceded the game.</source>
|
||||
<translation>%1が投了した!!!</translation>
|
||||
<translation>%1 が投了した!!!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="176"/>
|
||||
<source>%1 has restored connection to the game.</source>
|
||||
<translation>%1がゲームに再接続した。</translation>
|
||||
<translation>%1 がゲームに再接続した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="180"/>
|
||||
<source>%1 has lost connection to the game.</source>
|
||||
<translation>%1はゲームから切断された。</translation>
|
||||
<translation>%1 はゲームから切断された。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="721"/>
|
||||
<source>%1 shuffles %2.</source>
|
||||
<translation>%1は%2を切り直した。</translation>
|
||||
<translation>%1 は%2を切り直した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="522"/>
|
||||
|
|
@ -3094,27 +3094,27 @@ Cockatrice will now reload the card database.</source>
|
|||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="523"/>
|
||||
<source>%1 flipped a coin. It landed as %2.</source>
|
||||
<translation>%1はコインを投げた。結果は……【%2】だ!</translation>
|
||||
<translation>%1 はコインを投げた。結果は……【%2】だ!</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="527"/>
|
||||
<source>%1 rolls a %2 with a %3-sided die.</source>
|
||||
<translation>%1は%3面ダイスをふり、【%2】を出した。</translation>
|
||||
<translation>%1 は%3面ダイスをふり、【%2】を出した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="344"/>
|
||||
<source>%1 draws %2 card(s).</source>
|
||||
<translation>%1は%2枚カードを引いた。</translation>
|
||||
<translation>%1 は%2枚カードを引いた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="749"/>
|
||||
<source>%1 undoes their last draw.</source>
|
||||
<translation>%1は最後に引いたカードを戻した。</translation>
|
||||
<translation>%1 は最後に引いたカードを戻した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="752"/>
|
||||
<source>%1 undoes their last draw (%2).</source>
|
||||
<translation>%1は最後に引いたカード (《%2》) を戻した 。</translation>
|
||||
<translation>%1 は最後に引いたカード ( %2 ) を戻した 。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="72"/>
|
||||
|
|
@ -3154,202 +3154,202 @@ Cockatrice will now reload the card database.</source>
|
|||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="306"/>
|
||||
<source>%1 puts %2%3 into their graveyard.</source>
|
||||
<translation>%1は《%2》を%3墓地に置いた。</translation>
|
||||
<translation>%1 は %2 を%3墓地に置いた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="310"/>
|
||||
<source>%1 moves %2%3 to their hand.</source>
|
||||
<translation>%1は《%2》を%3手札に加えた。</translation>
|
||||
<translation>% 1は %2 を%3手札に加えた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="313"/>
|
||||
<source>%1 puts %2%3 into their library.</source>
|
||||
<translation>%1は《%2》を%3ライブラリーに加えた。</translation>
|
||||
<translation>%1 は %2 を%3ライブラリーに加えた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="315"/>
|
||||
<source>%1 puts %2%3 on bottom of their library.</source>
|
||||
<translation>%1は《%2》を%3ライブラリーの一番下に置いた。</translation>
|
||||
<translation>%1 は %2 を%3ライブラリーの一番下に置いた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="317"/>
|
||||
<source>%1 puts %2%3 on top of their library.</source>
|
||||
<translation>%1は《%2》を%3ライブラリーの一番上に置いた。</translation>
|
||||
<translation>%1 は %2 を%3ライブラリーの一番上に置いた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="439"/>
|
||||
<source>%1 takes a mulligan to %2.</source>
|
||||
<translation>%1は%2枚にマリガンした。</translation>
|
||||
<translation>%1 は%2枚にマリガンした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="441"/>
|
||||
<source>%1 draws their initial hand.</source>
|
||||
<translation>%1は初期手札を引いた。</translation>
|
||||
<translation>%1 は初期手札を引いた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="261"/>
|
||||
<source>%1 destroys %2.</source>
|
||||
<translation>%1は《%2》を取り除いた。</translation>
|
||||
<translation>%1 は %2 を取り除いた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="743"/>
|
||||
<source>%1 unattaches %2.</source>
|
||||
<translation>%1は《%2》をはずした。</translation>
|
||||
<translation>%1 は %2 をはずした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="242"/>
|
||||
<source>%1 creates token: %2%3.</source>
|
||||
<translation>%1はトークン:《%2》を%3作成した。</translation>
|
||||
<translation>%1 はトークン: %2 を%3作成した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="196"/>
|
||||
<source>%1 points from their %2 to themselves.</source>
|
||||
<translation>%1は《%2》から自分自身へ対象を指定した。</translation>
|
||||
<translation>%1 は %2 から自分自身へ対象を指定した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="199"/>
|
||||
<source>%1 points from their %2 to %3.</source>
|
||||
<translation>%1は、《%2》から%3へ対象を指定した。</translation>
|
||||
<translation>%1 は %2 から %3 へ対象を指定した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="203"/>
|
||||
<source>%1 points from %2's %3 to themselves.</source>
|
||||
<translation>%1は、%2の《%3》から自分自身へ対象を指定した。</translation>
|
||||
<translation>%1 は %2 の %3 から自分自身へ対象を指定した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="207"/>
|
||||
<source>%1 points from %2's %3 to %4.</source>
|
||||
<translation>%1は、%2の《%3》から%4へ対象を指定した。</translation>
|
||||
<translation>%1 は %2 の %3 から %4 へ対象を指定した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="215"/>
|
||||
<source>%1 points from their %2 to their %3.</source>
|
||||
<translation>%1は、《%2》から%3へ対象を指定した。</translation>
|
||||
<translation>%1 は %2 から %3 へ対象を指定した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="218"/>
|
||||
<source>%1 points from their %2 to %3's %4.</source>
|
||||
<translation>%1は、《%2》から%3の《%4》へ対象を指定した。</translation>
|
||||
<translation>%1 は %2 から %3 の %4 へ対象を指定した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="224"/>
|
||||
<source>%1 points from %2's %3 to their own %4.</source>
|
||||
<translation>%1は、%2の《%3》から《%4》へ対象を指定した。</translation>
|
||||
<translation>%1 は %2 の %3 から %4 へ対象を指定した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="230"/>
|
||||
<source>%1 points from %2's %3 to %4's %5.</source>
|
||||
<translation>%1は、%2の《%3》から%4の《%5》へ対象を指定した。</translation>
|
||||
<translation>%1 は %2 の %3 から %4 の %5 へ対象を指定した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="629"/>
|
||||
<source>%1 places %2 %3 counter(s) on %4 (now %5).</source>
|
||||
<translation>%1は《%4》の上に%3カウンターを%2個置いた (計%5個) 。</translation>
|
||||
<translation>%1 は %4 の上に%3カウンターを%2個置いた (計%5個) 。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="631"/>
|
||||
<source>%1 removes %2 %3 counter(s) from %4 (now %5).</source>
|
||||
<translation>%1は《%4》の上から%3カウンターを%2個取り除いた (計%5個) 。</translation>
|
||||
<translation>%1 は %4 の上から%3カウンターを%2個取り除いた (計%5個) 。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="708"/>
|
||||
<source>%1 taps their permanents.</source>
|
||||
<translation>%1は自分のコントロールするパーマネントをタップした。</translation>
|
||||
<translation>%1 は自分のコントロールするパーマネントをタップした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="708"/>
|
||||
<source>%1 untaps their permanents.</source>
|
||||
<translation>%1は自分のコントロールするパーマネントをアンタップした。</translation>
|
||||
<translation>%1 は自分のコントロールするパーマネントをアンタップした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="711"/>
|
||||
<source>%1 taps %2.</source>
|
||||
<translation>%1は《%2》をタップした。</translation>
|
||||
<translation>%1 は %2 をタップした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="711"/>
|
||||
<source>%1 untaps %2.</source>
|
||||
<translation>%1は《%2》をアンタップした。</translation>
|
||||
<translation>%1 は %2 をアンタップした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="659"/>
|
||||
<source>%1 sets counter %2 to %3 (%4%5).</source>
|
||||
<translation>%1は%2カウンターを%3に設定した (%4%5)。</translation>
|
||||
<translation>%1 は%2カウンターを%3に設定した (%4%5)。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="671"/>
|
||||
<source>%1 sets %2 to not untap normally.</source>
|
||||
<translation>%1は《%2》をアンタップ・ステップの間にアンタップしないようにした。</translation>
|
||||
<translation>%1 は %2 をアンタップ・ステップの間にアンタップしないようにした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="673"/>
|
||||
<source>%1 sets %2 to untap normally.</source>
|
||||
<translation>%1は《%2》を通常どおりアンタップするように設定した。</translation>
|
||||
<translation>%1 は %2 を通常どおりアンタップするように設定した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="682"/>
|
||||
<source>%1 sets PT of %2 to %3.</source>
|
||||
<translation>%1は《%2》のP/Tを%3にした。</translation>
|
||||
<translation>%1 は %2 のP/Tを%3にした。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="618"/>
|
||||
<source>%1 sets annotation of %2 to %3.</source>
|
||||
<translation>%1は《%2》に注釈をつけた (%3)。</translation>
|
||||
<translation>%1 は %2 に注釈をつけた (%3)。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="353"/>
|
||||
<source>%1 is looking at %2.</source>
|
||||
<translation>%1は%2を見ている。</translation>
|
||||
<translation>%1 は%2を見ている。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="357"/>
|
||||
<source>%1 is looking at the top %2 card(s) %3.</source>
|
||||
<translation>%1は%3上から%2枚のカードを見ている。</translation>
|
||||
<translation>%1 は%3上から%2枚のカードを見ている。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="736"/>
|
||||
<source>%1 stops looking at %2.</source>
|
||||
<translation>%1は%2を見るのをやめた。</translation>
|
||||
<translation>%1 は%2を見るのをやめた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="479"/>
|
||||
<source>%1 reveals %2 to %3.</source>
|
||||
<translation>%1は、%3に%2を見せた。</translation>
|
||||
<translation>%1 は %3 に%2を見せた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="484"/>
|
||||
<source>%1 reveals %2.</source>
|
||||
<translation>%1は%2を公開した。</translation>
|
||||
<translation>%1 は%2を公開した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="489"/>
|
||||
<source>%1 randomly reveals %2%3 to %4.</source>
|
||||
<translation>%1は%3無作為に《%2》を選び、%4に見せた。</translation>
|
||||
<translation>%1 は%3無作為に %2 を選び、%4に見せた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="496"/>
|
||||
<source>%1 randomly reveals %2%3.</source>
|
||||
<translation>%1は%3無作為に《%2》を選び、公開した。</translation>
|
||||
<translation>%1 は%3無作為に %2 を選び、公開した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="501"/>
|
||||
<source>%1 peeks at face down card #%2.</source>
|
||||
<translation>%1は裏向きのカード#%2の表面を確認した。</translation>
|
||||
<translation>%1 は裏向きのカード#%2の表面を確認した。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="503"/>
|
||||
<source>%1 peeks at face down card #%2: %3.</source>
|
||||
<translation>%1は裏向きのカード#%2の表面を確認した (《%3》) 。</translation>
|
||||
<translation>%1 は裏向きのカード#%2の表面を確認した ( %3 ) 。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="508"/>
|
||||
<source>%1 reveals %2%3 to %4.</source>
|
||||
<translation>%1は%3《%2》を%4に見せた。</translation>
|
||||
<translation>%1 は%3 %2 を %4 に見せた。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/messagelogwidget.cpp" line="515"/>
|
||||
<source>%1 reveals %2%3.</source>
|
||||
<translation>%1は%3《%2》を公開した</translation>
|
||||
<translation>%1 は%3 %2 を公開した。</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
|
@ -3515,7 +3515,7 @@ Cockatrice will now reload the card database.</source>
|
|||
<message>
|
||||
<location filename="../src/player.cpp" line="617"/>
|
||||
<source>Player "%1"</source>
|
||||
<translation>プレイヤー "%1"</translation>
|
||||
<translation>プレイヤー: %1</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/player.cpp" line="618"/>
|
||||
|
|
@ -3836,7 +3836,7 @@ Cockatrice will now reload the card database.</source>
|
|||
<location filename="../src/player.cpp" line="1085"/>
|
||||
<location filename="../src/player.cpp" line="2877"/>
|
||||
<source>C&reate another %1 token</source>
|
||||
<translation>別の%1トークンを出す</translation>
|
||||
<translation>別の %1 トークンを出す</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/player.cpp" line="1228"/>
|
||||
|
|
@ -4274,7 +4274,7 @@ Please check your shortcut settings!</source>
|
|||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="99"/>
|
||||
<source>Spoilers season has ended</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>スポイラーシーズンが終了しました</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/spoilerbackgroundupdater.cpp" line="99"/>
|
||||
|
|
@ -5063,7 +5063,7 @@ The more information you put in, the more specific your results will be.</source
|
|||
<message>
|
||||
<location filename="../src/tab_message.cpp" line="66"/>
|
||||
<source>Private &chat</source>
|
||||
<translation>プライベートチャット</translation>
|
||||
<translation>個人チャット</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_message.cpp" line="67"/>
|
||||
|
|
@ -5073,7 +5073,7 @@ The more information you put in, the more specific your results will be.</source
|
|||
<message>
|
||||
<location filename="../src/tab_message.cpp" line="83"/>
|
||||
<source>%1 - Private chat</source>
|
||||
<translation>%1 - プライベートチャット</translation>
|
||||
<translation>%1 - 個人チャット</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/tab_message.cpp" line="110"/>
|
||||
|
|
@ -5893,17 +5893,17 @@ Please refrain from engaging in this activity or further actions may be taken ag
|
|||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="139"/>
|
||||
<source>Warning: </source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>警告:</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="140"/>
|
||||
<source>While the set list is sorted by any of the columns, custom art priority setting is disabled.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>セットリストがいずれかの列でソートされている間、セット読み込み順の優先度設定は無効です。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="141"/>
|
||||
<source>To disable sorting click on the same column header again until this message disappears.</source>
|
||||
<translation type="unfinished"/>
|
||||
<translation>このメッセージが消えるまで同じ列見出しをクリックし続けると、ソートを無効にすることができます。</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../src/window_sets.cpp" line="170"/>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -26,6 +26,7 @@ SET(common_SOURCES
|
|||
server_room.cpp
|
||||
serverinfo_user_container.cpp
|
||||
sfmt/SFMT.c
|
||||
expression.cpp
|
||||
)
|
||||
|
||||
set(ORACLE_LIBS)
|
||||
|
|
|
|||
|
|
@ -2,8 +2,17 @@
|
|||
#include <QCryptographicHash>
|
||||
#include <QDebug>
|
||||
#include <QFile>
|
||||
#include <QRegularExpression>
|
||||
#include <QTextStream>
|
||||
|
||||
#if QT_VERSION < 0x050600
|
||||
// qHash on QRegularExpression was added in 5.6, FIX IT
|
||||
uint qHash(const QRegularExpression &key, uint seed) noexcept
|
||||
{
|
||||
return qHash(key.pattern(), seed); // call qHash on pattern QString instead
|
||||
}
|
||||
#endif
|
||||
|
||||
SideboardPlan::SideboardPlan(const QString &_name, const QList<MoveCard_ToZone> &_moveList)
|
||||
: name(_name), moveList(_moveList)
|
||||
{
|
||||
|
|
@ -477,161 +486,131 @@ bool DeckList::saveToFile_Native(QIODevice *device)
|
|||
|
||||
bool DeckList::loadFromStream_Plain(QTextStream &in)
|
||||
{
|
||||
const QRegularExpression reCardLine("^\\s*[\\w\\[\\(\\{].*$", QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression reEmpty("^\\s*$");
|
||||
const QRegularExpression reComment("[\\w\\[\\(\\{].*$", QRegularExpression::UseUnicodePropertiesOption);
|
||||
const QRegularExpression reSBMark("^\\s*sb:\\s*(.+)", QRegularExpression::CaseInsensitiveOption);
|
||||
const QRegularExpression reSBComment("sideboard", QRegularExpression::CaseInsensitiveOption);
|
||||
|
||||
// simplified matches
|
||||
const QRegularExpression reMultiplier("^[xX\\(\\[]*(\\d+)[xX\\*\\)\\]]* ?(.+)");
|
||||
const QRegularExpression reBrace(" ?[\\[\\{][^\\]\\}]*[\\]\\}] ?"); // not nested
|
||||
const QRegularExpression reRoundBrace("^\\([^\\)]*\\) ?"); // () are only matched at start of string
|
||||
const QRegularExpression reDigitBrace(" ?\\(\\d*\\) ?"); // () are matched if containing digits
|
||||
const QHash<QRegularExpression, QString> differences{{QRegularExpression("’"), QString("'")},
|
||||
{QRegularExpression("Æ"), QString("Ae")},
|
||||
{QRegularExpression("æ"), QString("ae")},
|
||||
{QRegularExpression(" ?[|/]+ ?"), QString(" // ")},
|
||||
{QRegularExpression("(?<![A-Z]) ?& ?"), QString(" // ")}};
|
||||
|
||||
cleanList();
|
||||
QVector<QString> inputs; // QTextStream -> QVector
|
||||
|
||||
bool priorEntryIsBlank = true, isAtBeginning = true;
|
||||
int blankLines = 0;
|
||||
while (!in.atEnd()) {
|
||||
QString line = in.readLine().simplified().toLower();
|
||||
QStringList inputs = in.readAll().trimmed().split('\n');
|
||||
int max_line = inputs.size();
|
||||
|
||||
/*
|
||||
* Removes all blank lines at start of inputs
|
||||
* Ex: ("", "", "", "Card1", "Card2") => ("Card1", "Card2")
|
||||
*
|
||||
* This will also concise multiple blank lines in a row to just one blank
|
||||
* Ex: ("Card1", "Card2", "", "", "", "Card3") => ("Card1", "Card2", "", "Card3")
|
||||
*/
|
||||
if (line.isEmpty()) {
|
||||
if (priorEntryIsBlank || isAtBeginning) {
|
||||
continue;
|
||||
}
|
||||
|
||||
priorEntryIsBlank = true;
|
||||
blankLines++;
|
||||
} else {
|
||||
isAtBeginning = false;
|
||||
priorEntryIsBlank = false;
|
||||
// start at the first empty line before the first cardline
|
||||
int deckStart = inputs.indexOf(reCardLine);
|
||||
if (deckStart == -1) { // there are no cards?
|
||||
if (inputs.indexOf(reComment) == -1)
|
||||
return false; // input is empty
|
||||
deckStart = max_line;
|
||||
} else {
|
||||
deckStart = inputs.lastIndexOf(reEmpty, deckStart);
|
||||
if (deckStart == -1) {
|
||||
deckStart = 0;
|
||||
}
|
||||
|
||||
inputs.push_back(line);
|
||||
}
|
||||
|
||||
/*
|
||||
* Removes blank line at end of inputs (if applicable)
|
||||
* Ex: ("Card1", "Card2", "") => ("Card1", "Card2")
|
||||
* NOTE: Any duplicates were taken care of above, so there can be
|
||||
* at most one blank line at the very end
|
||||
*/
|
||||
if (!inputs.empty() && inputs.last().isEmpty()) {
|
||||
blankLines--;
|
||||
inputs.erase(inputs.end() - 1);
|
||||
}
|
||||
|
||||
// If "Sideboard" line appears in inputs, then blank lines mean nothing
|
||||
if (inputs.contains("sideboard")) {
|
||||
blankLines = 2;
|
||||
}
|
||||
|
||||
bool inSideboard = false, titleFound = false, isSideboard;
|
||||
int okRows = 0;
|
||||
|
||||
foreach (QString line, inputs) {
|
||||
// This is a comment line, ignore it
|
||||
if (line.startsWith("//")) {
|
||||
if (!titleFound) // Set the title to the first comment
|
||||
{
|
||||
name = line.mid(2).trimmed();
|
||||
titleFound = true;
|
||||
} else if (okRows == 0) // We haven't processed any cards yet
|
||||
{
|
||||
comments += line.mid(2).trimmed() + "\n";
|
||||
// find sideboard position, if marks are used this won't be needed
|
||||
int sBStart = -1;
|
||||
if (inputs.indexOf(reSBMark, deckStart) == -1) {
|
||||
sBStart = inputs.indexOf(reSBComment, deckStart);
|
||||
if (sBStart == -1) {
|
||||
sBStart = inputs.indexOf(reEmpty, deckStart + 1);
|
||||
if (sBStart == -1) {
|
||||
sBStart = max_line;
|
||||
}
|
||||
int nextCard = inputs.indexOf(reCardLine, sBStart + 1);
|
||||
if (inputs.indexOf(reEmpty, nextCard + 1) != -1) {
|
||||
sBStart = max_line; // if there is another empty line all cards are mainboard
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int index = 0;
|
||||
QRegularExpressionMatch match;
|
||||
|
||||
// parse name and comments
|
||||
while (index < deckStart) {
|
||||
const QString current = inputs.at(index++);
|
||||
if (!current.contains(reEmpty)) {
|
||||
match = reComment.match(current);
|
||||
name = match.captured();
|
||||
break;
|
||||
}
|
||||
}
|
||||
while (index < deckStart) {
|
||||
const QString current = inputs.at(index++);
|
||||
if (!current.contains(reEmpty)) {
|
||||
match = reComment.match(current);
|
||||
comments += match.captured() + '\n';
|
||||
}
|
||||
}
|
||||
comments.chop(1); // remove last newline
|
||||
|
||||
// parse decklist
|
||||
for (; index < max_line; ++index) {
|
||||
|
||||
// check if line is a card
|
||||
match = reCardLine.match(inputs.at(index));
|
||||
if (!match.hasMatch())
|
||||
continue;
|
||||
}
|
||||
QString cardName = match.captured().simplified();
|
||||
|
||||
// If we have a blank line and it's the _ONLY_ blank line in the paste
|
||||
// and it follows at least one valid card
|
||||
// Then we assume it means to start the sideboard section of the paste.
|
||||
// If we have the word "Sideboard" appear on any line, then that will
|
||||
// also indicate the start of the sideboard.
|
||||
if ((line.isEmpty() && blankLines == 1 && okRows > 0) || line.startsWith("sideboard")) {
|
||||
inSideboard = true;
|
||||
continue; // The line isn't actually a card
|
||||
}
|
||||
|
||||
isSideboard = inSideboard;
|
||||
|
||||
if (line.startsWith("sb:")) {
|
||||
line = line.mid(3).trimmed();
|
||||
isSideboard = true;
|
||||
}
|
||||
|
||||
if (line.trimmed().isEmpty()) {
|
||||
continue; // The line was " " instead of "\n"
|
||||
}
|
||||
|
||||
// Filter out MWS edition symbols and basic land extras
|
||||
QRegExp rx("\\[.*\\]\\s?");
|
||||
line.remove(rx);
|
||||
rx.setPattern("\\s?\\(.*\\)");
|
||||
line.remove(rx);
|
||||
|
||||
// Filter out post card name editions
|
||||
rx.setPattern("\\|.*$");
|
||||
line.remove(rx);
|
||||
|
||||
// If the user inputs "Quicksilver Elemental" then it will cut it off
|
||||
// 1x Squishy Treaker
|
||||
int i = line.indexOf(' ');
|
||||
int cardNameStart = i + 1;
|
||||
|
||||
if (i > 0) {
|
||||
// If the count ends with an 'x', ignore it. For example,
|
||||
// "4x Storm Crow" will count 4 correctly.
|
||||
if (line.at(i - 1) == 'x') {
|
||||
i--;
|
||||
} else if (!line.at(i - 1).isDigit()) {
|
||||
// If the user inputs "Quicksilver Elemental" then it will work as 1x of that card
|
||||
cardNameStart = 0;
|
||||
// check if card should be sideboard
|
||||
bool sideboard = false;
|
||||
if (sBStart < 0) {
|
||||
match = reSBMark.match(cardName);
|
||||
if (match.hasMatch()) {
|
||||
sideboard = true;
|
||||
cardName = match.captured(1);
|
||||
}
|
||||
} else {
|
||||
if (index == sBStart) // skip sideboard line itself
|
||||
continue;
|
||||
sideboard = index > sBStart;
|
||||
}
|
||||
|
||||
bool ok;
|
||||
int number = line.left(i).toInt(&ok);
|
||||
|
||||
if (!ok) {
|
||||
number = 1; // If input is "cardName" assume it's "1x cardName"
|
||||
// check if a specific amount is mentioned
|
||||
int amount = 1;
|
||||
match = reMultiplier.match(cardName);
|
||||
if (match.hasMatch()) {
|
||||
amount = match.capturedRef(1).toInt();
|
||||
cardName = match.captured(2);
|
||||
}
|
||||
|
||||
QString cardName = line.mid(cardNameStart);
|
||||
// remove stuff inbetween braces
|
||||
cardName.remove(reBrace);
|
||||
cardName.remove(reRoundBrace); // I'll be entirely honest here, these are split to accommodate just three cards
|
||||
cardName.remove(reDigitBrace); // all cards from un-sets that have a word in between round braces at the end
|
||||
|
||||
// Common differences between Cockatrice's card names
|
||||
// and what's commonly used in decklists
|
||||
rx.setPattern("’");
|
||||
cardName.replace(rx, "'");
|
||||
rx.setPattern("Æ");
|
||||
cardName.replace(rx, "Ae");
|
||||
rx.setPattern("\\s*[|/]{1,2}\\s*");
|
||||
cardName.replace(rx, " // ");
|
||||
|
||||
// Replace only if the ampersand is preceded by a non-capital letter,
|
||||
// as would happen with acronyms. So 'Fire & Ice' is replaced but not
|
||||
// 'R&D' or 'R & D'.
|
||||
// Qt regexes don't support lookbehind so we capture and replace instead.
|
||||
rx.setPattern("([^A-Z])\\s*&\\s*");
|
||||
if (rx.indexIn(cardName) != -1) {
|
||||
cardName.replace(rx, QString("%1 // ").arg(rx.cap(1)));
|
||||
// replace common differences in cardnames
|
||||
for (auto diff = differences.constBegin(); diff != differences.constEnd(); ++diff) {
|
||||
cardName.replace(diff.key(), diff.value());
|
||||
}
|
||||
|
||||
// We need to get the name of the card from the database,
|
||||
// but we can't do that until we get the "real" name
|
||||
// (name stored in database for the card)
|
||||
// and establish a card info that is of the card, then it's
|
||||
// a simple getting the _real_ name of the card
|
||||
// (i.e. "STOrm, CrOW" => "Storm Crow")
|
||||
// get cardname, this function does nothing if the name is not found
|
||||
cardName = getCompleteCardName(cardName);
|
||||
|
||||
// Look for the correct card zone of where to place the new card
|
||||
QString zoneName = getCardZoneFromName(cardName, isSideboard ? DECK_ZONE_SIDE : DECK_ZONE_MAIN);
|
||||
// get zone name based on if it's in sideboard
|
||||
QString zoneName = getCardZoneFromName(cardName, sideboard ? DECK_ZONE_SIDE : DECK_ZONE_MAIN);
|
||||
|
||||
okRows++;
|
||||
new DecklistCardNode(cardName, number, getZoneObjFromName(zoneName));
|
||||
// make new entry in decklist
|
||||
new DecklistCardNode(cardName, amount, getZoneObjFromName(zoneName));
|
||||
}
|
||||
|
||||
updateDeckHash();
|
||||
return (okRows > 0);
|
||||
return true;
|
||||
}
|
||||
|
||||
InnerDecklistNode *DeckList::getZoneObjFromName(const QString zoneName)
|
||||
|
|
|
|||
108
common/expression.cpp
Normal file
108
common/expression.cpp
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#include "expression.h"
|
||||
#include "./lib/peglib.h"
|
||||
|
||||
#include <QByteArray>
|
||||
#include <QString>
|
||||
#include <cmath>
|
||||
#include <functional>
|
||||
|
||||
peg::parser math(R"(
|
||||
EXPRESSION <- P0
|
||||
P0 <- P1 (P1_OPERATOR P1)*
|
||||
P1 <- P2 (P2_OPERATOR P2)*
|
||||
P2 <- P3 (P3_OPERATOR P3)*
|
||||
P3 <- NUMBER / FUNCTION / VARIABLE / '(' P0 ')'
|
||||
|
||||
P1_OPERATOR <- < [-+] >
|
||||
P2_OPERATOR <- < [/*] >
|
||||
P3_OPERATOR <- < '^' >
|
||||
|
||||
NUMBER <- < '-'? [0-9]+ >
|
||||
NAME <- < [a-z][a-z0-9]* >
|
||||
VARIABLE <- < [x] >
|
||||
FUNCTION <- NAME '(' EXPRESSION ( [,\n] EXPRESSION )* ')'
|
||||
|
||||
%whitespace <- [ \t\r]*
|
||||
)");
|
||||
|
||||
QMap<QString, std::function<double(double)>> *default_functions = nullptr;
|
||||
|
||||
Expression::Expression(double initial) : value(initial)
|
||||
{
|
||||
if (default_functions == nullptr) {
|
||||
default_functions = new QMap<QString, std::function<double(double)>>();
|
||||
default_functions->insert("sin", [](double a) { return sin(a); });
|
||||
default_functions->insert("cos", [](double a) { return cos(a); });
|
||||
default_functions->insert("tan", [](double a) { return tan(a); });
|
||||
default_functions->insert("sqrt", [](double a) { return sqrt(a); });
|
||||
default_functions->insert("log", [](double a) { return log(a); });
|
||||
default_functions->insert("log10", [](double a) { return log(a); });
|
||||
default_functions->insert("trunc", [](double a) { return trunc(a); });
|
||||
default_functions->insert("abs", [](double a) { return abs(a); });
|
||||
|
||||
default_functions->insert("floor", [](double a) { return floor(a); });
|
||||
default_functions->insert("ceil", [](double a) { return ceil(a); });
|
||||
default_functions->insert("round", [](double a) { return round(a); });
|
||||
default_functions->insert("trunc", [](double a) { return trunc(a); });
|
||||
}
|
||||
fns = QMap<QString, std::function<double(double)>>(*default_functions);
|
||||
}
|
||||
|
||||
double Expression::eval(const peg::Ast &ast)
|
||||
{
|
||||
const auto &nodes = ast.nodes;
|
||||
if (ast.name == "NUMBER") {
|
||||
return stod(ast.token);
|
||||
} else if (ast.name == "FUNCTION") {
|
||||
QString name = QString::fromStdString(nodes[0]->token);
|
||||
if (!fns.contains(name))
|
||||
return 0;
|
||||
return fns[name](eval(*nodes[1]));
|
||||
} else if (ast.name == "VARIABLE") {
|
||||
return value;
|
||||
} else if (ast.name[0] == 'P') {
|
||||
double result = eval(*nodes[0]);
|
||||
for (int i = 1; i < nodes.size(); i += 2) {
|
||||
double arg = eval(*nodes[i + 1]);
|
||||
char operation = nodes[i]->token[0];
|
||||
switch (operation) {
|
||||
case '+':
|
||||
result += arg;
|
||||
break;
|
||||
case '-':
|
||||
result -= arg;
|
||||
break;
|
||||
case '*':
|
||||
result *= arg;
|
||||
break;
|
||||
case '/':
|
||||
result /= arg;
|
||||
break;
|
||||
case '^':
|
||||
result = pow(result, arg);
|
||||
break;
|
||||
default:
|
||||
result = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
double Expression::parse(const QString &expr)
|
||||
{
|
||||
QByteArray ba = expr.toLocal8Bit();
|
||||
|
||||
math.enable_ast();
|
||||
|
||||
std::shared_ptr<peg::Ast> ast;
|
||||
if (math.parse(ba.data(), ast)) {
|
||||
ast = peg::AstOptimizer(true).optimize(ast);
|
||||
return eval(*ast);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
28
common/expression.h
Normal file
28
common/expression.h
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
#ifndef EXPRESSION_H
|
||||
#define EXPRESSION_H
|
||||
|
||||
#include <QMap>
|
||||
#include <QString>
|
||||
#include <functional>
|
||||
|
||||
namespace peg
|
||||
{
|
||||
template <typename Annotation> struct AstBase;
|
||||
struct EmptyType;
|
||||
typedef AstBase<EmptyType> Ast;
|
||||
} // namespace peg
|
||||
|
||||
class Expression
|
||||
{
|
||||
public:
|
||||
double value;
|
||||
|
||||
explicit Expression(double initial = 0);
|
||||
double parse(const QString &expr);
|
||||
|
||||
private:
|
||||
double eval(const peg::Ast &ast);
|
||||
QMap<QString, std::function<double(double)>> fns;
|
||||
};
|
||||
|
||||
#endif
|
||||
3293
common/lib/peglib.h
Normal file
3293
common/lib/peglib.h
Normal file
File diff suppressed because it is too large
Load Diff
|
|
@ -169,3 +169,12 @@ if (UNIX)
|
|||
set(cockatrice_protocol_LIBS ${cockatrice_protocol_LIBS} -lpthread)
|
||||
endif (UNIX)
|
||||
target_link_libraries(cockatrice_protocol ${cockatrice_protocol_LIBS})
|
||||
|
||||
# ubuntu uses an outdated package for protobuf, 3.1.0 is required
|
||||
if(${Protobuf_VERSION} VERSION_LESS "3.1.0")
|
||||
# remove unused parameter and misleading indentation warnings when compiling to avoid errors
|
||||
set(CMAKE_CXX_FLAGS_DEBUG
|
||||
"${CMAKE_CXX_FLAGS_DEBUG} -Wno-unused-parameter -Wno-misleading-indentation")
|
||||
message(WARNING "Outdated protobuf version found (${Protobuf_VERSION} < 3.1.0), "
|
||||
"disabled warnings to avoid compilation errors.")
|
||||
endif()
|
||||
|
|
|
|||
|
|
@ -5,3 +5,10 @@ message Command_Concede {
|
|||
optional Command_Concede ext = 1017;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
message Command_Unconcede {
|
||||
extend GameCommand {
|
||||
optional Command_Unconcede ext = 1032;
|
||||
}
|
||||
}
|
||||
|
|
@ -6,3 +6,9 @@ message Context_Concede {
|
|||
optional Context_Concede ext = 1001;
|
||||
}
|
||||
}
|
||||
|
||||
message Context_Unconcede {
|
||||
extend GameEventContext {
|
||||
optional Context_Unconcede ext = 1009;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user