Compare commits

...

100 Commits

Author SHA1 Message Date
Zach H
a95b338c80 Add cmake format (#4618)
* Support CMakeify operation

* Run Cmakeify

* Update cmakeify.sh

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2022-05-08 21:22:43 +02:00
Zach H
3e90f109a2 Prevent bad access potential for removals by checking bounds (#4617)
* Prevent bad access potential for removals by checking bounds
Fix #4616

Switch to removeOne instead of bound checking removeAt

* Revert server cardzone check
2022-05-08 20:26:50 +02:00
ZeldaZach
b02adccf87 Support Qt6, Min Qt5.8, Fix Win32, Fix Servatrice
Add lock around deleting arrows for commanding cards

Add support for Qt6 w/ Backwards Qt5

Handle Qt5/6 cross compilation better

Last cleanups

caps matter

Fix serv

Prevent crash on 6.3.0 Linux & bump to 5.8 min

Prevent out of bounds indexing

Delete shutdown timer if it exists

Fixup ticket comments, remove unneeded guards

Try to add support for missing OSes

Update .ci/release_template.md

Update PR based on comments

Update XML name after done and remove Hirsute

Address local game crash

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

make soundengine more consistent across qt versions

disable tests on distros that are covered by others

Fix Oracle Crash due to bad memory access

Update Oracle to use new Qt6 way of adding translations

Add support for Qt5/Qt6 compiling of Cockatrice

Remove unneeded calls to QtMath/cmath/math.h

Update how we handle bitwise comparisons for enums with Tray Icon

Change header guards to not duplicate function

Leave comment & Fix Path for GHA Qt

Update common/server.h

Update cockatrice/src/window_main.cpp

Rollback change on cmake module path for NSIS

check docker image requirements

add size limit to ccache

put variables in quotes

properly set build type on mac

avoid names used in cmake

fix up cmake module path

cmake 3.10 does not recognize prepend

Support Tests in FindQtRuntime

set ccache size on non debug builds as well

immediately return when removing non existing client

handle incTxBytes with a signal instead

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

add comments

set macos qt version to 6

Try upgrading XCode versions to latest they can be supported on

Ensure Qt gets linked

add tmate so i can see what's going on

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

Establish Plugins directory for Qt6

Establish TLS plugins for Qt6 services

Minor change for release channel network manager

Let windows build in parallel cores

Wrong symbols

Qt6 patch up for signal

add missing qt6 package on deb builds

boolean expressions are hard

negative indexes should go to the end

Intentionally fail cache

move size checks to individual zone types

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

Update wording

use the --parallel option in all builds

clean up the .ci scripts some more

tweak fedora build

add os parameter to compile.sh

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

fixup yml

readd appended cache key to vcpkg step

fix windows 32 quirk

the json hash is already added to the key as well

remove os parameter and clean up ci files

set name_build.sh to output relative paths

set backwards compatible version of xcode and qt on mac

set QTDIR for mac builds on qt5

has no effect for qt6

export BUILD_DIR to name_build.sh

merge mac build steps

merge homebrew steps, set package suffix

link qt5

remove brew link

set qtdir to qt5 only

compile.sh vars need to be empty not 0

fix sets manager search bar on qt 5.12/15

fix oracle subprocess errors being ignored on qt 5

clean up translation loading

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

Use generator platform over osname

Short circuit if not Win defined
2022-05-06 17:31:08 -04:00
dependabot[bot]
accd5e4df7 Bump async from 2.6.3 to 2.6.4 in /webclient (#4614)
Bumps [async](https://github.com/caolan/async) from 2.6.3 to 2.6.4.
- [Release notes](https://github.com/caolan/async/releases)
- [Changelog](https://github.com/caolan/async/blob/v2.6.4/CHANGELOG.md)
- [Commits](https://github.com/caolan/async/compare/v2.6.3...v2.6.4)

---
updated-dependencies:
- dependency-name: async
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-06 17:31:08 -04:00
dependabot[bot]
d007196059 Bump ejs from 3.1.6 to 3.1.7 in /webclient (#4613)
Bumps [ejs](https://github.com/mde/ejs) from 3.1.6 to 3.1.7.
- [Release notes](https://github.com/mde/ejs/releases)
- [Changelog](https://github.com/mde/ejs/blob/main/CHANGELOG.md)
- [Commits](https://github.com/mde/ejs/compare/v3.1.6...v3.1.7)

---
updated-dependencies:
- dependency-name: ejs
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-05-06 17:31:08 -04:00
ebbit1q
79501a4af7 fix the uid and gid of the user in the docker container (#4610)
* fix the uid and gid of the user in the container

this fixes this error:
unsafe repository ('/src' is owned by someone else)
this caused the hash to go missing in the version number

* add --interactive option to .ci/docker.sh

* add --dir to .ci/compile.sh

* fix up the comments on the ci scripts

* add extra comment to docker.sh
2022-04-18 19:04:49 -04:00
ebbit1q
64c6611ea5 env vars don't go into docker containers like that (#4609)
reverts a bit of #4580 92ed53e13a
2022-04-17 22:11:55 -04:00
Zach H
a532a63403 Change actions to use Windows 2019
Windows 2022 isn't stable yet with the Qt installer, and we need to cut releases so this unblocks us
2022-04-02 00:55:05 -04:00
tooomm
c10c69d0a9 fix if condition on ci translations (#4603) 2022-04-01 11:24:51 +02:00
dependabot[bot]
191d5a83a9 Bump minimist from 1.2.5 to 1.2.6 in /webclient (#4601)
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-26 21:50:52 -04:00
dependabot[bot]
de69e2c41f Bump node-forge from 1.2.1 to 1.3.0 in /webclient (#4600)
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.2.1 to 1.3.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.2.1...v1.3.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-03-26 21:49:27 -04:00
Jeremy Letto
6d200d17b7 close previous testConnect attempts (#4598)
* close previous testConnect attempts

* remove onerror handler when canceling previous attempt

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-03-22 17:42:58 -05:00
Jeremy Letto
4899b6cfef add kosovo flag (#4597)
* add kosovo flag

* add xk and eu flags to cockatrice

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2022-03-19 20:07:40 -05:00
Jeremy Letto
0ff59e6d1e test connection UI (#4596)
* test connection UI

* cleanup

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-03-19 19:22:00 -05:00
Jeremy Letto
00a2a8ab71 update pr-bt translation file (#4593)
Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-03-13 15:59:36 -04:00
Jeremy Letto
2c702d3579 Webatrice: husky (#4591) 2022-03-13 13:44:51 -04:00
ebbit1q
b464fa8d99 actualise country names (#4592)
see wikipedia here:
https://en.m.wikipedia.org/wiki/ISO_3166-1_alpha-2#Officially_assigned_code_elements
2022-03-07 21:46:09 -06:00
ZeldaZach
2b330940e1 ncu update 2022-03-07 13:46:43 -05:00
Jeremy Letto
0d0337f091 Webatrice: update package.json (#4590)
* update package.json

* cleanup

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-03-07 13:43:01 -05:00
Jeremy Letto
533045445a Webatrice: improve language dropdown (#4589)
* useLocaleSort hook, translate language dropdown

* add pt-BR translation

* fix pt-BR flag

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-03-06 20:12:27 -06:00
Jeremy Letto
21f7dd5eba add fr and nl translations (#4587)
* add fr and nl translations

* update fr

* fix password label translation

* translate country strings

* fix double accents

* fix Ivory Coast

* sort countries

* use more performant Collator over localeCompare

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-03-06 17:19:51 -06:00
Jeremy Letto
f5b973e15c Webatrice: i18n login screen (#4584)
* i18n: login container and form

* i18n: activate, host, and register forms

* i18n: reset password forms

* i18n: login dialogs, ICU formatting

* i18n: login containers and components

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-03-02 22:34:57 -06:00
ebbit1q
baaf261116 use utf8 instead of the system encoding (#4582)
* use utf8 instead of the system preference

* found another toLocal8Bit
2022-02-27 22:33:36 +01:00
ebbit1q
92ed53e13a update workflow to use windows 2022 image (#4580)
* update workflow to use windows 2022 image

* return the version of the run vcpkg action

the action has been changed to now use a vcpkg.json file instead of the
txt file we use now, we should try to find a way to update it to the new
workflow in case the current one becomes obsolete

* clean up a bit for consistency

* run ctest directly instead of relying on the makefile

* set -C flag for ctest

* set config option for cmake --build

this option is ignored for other platforms
2022-02-27 22:32:54 +01:00
Jeremy Letto
2a54e9d7d1 Webatrice: fix saved password (#4563)
* fix saved label, and fix using hashedPassword when Save is unchecked

* update host only after successful login

* cleanup

* fix ability to deselect saved password on successful login

* cleanup

* clear options after connection

* fix registration saved username

* cleanup

* change label

* fix tests

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-02-27 10:12:38 -06:00
Jeremy Letto
9577ada171 Webatrice: i18n (#4562)
* implement i18n capability

* reset package.lock file

* remove custom fallback

* fix relative path for i18n files

* check for language support before fetch request

* add LanguageDropdown component, es translation file to prove functionality

* remove boilerplate

* bundle default english translation with app

* add missing file

* rollup component-level i18n files

* cleanup

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-02-26 21:36:53 -06:00
ebbit1q
217dc09c0f fix image downscaling (#4567) 2022-02-23 23:46:53 +01:00
ebbit1q
7108eb42c8 implement custom protobuf debug string creation (#4532)
* implement custom protobuf debug log string creation

* add version guards

* add missing header

* debian10 repository misses headers

* clean up logging messages a bit

* fix some more formatting on debug messages
2022-02-23 23:46:23 +01:00
ebbit1q
eb3ce1fd7e hide revealed cards when they are shuffled (#4570) 2022-02-23 23:46:07 +01:00
dependabot[bot]
c88d44e16c Bump url-parse from 1.5.3 to 1.5.7 in /webclient (#4578)
Bumps [url-parse](https://github.com/unshiftio/url-parse) from 1.5.3 to 1.5.7.
- [Release notes](https://github.com/unshiftio/url-parse/releases)
- [Commits](https://github.com/unshiftio/url-parse/compare/1.5.3...1.5.7)

---
updated-dependencies:
- dependency-name: url-parse
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 23:44:27 -05:00
dependabot[bot]
ec2ad4c713 Bump follow-redirects from 1.14.7 to 1.14.8 in /webclient (#4574)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.7 to 1.14.8.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.7...v1.14.8)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-02-22 23:44:16 -05:00
Brent Clark
4c04b4ef5a Webatrice: Registration toasts (#4566)
* wip

* Registration Success Toast

* remove debugging code

* remove unused field

* Show toast on successful password reset

* Toast on account activation success

* lint and PR feedback

* Rework interface names to avoid collision

* Move CssBaseline to sibling of ToastProvider

Co-authored-by: Brent Clark <brent@backboneiq.com>
2022-02-16 02:40:30 +01:00
Jeremy Letto
88b861d632 Webatrice: improve prebuild steps and add .env configs (#4564)
* create .env file for server configuration

* render client version

* automate env file

* add prestart command

* create server-props.json instead of using .env

* automate master proto file

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-02-13 00:58:47 +01:00
ebbit1q
408a13c937 remove unused include in pb file (#4572)
shows as warning on compile:
session_commands.proto:2:1: warning: Import serverinfo_user.proto is unused.
2022-02-12 23:40:47 +01:00
ebbit1q
7d0a255a49 add database migration from blob to mediumblob (#4568) 2022-02-09 20:11:13 +01:00
ebbit1q
252883f67e set rx and txBytes to zero on initialization (#4569) 2022-02-09 17:57:35 +01:00
Jeremy Letto
bf08a04cda Webatrice: tech debt (#4560)
* turn autocomplete off by default on inputs

* trim input fields onSubmit

* move trim to form submit

* cleanup

* remove dead code

* protect trim against null values

* make password optional on Login for servers that allow unregisted logins

* cleanup

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-02-06 17:41:02 +01:00
Jeremy Letto
6928a2bd98 Webatrice: show loading screen until protobuf initializes (#4559)
* show loading screen until protobuf initializes

* cleanup

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-02-04 17:03:39 -05:00
Jeremy Letto
bb16ae09ef Webatrice: fix login bugs (#4557)
* fix login after failed connection attempts, limit connection attempt time

* fix register hashed password and salt

* add feature detection and Unsupported Browser screen

* nit

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-02-04 14:07:15 -05:00
Brent Clark
81d031ca0f Webclient: Add Toasts component and show on known host CUD operations (#4556)
* Add Toasts component and show on known host CUD operations

* add slide transition

* NIT

Co-authored-by: Brent Clark <brent@backboneiq.com>
2022-02-01 12:08:05 -06:00
Jeremy Letto
8203a2fdeb fix failed saltRequest (#4554)
* fix failed saltRequest

* improve requestSalt error handling

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-02-01 04:03:31 +01:00
tooomm
75f0d60dff Webclient: Update script (#4553)
* Update package.json

* introduce linting error

* Revert "introduce linting error"

This reverts commit 0a622bcb2e.
2022-01-31 15:14:22 +01:00
Jeremy Letto
992e28797f Webatrice: support hashed passwords in register and resetPassword (#4549)
* support hashed passwords in register and resetPassword

* lint

* support hashedPasswords for accountActivation

* use salt in post-register login step

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-01-30 22:09:16 -06:00
Jeremy Letto
92f941a54c renable login after fail attempt (#4552)
Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-01-30 22:06:30 -06:00
Jeremy Letto
4c31527832 implement password length requirements (#4551)
Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-01-31 03:51:01 +01:00
Jeremy Letto
febe029ed4 use CompanyDropdown component in registration form (#4548)
Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-01-30 19:47:10 -06:00
Jeremy Letto
1d780058c8 Webatrice: Add account validation dialog/form (#4547)
* Add account validation dialog/form

* clean up

* close registration dialog on token request

* remove dupe code

* add subtitle styling

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2022-01-30 19:42:34 -06:00
Brent Clark
513fcb0908 Webclient: Handle firing an event once (#4499)
* draft: handle firing an event once

* lint

* Prevent rapid double-click on sending messages

* no rest spread on single primative when sibling components exist

* clear message instead of using a fireOnce handler.

* fix tests

* remove unnecessary validate mock
2022-01-30 12:14:28 -05:00
dependabot[bot]
4bb13677c8 Bump nanoid from 3.1.30 to 3.2.0 in /webclient (#4542)
Bumps [nanoid](https://github.com/ai/nanoid) from 3.1.30 to 3.2.0.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.1.30...3.2.0)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-24 00:15:46 -05:00
ebbit1q
a5baf4303c create workflow for automatically updating the translation sources (#4543)
* create workflow for automatically updating the translation sources

* change to once per month
2022-01-23 23:14:48 +01:00
ZeldaZach
7aba404f2e Add i18n for Oracle and fix Transifex 2022-01-22 00:17:29 -05:00
Zach H
1b7e8f3a16 Re-add handling of i18n for Oracle (since it was manual before) (#4541)
Removes en@source from options menu intentionally
2022-01-21 23:35:04 -05:00
ZeldaZach
5cf93ad61c Remove empty languages 2022-01-21 22:59:47 -05:00
ZeldaZach
5a52e085a7 Translation Dump! 2022-01-21 22:28:07 -05:00
ebbit1q
5d31b70406 [WIP] add english translation (#4120)
* move en.ts to en@source.ts

* run lupdate

Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2022-01-21 21:35:26 -05:00
tooomm
2885f93fdf run ci not only on pr's to master (#4537) 2022-01-20 18:27:26 +01:00
tooomm
d225f55e5a CI: Uniform job ordering and naming (#4534)
* remove xcode string in file name

* alphabetical ordering + newest to the top

* remove not needed entries

* append -bit to name

* chronological

* spaces
2022-01-20 02:51:42 +01:00
tooomm
69edc73585 cleanup (#4530) 2022-01-18 16:40:05 +01:00
tooomm
ead1143f2e Prettier settings dialog (#4357)
* prevent stretched layout in settings

* restore layout of settings pages with already expanding elements

* Support full screen resolution and set a minimum that works well no matter the screen size

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2022-01-16 21:06:52 -05:00
ebbit1q
2fc85e0c08 use hashed passwords in all commands (#4493)
* protocol changes

* server changes

* client changes for password reset and registration

* add hashed password to change password in client

* always use hashed password to log in

* add warning to client when using plain text password

* require real password for changing email on server

this is backwards compatible as users logged in with a real password on
older clients will not need this, only users logged in with a hashed
password

* implement password dialog when changing email

* require min password length

* use qstringlist to build query instead

* use clear instead of = ""

* add max to password dialog

* use proper const ness in abstractclient

* reject too long passwords instead of trimming
2022-01-16 20:32:30 -05:00
ebbit1q
fcafcb340a remove all instances of the type long (#4519)
the long type has different sizes across operating systems and should
not be used

in the timeline an overflow could occur if the width in pixels
multiplied by the total amount of milliseconds in the replay is larger
than 2^31 which is easy enough considering with only 500 pixels width
you'll reach this number with only 1.2 hours of replay (about 4 million
millis), note that this would be windows exclusive as *nix uses 64 bits

~~qt-json's own repo suggests using qt5's implementation instead, testing
revealed this is quite a bit faster, contrary to #3480~~ testing proved
this to not be compatible with older qt versions

servatrice uses the qthread usleep function which used to be protected
but is now public

cockatrice is not compatible with qt4 and hasn't been for a while
2022-01-16 18:05:24 -05:00
ebbit1q
ae9b8b8f34 miscellaneous refactors (#4521) 2022-01-16 17:58:53 -05:00
ebbit1q
994704d353 implement max lengths for input dialogs that are sent to the server (#4522)
* implement max lengths for input dialogs that are sent to the server

* missed a double setMaxLength

* implement max string lengths server side

* add custom getText dialog with max length

* fix deck storage tab and miscellaneous server side

* add max size for deck uploads

* final pass on client side limits
2022-01-16 17:57:01 -05:00
Zach H
d61c604bf4 Address macOS issue where right-clicking a username in the main chat (#4523)
* Address macOS issue where right-clicking a username in the main chat (or game chat) areas would pop up a seemingly empty user profile. This is because the resize event is overridden and doesn't actually attempt to resize based on the size hint of the dialog. Now that we're explicit with the call, this resize should be forced and have comparable results to popping up user profile from the user list.

* use datetime for calculating account age (#4526)

* use datetime for calculating account age

make translating easier by using tr multiples
automatically account for leap days

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2022-01-16 16:51:13 -05:00
tooomm
baaf22d0c4 UI: Improve alignment in user info (#4524)
* fix alignment

* tweaking

* lint

* limit flag to one column

* lint

* cleanup

* Update userinfobox.cpp

* re-add manual window resizing

* Update cockatrice/src/userinfobox.cpp

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
2022-01-16 22:49:41 +01:00
tooomm
368ff1793f CI: Add Debian 11 (#4525)
* add debian 11

* rename debian10

* fix space

* Update Dockerfile
2022-01-16 16:46:04 -05:00
dependabot[bot]
3253ad64fd Bump follow-redirects from 1.14.5 to 1.14.7 in /webclient (#4527)
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.14.5 to 1.14.7.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.14.5...v1.14.7)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2022-01-16 16:32:22 -05:00
ebbit1q
1e70989f38 add password hash test (#4528)
* clangify tests

* add password hash test

* properly use googletest semantics
2022-01-16 16:32:11 -05:00
ebbit1q
f6634de18d replace fixed size of criteria in log tab (#4515)
it's now a max size with expanding policy, looks fine I guess
fixes #4510
2022-01-11 21:35:18 -05:00
ebbit1q
7903cd520a perform restartLayout conditionally (#4513)
* Revert "Fixed layout on Deck Editor not using last layout. It was reseting layout on ctor. (#4420)"

This reverts commit 3bc90003b3.

* restart layout on fresh installs
2022-01-08 16:03:53 -05:00
ebbit1q
26d1fcc944 simplify search string (#4516) 2022-01-08 16:02:54 -05:00
ebbit1q
59d4e64a8d use multiline input dialog for annotations (#4517) 2022-01-08 16:02:25 -05:00
ebbit1q
1347d88ddb also forgot this in #4496 (#4514) 2022-01-08 16:01:54 -05:00
ebbit1q
6981cca2ae use qt round for better cross platform consistency (#4518)
* use qt round for better cross platform consistency

* remove unnecessary casts
2022-01-08 16:01:15 -05:00
ebbit1q
4d6c9ede8c missed this in #4496 (#4512) 2022-01-07 00:34:56 -05:00
ebbit1q
e845c95816 remove ccache from mac builds (#4505) 2021-12-27 22:23:11 -05:00
ebbit1q
a9f2fc427b allow servatrice to exit early based on commandline options (#4504) 2021-12-26 16:47:37 +01:00
ebbit1q
07e6aadbbe deprecate the gender property from the protocol entirely (#4496)
* deprecate the gender property from the protocol entirely

* use obsolete instead of deprecated

* add the database migration

* update internal database version as well
2021-12-14 01:51:57 -05:00
tooomm
86881bbbc3 CI: Little tweaks to web (#4488) 2021-12-07 23:01:46 -05:00
Jeremy Letto
1f15445c69 connect reset password to login view (#4489) 2021-12-07 22:57:12 -05:00
ebbit1q
811ee54c76 Fix move (#4491)
* wip fix card moving on server

* fix flipped cards being moved as -1

* fix cards from hand being moved as -1
2021-12-07 22:56:58 -05:00
ebbit1q
d1a40fd36e fix regression in local games (#4490) 2021-12-07 22:54:36 -05:00
ebbit1q
a3d3aaaca8 fix server crash on receiving email without @ (#4492) 2021-11-30 19:44:20 -08:00
tooomm
c5aaa0bc2e CI: Add webclient (#4478) 2021-11-26 16:55:53 -05:00
Jeremy Letto
6dc9f004ce fix tests, add golden command (#4486)
Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2021-11-26 16:55:12 -05:00
Jeremy Letto
6ce346af4a Webatrice: KnownHosts component (#4456)
* refactor dexie services for future schema updates

Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2021-11-25 22:12:23 -05:00
ZeldaZach
37879c4255 Re-lint on linux 2021-11-23 02:49:11 -05:00
Zach H
0683d1aced Support Server requests for MFA, Render failed UI statuses to user, C… (#4483)
* Support Server requests for MFA, Render failed UI statuses to user, Connect to KnownHosts component
2021-11-23 02:45:08 -05:00
Joseph Chamish
73c5956ece Dev/jchamish/forgotpassword (#4481)
* Implementation of Forgotten Password Reset

* Update webclient/src/hooks/useReduxEffect.tsx

Co-authored-by: Zach H <zahalpern+github@gmail.com>
2021-11-19 21:00:05 -05:00
Zach H
7c27e955d5 Support all OS development for linters and prevent linting while in dev mode (#4480) 2021-11-19 20:59:55 -05:00
Jeremy Letto
6ef394000b fix file line returns (#4482)
Co-authored-by: Jeremy Letto <jeremy.letto@datasite.com>
2021-11-18 19:46:49 -05:00
Aren Kasner
755a09bd83 country dropdown (#4479) 2021-11-16 16:55:30 -05:00
ZeldaZach
8b1daa21ef Revert "fix card moving on server (#4413)"
This reverts commit c25bf491e4.
2021-11-15 00:54:21 -05:00
ebbit1q
691bcb9338 comment out new feature from feature list (#4477)
we don't have an official release for a version that has this feature
yet
2021-11-15 00:44:16 -05:00
Joseph Chamish
911a303326 Fix the additional line endings (#4476) 2021-11-14 22:16:13 -05:00
Johannes
5652b56b45 Respect device pixel ratio when scaling card imgs (#4467) 2021-11-13 17:01:27 -05:00
Zach H
26acfd5102 Update packages & cleanup (#4475) 2021-11-13 15:30:49 -05:00
Zach H
f789e02096 Add ESLint & Run it against the system (#4470) 2021-11-13 14:56:15 -05:00
Zach H
43eee6b32e Support HashedPassword workflow for logins (#4469)
* Support HashedPassword workflow for logins

* Address comments in PR
2021-11-13 10:37:13 -06:00
ebbit1q
45d86e7ab7 allow login using hashed passwords (#4464)
* Support getting a user's password salt via initial websocket connection (added to Event_ServerIdentification)

* Nonsense stuff to figure out later

* move passwordhasher to correct location

* protobuf changes

* add ext to protobuf

* implement request password salt server side

* add supportspasswordhash to server identification

* check backwards compatibility

* reset some changes to master

* implement get password salt client side

* implement checking hashed passwords on server login

* check for registration requirement on getting password salt

* properly check password salt response and show errors

* remove unused property

* add password salt to list of response types

Co-authored-by: ZeldaZach <zahalpern+github@gmail.com>
2021-11-09 20:00:41 -05:00
449 changed files with 87745 additions and 92918 deletions

View File

@@ -1,4 +1,4 @@
FROM debian:buster
FROM debian:10
RUN apt-get update && apt-get install -y --no-install-recommends \
build-essential \
@@ -19,6 +19,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
qt5-default \
qtbase5-dev \
qtmultimedia5-dev \
qttools5-dev \
qttools5-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -1,4 +1,4 @@
FROM ubuntu:hirsute
FROM debian:11
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \

14
.ci/Fedora36/Dockerfile Normal file
View File

@@ -0,0 +1,14 @@
FROM fedora:36
RUN dnf install -y \
ccache \
cmake \
gcc-c++ \
git \
mariadb-devel \
protobuf-devel \
qt6-{qttools,qtsvg,qtmultimedia,qtwebsockets,qt5compat}-devel \
rpm-build \
xz-devel \
zlib-devel \
&& dnf clean all

View File

@@ -0,0 +1,27 @@
FROM ubuntu:jammy
RUN apt-get update && \
DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \
build-essential \
ccache \
clang-format \
cmake \
file \
g++ \
git \
libgl-dev \
liblzma-dev \
libmariadb-dev-compat \
libprotobuf-dev \
libqt6core5compat6-dev \
libqt6multimedia6 \
libqt6sql6-mysql \
libqt6svg6-dev \
libqt6websockets6-dev \
protobuf-compiler \
qt6-l10n-tools \
qt6-multimedia-dev \
qt6-tools-dev \
qt6-tools-dev-tools \
&& apt-get clean \
&& rm -rf /var/lib/apt/lists/*

View File

@@ -2,16 +2,26 @@
# This script is to be used by the ci environment from the project root directory, do not use it from somewhere else.
# Compiles cockatrice inside of a ci environment
# --install runs make install
# --package [<package type>] runs make package, optionally force the type
# --suffix <suffix> renames package with this suffix, requires arg
# --server compiles servatrice
# --test runs tests
# --debug or --release sets the build type ie CMAKE_BUILD_TYPE
# --ccache [<size>] uses ccache and shows stats, optionally provide size
# --dir <dir> sets the name of the build dir, default is "build"
# --parallel <core count> sets how many cores cmake should build with in parallel
# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_TEST USE_CCACHE CCACHE_SIZE BUILD_DIR PARALLEL_COUNT
# (correspond to args: --debug/--release --install --package <package type> --suffix <suffix> --server --test --ccache <ccache_size> --dir <dir> --parallel <core_count>)
# exitcode: 1 for failure, 3 for invalid arguments
# Read arguments
while [[ "$@" ]]; do
while [[ $# != 0 ]]; do
case "$1" in
'--')
shift
;;
'--format')
CHECK_FORMAT=1
shift
;;
'--install')
MAKE_INSTALL=1
shift
@@ -19,7 +29,7 @@ while [[ "$@" ]]; do
'--package')
MAKE_PACKAGE=1
shift
if [[ $# != 0 && $1 != -* ]]; then
if [[ $# != 0 && ${1:0:1} != - ]]; then
PACKAGE_TYPE="$1"
shift
fi
@@ -28,7 +38,7 @@ while [[ "$@" ]]; do
shift
if [[ $# == 0 ]]; then
echo "::error file=$0::--suffix expects an argument"
exit 1
exit 3
fi
PACKAGE_SUFFIX="$1"
shift
@@ -49,94 +59,137 @@ while [[ "$@" ]]; do
BUILDTYPE="Release"
shift
;;
*)
if [[ $1 == -* ]]; then
echo "::error file=$0::unrecognized option: $1"
'--ccache')
USE_CCACHE=1
shift
if [[ $# != 0 && ${1:0:1} != - ]]; then
CCACHE_SIZE="$1"
shift
fi
;;
'--dir')
shift
if [[ $# == 0 ]]; then
echo "::error file=$0::--dir expects an argument"
exit 3
fi
BUILDTYPE="$1"
BUILD_DIR="$1"
shift
;;
'--parallel')
shift
if [[ $# == 0 ]]; then
echo "::error file=$0::--parallel expects an argument"
exit 3
fi
PARALLEL_COUNT="$1"
shift
;;
*)
echo "::error file=$0::unrecognized option: $1"
exit 3
;;
esac
done
# Check formatting using clang-format
if [[ $CHECK_FORMAT ]]; then
echo "::group::Run linter"
source ./.ci/lint.sh
echo "::endgroup::"
fi
set -e
# Setup
./servatrice/check_schema_version.sh
mkdir -p build
cd build
if [[ ! $CMAKE_BUILD_PARALLEL_LEVEL ]]; then
CMAKE_BUILD_PARALLEL_LEVEL=2 # default machines have 2 cores
if [[ ! $BUILDTYPE ]]; then
BUILDTYPE=Release
fi
if [[ ! $BUILD_DIR ]]; then
BUILD_DIR="build"
fi
mkdir -p "$BUILD_DIR"
cd "$BUILD_DIR"
# Add cmake flags
flags=("-DCMAKE_BUILD_TYPE=$BUILDTYPE")
if [[ $MAKE_SERVER ]]; then
flags+=" -DWITH_SERVER=1"
flags+=("-DWITH_SERVER=1")
fi
if [[ $MAKE_TEST ]]; then
flags+=" -DTEST=1"
flags+=("-DTEST=1")
fi
if [[ $BUILDTYPE ]]; then
flags+=" -DCMAKE_BUILD_TYPE=$BUILDTYPE"
if [[ $USE_CCACHE ]]; then
flags+=("-DUSE_CCACHE=1")
if [[ $CCACHE_SIZE ]]; then
# note, this setting persists after running the script
ccache --max-size "$CCACHE_SIZE"
fi
fi
if [[ $PACKAGE_TYPE ]]; then
flags+=" -DCPACK_GENERATOR=$PACKAGE_TYPE"
flags+=("-DCPACK_GENERATOR=$PACKAGE_TYPE")
fi
if [[ $(uname) == "Darwin" ]]; then
# prepend ccache compiler binaries to path
PATH="/usr/local/opt/ccache/libexec:$PATH"
# Add qt install location when using homebrew
flags+=" -DCMAKE_PREFIX_PATH=/usr/local/opt/qt5/"
# Add cmake --build flags
buildflags=(--config "$BUILDTYPE")
if [[ $PARALLEL_COUNT ]]; then
if [[ $(cmake --build /not_a_dir --parallel |& head -1) =~ parallel ]]; then
# workaround for bionic having an old cmake
echo "this version of cmake does not support --parallel, using native build tool -j instead"
buildflags+=(-- -j "$PARALLEL_COUNT")
# note, no normal build flags should be added after this
else
buildflags+=(--parallel "$PARALLEL_COUNT")
fi
fi
function ccachestatsverbose() {
# note, verbose only works on newer ccache, discard the error
local got
if got="$(ccache --show-stats --verbose 2>/dev/null)"; then
echo "$got"
else
ccache --show-stats
fi
}
# Compile
echo "::group::Show ccache stats"
ccache --show-stats
echo "::endgroup::"
if [[ $USE_CCACHE ]]; then
echo "::group::Show ccache stats"
ccachestatsverbose
echo "::endgroup::"
fi
echo "::group::Configure cmake"
cmake --version
cmake .. $flags
cmake .. "${flags[@]}"
echo "::endgroup::"
echo "::group::Build project"
cmake --build .
cmake --build . "${buildflags[@]}"
echo "::endgroup::"
echo "::group::Show ccache stats again"
ccache --show-stats
echo "::endgroup::"
if [[ $USE_CCACHE ]]; then
echo "::group::Show ccache stats again"
ccachestatsverbose
echo "::endgroup::"
fi
if [[ $MAKE_TEST ]]; then
echo "::group::Run tests"
cmake --build . --target test
ctest -C "$BUILDTYPE"
echo "::endgroup::"
fi
if [[ $MAKE_INSTALL ]]; then
echo "::group::Install"
cmake --build . --target install
cmake --build . --target install --config "$BUILDTYPE"
echo "::endgroup::"
fi
if [[ $MAKE_PACKAGE ]]; then
echo "::group::Create package"
cmake --build . --target package
cmake --build . --target package --config "$BUILDTYPE"
echo "::endgroup::"
if [[ $PACKAGE_SUFFIX ]]; then
echo "::group::Update package name"
../.ci/name_build.sh "$PACKAGE_SUFFIX"
cd ..
BUILD_DIR="$BUILD_DIR" .ci/name_build.sh "$PACKAGE_SUFFIX"
echo "::endgroup::"
fi
fi

View File

@@ -3,11 +3,15 @@
# This script is to be used by the ci environment from the project root directory, do not use it from somewhere else.
# Creates or loads docker images to use in compilation, creates RUN function to start compilation on the docker image.
# <arg> sets the name of the docker image, these correspond to directories in .ci
# --get loads the image from a previously saved image cache, will build if no image is found
# --build builds the image from the Dockerfile in .ci/$NAME
# --save stores the image, if an image was loaded it will not be stored
# --interactive immediately starts the image interactively for debugging
# --set-cache <location> sets the location to cache the image or for ccache
# requires: docker
# uses env: NAME CACHE BUILD GET SAVE (correspond to args: <name> --set-cache <cache> --build --get --save)
# uses env: NAME CACHE BUILD GET SAVE INTERACTIVE
# (correspond to args: <name> --set-cache <cache> --build --get --save --interactive)
# sets env: RUN CCACHE_DIR IMAGE_NAME RUN_ARGS RUN_OPTS BUILD_SCRIPT
# exitcode: 1 for failure, 2 for missing dockerfile, 3 for invalid arguments
export BUILD_SCRIPT=".ci/compile.sh"
@@ -18,7 +22,7 @@ image_cache="image"
ccache_cache=".ccache"
# Read arguments
while [[ "$@" ]]; do
while [[ $# != 0 ]]; do
case "$1" in
'--build')
BUILD=1
@@ -28,6 +32,10 @@ while [[ "$@" ]]; do
GET=1
shift
;;
'--interactive')
INTERACTIVE=1
shift
;;
'--save')
SAVE=1
shift
@@ -36,12 +44,12 @@ while [[ "$@" ]]; do
CACHE=$2
if ! [[ -d $CACHE ]]; then
echo "could not find cache path: $CACHE" >&2
exit 3
return 3
fi
shift 2
;;
*)
if [[ $1 == -* ]]; then
if [[ ${1:0:1} == - ]]; then
echo "unrecognized option: $1"
return 3
fi
@@ -67,27 +75,27 @@ fi
if ! [[ $CACHE ]]; then
echo "cache dir is not set!" >&2
else
if ! [[ -d $CACHE ]]; then
echo "could not find cache dir: $CACHE" >&2
mkdir -p $CACHE
unset GET # the dir is empty
fi
if [[ $GET || $SAVE ]]; then
img_dir="$CACHE/$image_cache"
img_save="$img_dir/$IMAGE_NAME$save_extension"
if ! [[ -d $img_dir ]]; then
echo "could not find image dir: $img_dir" >&2
mkdir -p "$img_dir"
fi
fi
export CCACHE_DIR="$CACHE/$ccache_cache"
if ! [[ -d $CCACHE_DIR ]]; then
echo "could not find ccache dir: $CCACHE_DIR" >&2
mkdir -p "$CCACHE_DIR"
CACHE="$(mktemp -d)"
echo "set cache dir to $CACHE" >&2
fi
if ! [[ -d $CACHE ]]; then
echo "could not find cache dir: $CACHE" >&2
mkdir -p "$CACHE"
unset GET # the dir is empty
fi
if [[ $GET || $SAVE ]]; then
img_dir="$CACHE/$image_cache"
img_save="$img_dir/$IMAGE_NAME$save_extension"
if ! [[ -d $img_dir ]]; then
echo "could not find image dir: $img_dir" >&2
mkdir -p "$img_dir"
fi
fi
export CCACHE_DIR="$CACHE/$ccache_cache"
if ! [[ -d $CCACHE_DIR ]]; then
echo "could not find ccache dir: $CCACHE_DIR" >&2
mkdir -p "$CCACHE_DIR"
fi
# Get the docker image from previously stored save
if [[ $GET ]]; then
@@ -132,15 +140,26 @@ fi
function RUN ()
{
echo "running image:"
if docker images | grep "$IMAGE_NAME"; then
args="--mount type=bind,source=$PWD,target=/src -w=/src"
if [[ $(docker images) =~ "$IMAGE_NAME" ]]; then
local args=(--mount "type=bind,source=$PWD,target=/src")
args+=(--workdir "/src")
args+=(--user "$(id -u):$(id -g)")
if [[ $CCACHE_DIR ]]; then
args+=" --mount type=bind,source=$CCACHE_DIR,target=/.ccache -e CCACHE_DIR=/.ccache"
args+=(--mount "type=bind,source=$CCACHE_DIR,target=/.ccache")
args+=(--env "CCACHE_DIR=/.ccache")
fi
docker run $args $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS $@
docker run "${args[@]}" $RUN_ARGS "$IMAGE_NAME" bash "$BUILD_SCRIPT" $RUN_OPTS "$@"
return $?
else
echo "could not find docker image: $IMAGE_NAME" >&2
return 3
fi
}
# for debugging, start the docker image interactively instead of building
# starts immediately, does not require sourcing or RUN
if [[ $INTERACTIVE ]]; then
export BUILD_SCRIPT="-i"
export RUN_ARGS="$RUN_ARGS -it"
RUN
fi

35
.ci/download_openssl.sh Normal file
View File

@@ -0,0 +1,35 @@
#!/bin/bash
# Read arguments
while [[ $# != 0 ]]; do
case "$1" in
'--')
shift
;;
'--arch')
shift
if [[ $# == 0 ]]; then
echo "::error file=$0::--arch expects an argument"
exit 3
fi
OS_ARCH="$1"
shift
;;
*)
echo "::error file=$0::unrecognized option: $1"
exit 3
;;
esac
done
set -e
OPEN_SSL_VERSION="1.1.1n"
DEST_PATH="C:\OpenSSL-Win$OS_ARCH"
curl -JLSs "https://github.com/CristiFati/Prebuilt-Binaries/raw/master/OpenSSL/v1.1.1/OpenSSL-$OPEN_SSL_VERSION-Win-pc0$OS_ARCH.zip" -o OpenSSL.zip
unzip -q "OpenSSL.zip"
rm "OpenSSL.zip"
mv "OpenSSL\OpenSSL\\$OPEN_SSL_VERSION" "$DEST_PATH"
rm -r "OpenSSL"
echo "Installed OpenSSL v$OPEN_SSL_VERSION to $DEST_PATH"

View File

@@ -42,11 +42,11 @@ ${diff#*
Exiting...
EOM
exit 2
;;
exit 2
;;
0)
cat <<EOM
0)
cat <<EOM
***********************************************************
*** ***
@@ -58,12 +58,12 @@ EOM
Exiting...
EOM
exit 0
;;
exit 0
;;
*)
echo ""
echo "Something went wrong in our formatting checks: clangify returned $err" >&2
echo ""
;;
esac
*)
echo ""
echo "Something went wrong in our formatting checks: clangify returned $err" >&2
echo ""
;;
esac

View File

@@ -3,8 +3,8 @@
# renames the file to [original name][SUFFIX].[original extension]
# where SUFFIX is either available in the environment or as the first arg
# if MAKE_ZIP is set instead a zip is made
# expected to be run in the build directory
builddir="."
# expected to be run in the build directory unless BUILD_DIR is set
builddir="${BUILD_DIR:=.}"
findrx="Cockatrice-*.*"
if [[ $1 ]]; then
@@ -27,6 +27,7 @@ if [[ ! $file ]]; then
echo "::error file=$0::could not find package"
exit 1
fi
oldpwd="$PWD"
if ! cd "$path"; then
echo "::error file=$0::could not get file path"
exit 1
@@ -45,6 +46,9 @@ else
echo "renaming '$file' to '$filename'"
mv "$file" "$filename"
fi
ls -l "$PWD/$filename"
echo "::set-output name=path::$PWD/$filename"
cd "$oldpwd"
relative_path="$path/$filename"
ls -l "$relative_path"
echo "::set-output name=path::$relative_path"
echo "::set-output name=name::$filename"

View File

@@ -8,18 +8,20 @@ git push -d origin --REPLACE-WITH-BETA-LIST--
include different targets -->
<pre>
<b>Pre-compiled binaries we serve:</b>
- <kbd>Windows 7/8/10 (32-bit)</kbd></i>
- <kbd>Windows 7/8/10 (64-bit)</kbd></i>
- <kbd>macOS 10.14</kbd> ("Mojave")</i>
- <kbd>macOS 10.15</kbd> ("Catalina")</i>
- <kbd>macOS 11.0</kbd> ("Big Sur")</i>
- <kbd>Ubuntu 18.04</kbd> ("Bionic Beaver")</i>
- <kbd>Ubuntu 20.04</kbd> ("Focal Fossa")</i>
- <kbd>Ubuntu 20.10</kbd> ("Groovy Gorilla")</i>
- <kbd>Ubuntu 21.04</kbd> ("Hirsute Hippo")</i>
- <kbd>Debian 10</kbd> ("Buster")</i>
- <kbd>Fedora 33</kbd></i>
- <kbd>Fedora 34</kbd></i>
- <kbd>Windows 7/8/10/11 (32-bit)</kbd>
- <kbd>Windows 7/8/10/11 (64-bit)</kbd>
- <kbd>macOS 10.14</kbd> ("Mojave")
- <kbd>macOS 10.15</kbd> ("Catalina")
- <kbd>macOS 11.0</kbd> ("Big Sur")
- <kbd>Ubuntu 18.04</kbd> ("Bionic Beaver")
- <kbd>Ubuntu 20.04</kbd> ("Focal Fossa")
- <kbd>Ubuntu 21.10</kbd> ("Impish Indri")
- <kbd>Ubuntu 22.04</kbd> ("Jammy Jellyfish")
- <kbd>Debian 10</kbd> ("Buster")
- <kbd>Debian 11</kbd> ("Bullseye")
- <kbd>Fedora 34</kbd>
- <kbd>Fedora 35</kbd>
- <kbd>Fedora 36</kbd>
<kbd>We are also packaged in Arch Linux's official community repository, courtesy of @FFY00</kbd></i>
<kbd>General linux support is available via a flatpak package (Flathub)</kbd></i>
</pre>
@@ -44,7 +46,7 @@ If you'd like to help contribute to Cockatrice in any way, check out our [README
> ⚠️ **With this release, we no longer provide a ready-to-install binary for:**
> --DEPRECATED-OS-HERE--
-->
- Run the internal software updater: <kbd>Help → Check for Client Updates</kbd>
Don't forget to update your card database right after! (<kbd>Help → Check for Card Updates...</kbd>)

106
.cmake-format.json Normal file
View File

@@ -0,0 +1,106 @@
{
"format": {
"_help_line_width": [
"How wide to allow formatted cmake files"
],
"line_width": 120,
"_help_tab_size": [
"How many spaces to tab for indent"
],
"tab_size": 2,
"_help_max_subgroups_hwrap": [
"If an argument group contains more than this many sub-groups",
"(parg or kwarg groups) then force it to a vertical layout."
],
"max_subgroups_hwrap": 2,
"_help_max_pargs_hwrap": [
"If a positional argument group contains more than this many",
"arguments, then force it to a vertical layout."
],
"max_pargs_hwrap": 6,
"_help_max_rows_cmdline": [
"If a cmdline positional group consumes more than this many",
"lines without nesting, then invalidate the layout (and nest)"
],
"max_rows_cmdline": 5,
"_help_separate_ctrl_name_with_space": [
"If true, separate flow control names from their parentheses",
"with a space"
],
"separate_ctrl_name_with_space": false,
"_help_separate_fn_name_with_space": [
"If true, separate function names from parentheses with a",
"space"
],
"separate_fn_name_with_space": false,
"_help_dangle_parens": [
"If a statement is wrapped to more than one line, than dangle",
"the closing parenthesis on its own line."
],
"dangle_parens": true,
"_help_dangle_align": [
"If the trailing parenthesis must be 'dangled' on its on",
"line, then align it to this reference: `prefix`: the start",
"of the statement, `prefix-indent`: the start of the",
"statement, plus one indentation level, `child`: align to",
"the column of the arguments"
],
"dangle_align": "prefix",
"_help_min_prefix_chars": [
"If the statement spelling length (including space and",
"parenthesis) is smaller than this amount, then force reject",
"nested layouts."
],
"min_prefix_chars": 4,
"_help_max_prefix_chars": [
"If the statement spelling length (including space and",
"parenthesis) is larger than the tab width by more than this",
"amount, then force reject un-nested layouts."
],
"max_prefix_chars": 10,
"_help_max_lines_hwrap": [
"If a candidate layout is wrapped horizontally but it exceeds",
"this many lines, then reject the layout."
],
"max_lines_hwrap": 2,
"_help_line_ending": [
"What style line endings to use in the output."
],
"line_ending": "auto",
"_help_command_case": [
"Format command names consistently as 'lower' or 'upper' case"
],
"command_case": "lower",
"_help_keyword_case": [
"Format keywords consistently as 'lower' or 'upper' case"
],
"keyword_case": "upper",
"_help_always_wrap": [
"A list of command names which should always be wrapped"
],
"always_wrap": [],
"_help_enable_sort": [
"If true, the argument lists which are known to be sortable",
"will be sorted lexicographically"
],
"enable_sort": true,
"_help_autosort": [
"If true, the parsers may infer whether or not an argument",
"list is sortable (without annotation)."
],
"autosort": true,
"_help_require_valid_layout": [
"By default, if cmake-format cannot successfully fit",
"everything into the desired line-width it will apply the",
"last, most aggressive attempt that it made. If this flag is",
"True, however, cmake-format will print error, exit with non-",
"zero status code, and write-out nothing"
],
"require_valid_layout": false,
"_help_layout_passes": [
"A dictionary mapping layout nodes to a list of wrap",
"decisions. See the documentation for more information."
],
"layout_passes": {}
}
}

View File

@@ -290,7 +290,7 @@ be included in the next release 👍
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;
2. Every few days, a maintainer updates the `*_en@source.ts files` with the new strings;
3. Transifex picks up the new files from GitHub every 24 hours;
4. Translators translate the new untranslated strings on Transifex;
5. Before a release, a maintainer fetches the updated translations from Transifex.
@@ -344,14 +344,14 @@ make
If the parameter has been enabled correctly, when running "make" you should see
a line similar to this one (the numbers may vary):
```sh
[ 76%] Generating ../../cockatrice/translations/cockatrice_en.ts
Updating '../../cockatrice/translations/cockatrice_en.ts'...
[ 76%] Generating ../../cockatrice/translations/cockatrice_en@source.ts
Updating '../../cockatrice/translations/cockatrice_en@source.ts'...
Found 857 source text(s) (8 new and 849 already existing)
```
You should then notice that the following files have uncommitted changes:
cockatrice/translations/cockatrice_en.ts
oracle/translations/oracle_en.ts
cockatrice/translations/cockatrice_en@source.ts
oracle/translations/oracle_en@source.ts
It is recommended to disable the parameter afterwards using:
```sh

View File

@@ -1,4 +1,4 @@
name: Build
name: Build Desktop
on:
push:
@@ -7,21 +7,19 @@ on:
paths-ignore:
- '**.md'
- 'webclient/**'
- '.github/workflows/web-*.yml'
tags:
- '*'
pull_request:
branches:
- master
paths-ignore:
- '**.md'
- 'webclient/**'
- '.github/workflows/web-*.yml'
jobs:
configure:
name: Configure
runs-on: ubuntu-latest
outputs:
tag: ${{steps.configure.outputs.tag}}
sha: ${{steps.configure.outputs.sha}}
@@ -55,7 +53,7 @@ jobs:
with:
fetch-depth: 0
- name: Prepare release paramaters
- name: Prepare release parameters
id: prepare
if: steps.configure.outputs.tag != null
shell: bash
@@ -82,45 +80,52 @@ jobs:
matrix:
# these names correspond to the files in .ci/$distro
include:
- distro: UbuntuImpish
package: DEB
- distro: UbuntuHirsute
package: DEB
test: skip
- distro: UbuntuFocal
package: DEB
test: skip # UbuntuFocal has a broken qt for debug builds
- distro: UbuntuBionic
package: DEB
- distro: ArchLinux
package: skip # we are packaged in arch already
allow-failure: yes
- distro: DebianBuster
- distro: Debian10
package: DEB
test: skip # running tests on all distros is superfluous
- distro: Fedora35
package: RPM
- distro: Debian11
package: DEB
- distro: Fedora34
package: RPM
test: skip # gtest does not compile for some reason
- distro: Fedora35
package: RPM
test: skip
- distro: Fedora36
package: RPM
- distro: UbuntuBionic
package: DEB
- distro: UbuntuFocal
package: DEB
test: skip # UbuntuFocal has a broken qt for debug builds
- distro: UbuntuImpish
package: DEB
test: skip
- distro: UbuntuJammy
package: DEB
name: ${{matrix.distro}}
needs: configure
runs-on: ubuntu-latest
continue-on-error: ${{matrix.allow-failure == 'yes'}}
env:
NAME: ${{matrix.distro}}
CACHE: /tmp/${{matrix.distro}}-cache # ${{runner.temp}} does not work?
# cache size over the entire repo is 10Gi link:
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
CCACHE_SIZE: 200M
steps:
- name: Checkout
@@ -148,9 +153,11 @@ jobs:
- name: Build debug and test
if: matrix.test != 'skip'
shell: bash
env:
distro: '${{matrix.distro}}'
run: |
source .ci/docker.sh
RUN --server --debug --test
RUN --server --debug --test --ccache "$CCACHE_SIZE" --parallel 2
- name: Build release package
id: package
@@ -159,16 +166,18 @@ jobs:
env:
suffix: '-${{matrix.distro}}'
type: '${{matrix.package}}'
distro: '${{matrix.distro}}'
run: |
source .ci/docker.sh
RUN --server --release --package "$type" --suffix "$suffix"
RUN --server --release --package "$type" --suffix "$suffix" \
--ccache "$CCACHE_SIZE" --parallel 2
- name: Upload artifact
if: matrix.package != 'skip'
uses: actions/upload-artifact@v2
with:
name: ${{matrix.distro}}-package
path: ./build/${{steps.package.outputs.name}}
path: ${{steps.package.outputs.path}}
if-no-files-found: error
- name: Upload to release
@@ -178,7 +187,7 @@ jobs:
GITHUB_TOKEN: ${{github.token}}
with:
upload_url: ${{needs.configure.outputs.upload_url}}
asset_path: ./build/${{steps.package.outputs.name}}
asset_path: ${{steps.package.outputs.path}}
asset_name: ${{steps.package.outputs.name}}
asset_content_type: application/octet-stream
@@ -186,50 +195,51 @@ jobs:
strategy:
fail-fast: false
matrix:
target:
- Debug
- 10.14_Mojave
- 10.15_Catalina
- 11_Big_Sur
include:
- target: Debug # tests only
os: macos-latest
xcode: 12.1
xcode: 12.5.1
qt_version: 6
type: Debug
do_tests: 0 # tests do not work yet on mac
make_package: false
do_tests: 1
- target: 10.14_Mojave
os: macos-10.15 # runs on Catalina
xcode: 10.3 # allows compatibility with macOS 10.14
qt_version: 5
type: Release
do_tests: 0
make_package: true
# do_tests: 1 # tests do not work on qt5?
make_package: 1
- target: 10.15_Catalina
os: macos-10.15
xcode: 12.1
xcode: 12.4
qt_version: 6
type: Release
do_tests: 0
make_package: true
do_tests: 1
make_package: 1
- target: 11_Big_Sur
os: macos-11
xcode: 12.5.1
xcode: 13.2
qt_version: 6
type: Release
do_tests: 0
make_package: true
do_tests: 1
make_package: 1
# - target: 12_Monterey
# os: macos-12
# xcode: 13.3
# qt_version: 6
# type: Release
# do_tests: 1
# make_package: 1
name: macOS ${{matrix.target}}
needs: configure
runs-on: ${{matrix.os}}
continue-on-error: ${{matrix.allow-failure == 'yes'}}
env:
CCACHE_DIR: ~/.ccache
DEVELOPER_DIR:
/Applications/Xcode_${{matrix.xcode}}.app/Contents/Developer
@@ -241,60 +251,32 @@ jobs:
shell: bash
# cmake cannot find the mysql connector
# neither of these works: mariadb-connector-c mysql-connector-c++
run: brew install ccache protobuf
- name: Install QT using homebrew
id: brew_install_qt
continue-on-error: true
shell: bash
run: brew install qt@5 --force-bottle
- name: Install QT using actions
if: steps.brew_install_qt.outcome != 'success'
uses: jurplel/install-qt-action@v2
- name: Get ccache timestamp
id: ccache_timestamp
shell: bash
run: echo "::set-output name=timestamp::$(date -u '+%Y%m%d%H%M%S')"
- name: Restore ccache cache
uses: actions/cache@v2
env:
timestamp: ${{steps.ccache_timestamp.outputs.timestamp}}
with:
path: ${{env.CCACHE_DIR}}
key: ${{runner.os}}-xcode-${{matrix.xcode}}-ccache-${{env.timestamp}}
restore-keys: |
${{runner.os}}-xcode-${{matrix.xcode}}-ccache-
qt_version: 'qt@${{matrix.qt_version}}'
run: |
brew update
brew install protobuf
brew install "$qt_version" --force-bottle
- name: Build on Xcode ${{matrix.xcode}}
shell: bash
id: build
env:
CMAKE_BUILD_PARALLEL_LEVEL: 3 # mac machines actually have 3 cores
run: .ci/compile.sh ${{matrix.type}} --server
- name: Test
if: matrix.do_tests == 1
shell: bash
working-directory: build
run: cmake --build . --target test
- name: Package for ${{matrix.target}}
id: package
if: matrix.make_package
shell: bash
working-directory: build
run: |
cmake --build . --target package
../.ci/name_build.sh "-macOS-${{matrix.target}}"
BUILDTYPE: '${{matrix.type}}'
MAKE_TEST: '${{matrix.do_tests}}'
MAKE_PACKAGE: '${{matrix.make_package}}'
PACKAGE_SUFFIX: '-macOS-${{matrix.target}}'
# set QTDIR to find qt5, qt6 can be found without this
QTDIR: '/usr/local/opt/qt5'
# Mac machines actually have 3 cores
run: .ci/compile.sh --server --parallel 3
- name: Upload artifact
if: matrix.make_package
uses: actions/upload-artifact@v2
with:
name: macOS-${{matrix.target}}-xcode-${{matrix.xcode}}-dmg
path: ${{steps.package.outputs.path}}
name: macOS-${{matrix.target}}-dmg
path: ${{steps.build.outputs.path}}
if-no-files-found: error
- name: Upload to release
@@ -304,96 +286,90 @@ jobs:
GITHUB_TOKEN: ${{github.token}}
with:
upload_url: ${{needs.configure.outputs.upload_url}}
asset_path: ${{steps.package.outputs.path}}
asset_name: ${{steps.package.outputs.name}}
asset_path: ${{steps.build.outputs.path}}
asset_name: ${{steps.build.outputs.name}}
asset_content_type: application/octet-stream
build-windows:
strategy:
fail-fast: false
matrix:
arch:
- 64
- 32
include:
- arch: 64
triplet: x64
cmake: x64
append: _64
- arch: 32
triplet: x86
cmake: Win32
name: Windows ${{matrix.arch}}
vcpkg_default_triplet: x86
qt_version: '5.15.2'
cmake_generator_platform: Win32
qt_arch: msvc2019
- arch: 64
vcpkg_default_triplet: x64
qt_version: '6.3.0'
cmake_generator_platform: x64
qt_arch: msvc2019_64
qt_modules: "qt5compat qtmultimedia qtwebsockets"
name: Windows (${{matrix.arch}}-bit)
needs: configure
runs-on: windows-latest
runs-on: windows-2019
env:
QT_VERSION: '5.15.2'
QT_ARCH: msvc2019${{matrix.append}}
CMAKE_GENERATOR: 'Visual Studio 16 2019'
steps:
- name: Add msbuild to PATH
id: add-msbuild
uses: microsoft/setup-msbuild@v1.0.2
uses: microsoft/setup-msbuild@v1.1
- name: Checkout
uses: actions/checkout@v2
uses: actions/checkout@v3
with:
submodules: recursive
- name: Restore Qt ${{env.QT_VERSION}} ${{matrix.arch}}-bit from cache
- name: Restore Qt ${{matrix.qt_version}} (${{matrix.arch}}-bit) from cache
id: cache-qt
uses: actions/cache@v2
uses: actions/cache@v1 # Intentionally v1, based on jurplel documentation
with:
key: ${{runner.os}}-QtCache-${{env.QT_VERSION}}-${{matrix.arch}}
path: ${{runner.workspace}}/Qt
key: ${{runner.os}}-QtCache-${{matrix.qt_version}}-${{matrix.arch}}
path: '${{github.workspace}}/../Qt'
- name: Install ${{matrix.arch}}-bit Qt
uses: jurplel/install-qt-action@v2
- name: Install Qt ${{matrix.qt_version}} (${{matrix.arch}}-bit)
uses: jurplel/install-qt-action@v3
with:
cached: ${{steps.cache-qt.outputs.cache-hit}}
version: ${{env.QT_VERSION}}
arch: win${{matrix.arch}}_${{env.QT_ARCH}}
version: ${{matrix.qt_version}}
arch: win${{matrix.arch}}_${{matrix.qt_arch}}
modules: ${{matrix.qt_modules}}
- name: Restore or setup vcpkg
uses: lukka/run-vcpkg@v6
- name: Run vcpkg
uses: lukka/run-vcpkg@v10.2
with:
vcpkgArguments: '@${{github.workspace}}/vcpkg.txt'
vcpkgDirectory: ${{github.workspace}}/vcpkg
appendedCacheKey: ${{hashFiles('**/vcpkg.txt')}}
vcpkgTriplet: ${{matrix.triplet}}-windows
runVcpkgInstall: true
appendedCacheKey: ${{matrix.arch}}-bit
env:
VCPKG_DEFAULT_TRIPLET: '${{matrix.vcpkg_default_triplet}}-windows'
VCPKG_DISABLE_METRICS: 1
- name: Configure Cockatrice ${{matrix.arch}}-bit
- name: Install OpenSSL (${{matrix.arch}}-bit)
shell: bash
run: |
mkdir -p build
cd build
export QTDIR="${{runner.workspace}}/Qt/${{env.QT_VERSION}}/${{env.QT_ARCH}}"
cmake .. -G "${{env.CMAKE_GENERATOR}}" -A "${{matrix.cmake}}" -DCMAKE_BUILD_TYPE="Release" -DWITH_SERVER=1 -DTEST=1
run: .ci/download_openssl.sh --arch ${{matrix.arch}}
- name: Build Cockatrice ${{matrix.arch}}-bit
id: package
- name: Build Cockatrice (${{matrix.arch}}-bit)
id: build
shell: bash
working-directory: build
run: |
cmake --build . --target package --config Release
../.ci/name_build.sh "-win${{matrix.arch}}"
env:
PACKAGE_SUFFIX: '-win${{matrix.arch}}'
CMAKE_GENERATOR: '${{env.CMAKE_GENERATOR}}'
CMAKE_GENERATOR_PLATFORM: '${{matrix.cmake_generator_platform}}'
QTDIR: '${{github.workspace}}\Qt\${{matrix.qt_version}}\win${{matrix.arch}}_${{matrix.qt_arch}}'
run: .ci/compile.sh --server --release --test --package --parallel 2
- name: Run tests
shell: bash
working-directory: build
run: ctest -T Test -C Release
- name: Setup tmate session
if: ${{ failure() }}
uses: mxschmitt/action-tmate@v3
- name: Upload artifact
uses: actions/upload-artifact@v2
uses: actions/upload-artifact@v3
with:
name: Windows-${{matrix.arch}}bit-installer
path: ./build/${{steps.package.outputs.name}}
path: ${{steps.build.outputs.path}}
if-no-files-found: error
- name: Upload to release
@@ -403,6 +379,6 @@ jobs:
GITHUB_TOKEN: ${{github.token}}
with:
upload_url: ${{needs.configure.outputs.upload_url}}
asset_path: ./build/${{steps.package.outputs.name}}
asset_name: ${{steps.package.outputs.name}}
asset_path: ${{steps.build.outputs.path}}
asset_name: ${{steps.build.outputs.name}}
asset_content_type: application/octet-stream

View File

@@ -2,11 +2,10 @@ name: Code Style (C++)
on:
pull_request:
branches:
- master
paths-ignore:
- '**.md'
- 'webclient/**'
- '.github/workflows/web-*.yml'
jobs:
clang-format:

66
.github/workflows/translations.yml vendored Normal file
View File

@@ -0,0 +1,66 @@
name: Update translation source
on:
workflow_dispatch:
schedule:
# runs once per month
- cron: '0 0 1 * *'
jobs:
translations:
# Do not run the scheduled workflow on forks
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
runs-on: ubuntu-latest
steps:
- name: Install lupdate
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends qttools5-dev-tools
- name: Checkout repo
uses: actions/checkout@v2
- name: Update cockatrice translations
shell: bash
run: |
shopt -s globstar # globstar is needed for recursive **
lupdate -version
echo "reading the following source files:"
# note: there are three strings to translate in common right now
echo {cockatrice,common}/**/*.{cpp,h}
echo "$(echo {cockatrice,common}/**/*.{cpp,h} | wc -w) files total"
lupdate {cockatrice,common}/**/*.{cpp,h} -ts cockatrice/translations/cockatrice_en@source.ts
- name: Update oracle translations
shell: bash
run: |
shopt -s globstar # globstar is needed for recursive **
lupdate -version
echo "reading the following source files:"
echo oracle/**/*.{cpp,h}
echo "$(echo oracle/**/*.{cpp,h} | wc -w) files total"
lupdate oracle/**/*.{cpp,h} -ts oracle/translations/oracle_en@source.ts
- name: Check for updates
id: check
shell: bash
run: |
set +e # do not fail, just save the exit state
git diff --exit-code
echo "::set-output name=deploy::$?"
- name: Commit changes
if: steps.check.outputs.deploy == '1'
shell: bash
working-directory: ${{env.OUTPUT_PATH}}
run: |
git config user.name github-actions
git config user.email github-actions@github.com
git add cockatrice/translations/cockatrice_en@source.ts oracle/translations/oracle_en@source.ts
git commit -m "Automated translation update ( $GITHUB_SHA )"
git push
deploy_commit=$(git rev-parse HEAD)
echo "Created commit: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/commit/$deploy_commit"

53
.github/workflows/web-build.yml vendored Normal file
View File

@@ -0,0 +1,53 @@
name: Build Web
on:
push:
branches:
- master
paths:
- '.github/workflows/web-*.yml'
- 'webclient/**'
- '!**.md'
pull_request:
paths:
- '.github/workflows/web-*.yml'
- 'webclient/**'
- '!**.md'
jobs:
build-web:
name: React (Node ${{matrix.node_version}})
runs-on: ubuntu-latest
defaults:
run:
working-directory: webclient
strategy:
fail-fast: false
matrix:
node_version:
- 12
- lts/*
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
node-version: ${{matrix.node_version}}
cache: 'npm'
cache-dependency-path: 'webclient/package-lock.json'
- name: Install dependencies
run: npm clean-install
- name: Build app
run: npm run build
- name: Test app
run: npm run test

32
.github/workflows/web-lint.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: Code Style (TypeScript)
on:
pull_request:
paths:
- '.github/workflows/web-*.yml'
- 'webclient/**'
- '!**.md'
jobs:
ESLint:
runs-on: ubuntu-latest
defaults:
run:
working-directory: webclient
steps:
- name: Checkout
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2
with:
cache: 'npm'
cache-dependency-path: 'webclient/package-lock.json'
- name: Install ESLint
run: npm clean-install --ignore-scripts
- name: Run ESLint
run: npm run lint

3
.gitignore vendored
View File

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

7
.husky/pre-commit Executable file
View File

@@ -0,0 +1,7 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
cd webclient
npm run translate
git add src/i18n-default.json

View File

@@ -1,13 +1,13 @@
[main]
host = https://www.transifex.com
[cockatrice.cockatrice]
[cockatrice.cockatrice-translations-cockatrice-en-source-ts--master]
file_filter = cockatrice/translations/cockatrice_<lang>.ts
source_file = cockatrice/translations/cockatrice_en.ts
source_file = cockatrice/translations/cockatrice_en@source.ts
source_lang = en
[cockatrice.oracle]
[cockatrice.oracle-translations-oracle-en-source-ts--master]
file_filter = oracle/translations/oracle_<lang>.ts
source_file = oracle/translations/oracle_en.ts
source_file = oracle/translations/oracle_en@source.ts
source_lang = en

View File

@@ -5,9 +5,26 @@
# This file sets all the variables shared between the projects
# like the installation path, compilation flags etc..
# Cmake 3.1 is required to enable C++11 support correctly
# cmake 3.16 is required if using qt6
cmake_minimum_required(VERSION 3.10)
# Early detect ccache
option(USE_CCACHE "Cache the build results with ccache" ON)
# Treat warnings as errors (Debug builds only)
option(WARNING_AS_ERROR "Treat warnings as errors in debug builds" ON)
# Check for translation updates
option(UPDATE_TRANSLATIONS "Update translations on compile" OFF)
# Compile servatrice
option(WITH_SERVER "build servatrice" OFF)
# Compile cockatrice
option(WITH_CLIENT "build cockatrice" ON)
# Compile oracle
option(WITH_ORACLE "build oracle" ON)
# Compile dbconverter
option(WITH_DBCONVERTER "build dbconverter" ON)
# Compile tests
option(TEST "build tests" OFF)
# Default to "Release" build type
# User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call
IF(DEFINED CMAKE_BUILD_TYPE)
@@ -16,8 +33,6 @@ ELSE()
SET(CMAKE_BUILD_TYPE Release CACHE STRING "Type of build")
ENDIF()
# Early detect ccache
OPTION(USE_CCACHE "Cache the build results with ccache" ON)
if(USE_CCACHE)
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM)
@@ -41,22 +56,23 @@ endif()
# A project name is needed for CPack
# Version can be overriden by git tags, see cmake/getversion.cmake
PROJECT("Cockatrice" VERSION 2.8.1)
project("Cockatrice" VERSION 2.8.1)
# Set release name if not provided via env/cmake var
if(NOT DEFINED GIT_TAG_RELEASENAME)
set(GIT_TAG_RELEASENAME "Prismatic Bridge")
endif()
# Use c++11 for all targets
set(CMAKE_CXX_STANDARD 11 CACHE STRING "C++ ISO Standard")
# Use c++17 for all targets
set(CMAKE_CXX_STANDARD 17 CACHE STRING "C++ ISO Standard")
set(CMAKE_CXX_STANDARD_REQUIRED True)
# Set conventional loops
set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
# Search path for cmake modules
SET(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake)
set(COCKATRICE_CMAKE_PATH "${PROJECT_SOURCE_DIR}/cmake")
list(INSERT CMAKE_MODULE_PATH 0 "${COCKATRICE_CMAKE_PATH}")
include(getversion)
@@ -76,8 +92,8 @@ if(UNIX)
if(RULE_LAUNCH_COMPILE)
MESSAGE(STATUS "Force enabling CCache usage under macOS")
# Set up wrapper scripts
configure_file(${CMAKE_MODULE_PATH}/launch-c.in launch-c)
configure_file(${CMAKE_MODULE_PATH}/launch-cxx.in launch-cxx)
configure_file("${COCKATRICE_CMAKE_PATH}/launch-c.in" launch-c)
configure_file("${COCKATRICE_CMAKE_PATH}/launch-cxx.in" launch-cxx)
execute_process(COMMAND chmod a+rx
"${CMAKE_BINARY_DIR}/launch-c"
"${CMAKE_BINARY_DIR}/launch-cxx")
@@ -103,13 +119,10 @@ elseif(WIN32)
set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/rundir/${CMAKE_BUILD_TYPE})
endif()
# Treat warnings as errors (Debug builds only)
option(WARNING_AS_ERROR "Treat warnings as errors in debug builds" ON)
# Define proper compilation flags
IF(MSVC)
# Visual Studio: Maximum optimization, disable warning C4251
set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251 ")
# Visual Studio: Maximum optimization, disable warning C4251, establish C++17 compatibility
SET(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD /wd4251 /Zc:__cplusplus /std:c++17 /permissive-")
# Generate complete debugging information
#set(CMAKE_CXX_FLAGS_DEBUG "/Zi")
ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
@@ -123,6 +136,10 @@ ELSEIF (CMAKE_COMPILER_IS_GNUCXX)
set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -Wall -Wextra")
endif()
IF(APPLE)
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++17")
ENDIF()
set(ADDITIONAL_DEBUG_FLAGS -Wcast-align -Wmissing-declarations -Wno-long-long -Wno-error=extra -Wno-error=delete-non-virtual-dtor -Wno-error=sign-compare -Wno-error=missing-declarations)
FOREACH(FLAG ${ADDITIONAL_DEBUG_FLAGS})
@@ -148,7 +165,7 @@ ENDIF()
FIND_PACKAGE(Threads REQUIRED)
# Find Qt5
# Determine 32 or 64 bit build
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
set(_lib_suffix 64)
else()
@@ -165,28 +182,9 @@ elseif(DEFINED ENV{QTDIR})
list(APPEND CMAKE_PREFIX_PATH "$ENV{QTDIR}")
endif()
FIND_PACKAGE(Qt5Core 5.5.0 REQUIRED)
MESSAGE(STATUS "Update Translations: ${UPDATE_TRANSLATIONS}")
IF(Qt5Core_FOUND)
MESSAGE(STATUS "Found Qt ${Qt5Core_VERSION_STRING}")
# FIX: Qt was built with -reduce-relocations
if (Qt5_POSITION_INDEPENDENT_CODE)
SET(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
# guess plugins and libraries directory
set(QT_PLUGINS_DIR "${Qt5Core_DIR}/../../../plugins")
get_target_property(QT_LIBRARY_DIR Qt5::Core LOCATION)
get_filename_component(QT_LIBRARY_DIR ${QT_LIBRARY_DIR} PATH)
ELSE()
MESSAGE(FATAL_ERROR "No Qt5 found!")
ENDIF()
# Check for translation updates
OPTION(UPDATE_TRANSLATIONS "Update translations on compile" OFF)
MESSAGE(STATUS "UPDATE TRANSLATIONS: ${UPDATE_TRANSLATIONS}")
include(FindQtRuntime)
set(CMAKE_AUTOMOC TRUE)
@@ -195,7 +193,7 @@ FIND_PACKAGE(Protobuf REQUIRED)
IF(NOT EXISTS "${Protobuf_PROTOC_EXECUTABLE}")
MESSAGE(FATAL_ERROR "No protoc command found!")
ELSE()
MESSAGE(STATUS "Protoc version ${Protobuf_VERSION} found!")
MESSAGE(STATUS "Found Protobuf ${Protobuf_VERSION} at: ${Protobuf_LIBRARIES}")
ENDIF()
#Find OpenSSL
@@ -209,8 +207,8 @@ IF(MSVC)
ENDIF()
# Package builder
set(CPACK_PACKAGE_CONTACT "Zach Halpern <zahalpern+github@gmail.com>")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY ${PROJECT_NAME})
set(CPACK_PACKAGE_CONTACT "Zach Halpern <zach@cockatrice.us>")
set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_NAME}")
set(CPACK_PACKAGE_VENDOR "Cockatrice Development Team")
set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.md")
set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE")
@@ -231,15 +229,33 @@ if(UNIX)
# linux
IF(CPACK_GENERATOR STREQUAL "RPM")
set(CPACK_RPM_PACKAGE_LICENSE "GPLv2")
set(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt5-qttools, qt5-qtsvg, qt5-qtmultimedia")
set(CPACK_RPM_MAIN_COMPONENT "cockatrice")
IF(Qt6_FOUND)
SET(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt6-qttools, qt6-qtsvg, qt6-qtmultimedia")
ELSEIF(Qt5_FOUND)
SET(CPACK_RPM_PACKAGE_REQUIRES "protobuf, qt5-qttools, qt5-qtsvg, qt5-qtmultimedia")
ENDIF()
set(CPACK_RPM_PACKAGE_GROUP "Amusements/Games")
set(CPACK_RPM_PACKAGE_URL "http://github.com/Cockatrice/Cockatrice")
# stop directories from making package conflicts
set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION
/usr/share/applications
/usr/share/icons
/usr/share/icons/hicolor
/usr/share/icons/hicolor/48x48
/usr/share/icons/hicolor/48x48/apps
/usr/share/icons/hicolor/scalable
/usr/share/icons/hicolor/scalable/apps)
ELSE()
set(CPACK_GENERATOR DEB)
set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON)
set(CPACK_DEBIAN_PACKAGE_SECTION "games")
set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://github.com/Cockatrice/Cockatrice")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5")
IF(Qt6_FOUND)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins")
ELSEIF(Qt5_FOUND)
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5")
ENDIF()
ENDIF()
endif()
elseif(WIN32)
@@ -252,8 +268,8 @@ elseif(WIN32)
# Configure file with custom definitions for NSIS.
configure_file(
${CMAKE_MODULE_PATH}/NSIS.definitions.nsh.in
${PROJECT_BINARY_DIR}/NSIS.definitions.nsh
"${COCKATRICE_CMAKE_PATH}/NSIS.definitions.nsh.in"
"${PROJECT_BINARY_DIR}/NSIS.definitions.nsh"
)
# include vcredist into the package; NSIS will take care of running it
@@ -264,38 +280,33 @@ endif()
include(CPack)
# Compile servatrice (default off)
option(WITH_SERVER "build servatrice" OFF)
add_subdirectory(common)
if(WITH_SERVER)
add_subdirectory(servatrice)
SET(CPACK_INSTALL_CMAKE_PROJECTS "Servatrice;Servatrice;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
endif()
# Compile cockatrice (default on)
option(WITH_CLIENT "build cockatrice" ON)
if(WITH_CLIENT)
add_subdirectory(cockatrice)
SET(CPACK_INSTALL_CMAKE_PROJECTS "Cockatrice;Cockatrice;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
endif()
# Compile oracle (default on)
option(WITH_ORACLE "build oracle" ON)
if(WITH_ORACLE)
add_subdirectory(oracle)
SET(CPACK_INSTALL_CMAKE_PROJECTS "Oracle;Oracle;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
endif()
# Compile dbconverter (default on)
option(WITH_DBCONVERTER "build dbconverter" ON)
if(WITH_DBCONVERTER)
add_subdirectory(dbconverter)
SET(CPACK_INSTALL_CMAKE_PROJECTS "Dbconverter;Dbconverter;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
endif()
# Compile tests (default off)
option(TEST "build tests" OFF)
if(TEST)
include(CTest)
add_subdirectory(tests)
endif()
if(Qt6Found AND Qt6_VERSION_MINOR GREATER_EQUAL 3)
# Qt6.3+ requires project finalization to support translations
qt6_finalize_project()
endif()

View File

@@ -8,7 +8,7 @@
<a href="#get-involved--">Get Involved</a> <b>|</b>
<a href="#community-resources">Community</a> <b>|</b>
<a href="#translations-">Translations</a> <b>|</b>
<a href="#build-">Build</a> <b>|</b>
<a href="#build--">Build</a> <b>|</b>
<a href="#run">Run</a> <b>|</b>
<a href="#license-">License</a>
</p>
@@ -78,7 +78,7 @@ Cockatrice uses Transifex for translations. You can help us bring Cockatrice and
Check out our [Translator FAQ](https://github.com/Cockatrice/Cockatrice/wiki/Translation-FAQ) for more information about contributing!<br>
# Build [![CI Builds](https://github.com/Cockatrice/Cockatrice/actions/workflows/ci-builds.yml/badge.svg?branch=master&event=push)](https://github.com/Cockatrice/Cockatrice/actions/workflows/ci-builds.yml?query=branch%3Amaster+event%3Apush)
# Build [![CI Desktop](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml/badge.svg?branch=master&event=push)](https://github.com/Cockatrice/Cockatrice/actions/workflows/desktop-build.yml?query=branch%3Amaster+event%3Apush) [![CI Web](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml/badge.svg?branch=master&event=push)](https://github.com/Cockatrice/Cockatrice/actions/workflows/web-build.yml?query=branch%3Amaster+event%3Apush)
**Detailed compiling instructions can be found on the Cockatrice wiki under [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)**
@@ -117,6 +117,7 @@ The following flags can be passed to `cmake`:
- `-DWARNING_AS_ERROR=0` Whether to treat compilation warnings as errors in debug mode (default 1 = yes).
- `-DUPDATE_TRANSLATIONS=1` Configure `make` to update the translation .ts files for new strings in the source code. Note: Running `make clean` will remove the .ts files (default 0 = no).
- `-DTEST=1` Enable regression tests (default 0 = no). Note: needs googletest, will be downloaded on the fly if unavailable. To run tests: ```make test```.
- `-DFORCE_USE_QT5=1` Skip looking for Qt6 before trying to find Qt5
# Run

View File

@@ -1,7 +1,7 @@
#!/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.
# Never, ever, should this receive a path with a newline in it. Don't bother proofing it for that.
# go to the project root directory, this file should be located in the project root directory

View File

@@ -1,18 +1,18 @@
# Find the LibExecinfo library - FreeBSD only
FIND_PATH(LIBEXECINFO_INCLUDE_DIR execinfo.h)
FIND_LIBRARY(LIBEXECINFO_LIBRARY NAMES execinfo)
find_path(LIBEXECINFO_INCLUDE_DIR execinfo.h)
find_library(LIBEXECINFO_LIBRARY NAMES execinfo)
IF(LIBEXECINFO_INCLUDE_DIR AND LIBEXECINFO_LIBRARY)
SET(LIBEXECINFO_FOUND TRUE)
ENDIF()
if(LIBEXECINFO_INCLUDE_DIR AND LIBEXECINFO_LIBRARY)
set(LIBEXECINFO_FOUND TRUE)
endif()
IF(LIBEXECINFO_FOUND)
IF(NOT LIBEXECINFO_FIND_QUIETLY)
MESSAGE(STATUS "Found LibExecinfo: ${EXECINFO_LIBRARY}")
ENDIF()
ELSE()
IF(LIBEXECINFO_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find LibExecinfo")
ENDIF()
ENDIF()
if(LIBEXECINFO_FOUND)
if(NOT LIBEXECINFO_FIND_QUIETLY)
message(STATUS "Found LibExecinfo: ${EXECINFO_LIBRARY}")
endif()
else()
if(LIBEXECINFO_FIND_REQUIRED)
message(FATAL_ERROR "Could not find LibExecinfo")
endif()
endif()

119
cmake/FindQtRuntime.cmake Normal file
View File

@@ -0,0 +1,119 @@
# Find a compatible Qt version Inputs: WITH_SERVER, WITH_CLIENT, WITH_ORACLE, WITH_DBCONVERTER, FORCE_USE_QT5 Optional
# Input: QT6_DIR -- Hint as to where Qt6 lives on the system Optional Input: QT5_DIR -- Hint as to where Qt5 lives on
# the system Output: COCKATRICE_QT_VERSION_NAME -- Example values: Qt5, Qt6 Outputs: SERVATRICE_QT_MODULES,
# COCKATRICE_QT_MODULES, ORACLE_QT_MODULES, DBCONVERTER_QT_MODULES, TEST_QT_MODULES
set(REQUIRED_QT_COMPONENTS Core)
if(WITH_SERVER)
set(_SERVATRICE_NEEDED Network Sql WebSockets)
endif()
if(WITH_CLIENT)
set(_COCKATRICE_NEEDED
Concurrent
Gui
Multimedia
Network
PrintSupport
Svg
Widgets
WebSockets
)
endif()
if(WITH_ORACLE)
set(_ORACLE_NEEDED Concurrent Network Svg Widgets)
endif()
if(WITH_DBCONVERTER)
set(_DBCONVERTER_NEEDED Network Widgets)
endif()
if(TEST)
set(_TEST_NEEDED Widgets)
endif()
set(REQUIRED_QT_COMPONENTS ${REQUIRED_QT_COMPONENTS} ${_SERVATRICE_NEEDED} ${_COCKATRICE_NEEDED} ${_ORACLE_NEEDED}
${_DBCONVERTER_NEEDED} ${_TEST_NEEDED}
)
list(REMOVE_DUPLICATES REQUIRED_QT_COMPONENTS)
if(NOT FORCE_USE_QT5)
# Core5Compat is Qt6 Only, Linguist is now a component in Qt6 instead of an external package
find_package(
Qt6 6.2.3
COMPONENTS Core5Compat ${REQUIRED_QT_COMPONENTS}
OPTIONAL_COMPONENTS Linguist
QUIET HINTS ${Qt6_DIR}
)
endif()
if(Qt6_FOUND)
set(COCKATRICE_QT_VERSION_NAME Qt6)
if(Qt6LinguistTools_FOUND)
list(FIND Qt6LinguistTools_TARGETS Qt6::lrelease QT6_LRELEASE_INDEX)
if(QT6_LRELEASE_INDEX EQUAL -1)
message(WARNING "Qt6 lrelease not found.")
endif()
list(FIND Qt6LinguistTools_TARGETS Qt6::lupdate QT6_LUPDATE_INDEX)
if(QT6_LUPDATE_INDEX EQUAL -1)
message(WARNING "Qt6 lupdate not found.")
endif()
endif()
else()
find_package(
Qt5 5.8.0
COMPONENTS ${REQUIRED_QT_COMPONENTS}
QUIET HINTS ${Qt5_DIR}
)
if(Qt5_FOUND)
set(COCKATRICE_QT_VERSION_NAME Qt5)
else()
message(FATAL_ERROR "No suitable version of Qt was found")
endif()
# Qt5 Linguist is in a separate package
find_package(Qt5LinguistTools QUIET)
if(Qt5LinguistTools_FOUND)
if(NOT Qt5_LRELEASE_EXECUTABLE)
message(WARNING "Qt5 lrelease not found.")
endif()
if(NOT Qt5_LUPDATE_EXECUTABLE)
message(WARNING "Qt5 lupdate not found.")
endif()
else()
message(WARNING "Linguist Tools not found, cannot handle translations")
endif()
endif()
if(Qt5_POSITION_INDEPENDENT_CODE OR Qt6_FOUND)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()
# Establish Qt Plugins directory & Library directories
get_target_property(QT_LIBRARY_DIR ${COCKATRICE_QT_VERSION_NAME}::Core LOCATION)
get_filename_component(QT_LIBRARY_DIR ${QT_LIBRARY_DIR} DIRECTORY)
if(Qt6_FOUND)
get_filename_component(QT_PLUGINS_DIR "${Qt6Core_DIR}/../../../${QT6_INSTALL_PLUGINS}" ABSOLUTE)
get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/../../.." ABSOLUTE)
if(UNIX AND APPLE)
# Mac needs a bit more help finding all necessary components
list(APPEND QT_LIBRARY_DIR "/usr/local/lib")
endif()
elseif(Qt5_FOUND)
get_filename_component(QT_PLUGINS_DIR "${Qt5Core_DIR}/../../../plugins" ABSOLUTE)
get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/.." ABSOLUTE)
endif()
message(DEBUG "QT_PLUGINS_DIR = ${QT_PLUGINS_DIR}")
message(DEBUG "QT_LIBRARY_DIR = ${QT_LIBRARY_DIR}")
# Establish exports
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" SERVATRICE_QT_MODULES "${_SERVATRICE_NEEDED}")
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" COCKATRICE_QT_MODULES "${_COCKATRICE_NEEDED}")
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" ORACLE_QT_MODULES "${_ORACLE_NEEDED}")
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" DB_CONVERTER_QT_MODULES "${_DBCONVERTER_NEEDED}")
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" TEST_QT_MODULES "${_TEST_NEEDED}")
if(Qt6_FOUND)
list(APPEND SERVATRICE_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Core5Compat)
list(APPEND COCKATRICE_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Core5Compat)
list(APPEND ORACLE_QT_MODULES ${COCKATRICE_QT_VERSION_NAME}::Core5Compat)
endif()
message(STATUS "Found Qt ${${COCKATRICE_QT_VERSION_NAME}_VERSION} at: ${${COCKATRICE_QT_VERSION_NAME}_DIR}")

View File

@@ -1,36 +1,38 @@
# Find the MS Visual Studio VC redistributable package
if (WIN32)
set(VCREDISTRUNTIME_FOUND "NO")
if(WIN32)
set(VCREDISTRUNTIME_FOUND "NO")
if(CMAKE_SIZEOF_VOID_P EQUAL 8) # 64-bit
set(REDIST_ARCH x64)
else()
set(REDIST_ARCH x86)
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()
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()
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()

View File

@@ -1,77 +1,70 @@
# Find the OpenSSL runtime libraries (.dll) for Windows that
# will be needed by Qt in order to access https urls.
# Find the OpenSSL runtime libraries (.dll) for Windows that will be needed by Qt in order to access https urls.
if(NOT DEFINED WIN32 OR NOT ${WIN32})
message(STATUS "Non-Windows device trying to execute FindWin32SslRuntime, skipping")
return()
endif()
if (WIN32)
# Get standard installation paths for OpenSSL under Windows
# http://www.slproweb.com/products/Win32OpenSSL.html
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
# target win64
set(_OPENSSL_ROOT_HINTS
${OPENSSL_ROOT_DIR}
"[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\OpenSSL (64-bit)_is1;Inno Setup: App Path]"
ENV OPENSSL_ROOT_DIR
)
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
if("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "x64")
message(STATUS "Looking for OpenSSL for ${CMAKE_GENERATOR_PLATFORM}")
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
set(_OPENSSL_ROOT_PATHS "$ENV{VCPKG_PACKAGES_DIR}/x64-windows/bin" "C:/OpenSSL-Win64/bin" "C:/OpenSSL-Win64"
"C:/Tools/vcpkg/installed/x64-windows/bin" "${_programfiles}/OpenSSL-Win64"
)
unset(_programfiles)
elseif("${CMAKE_GENERATOR_PLATFORM}" STREQUAL "Win32")
message(STATUS "Looking for OpenSSL for ${CMAKE_GENERATOR_PLATFORM}")
file(TO_CMAKE_PATH "$ENV{PROGRAMFILES}" _programfiles)
set(_OPENSSL_ROOT_PATHS
"$ENV{VCPKG_PACKAGES_DIR}/x86-windows/bin"
"C:/OpenSSL-Win32/bin"
"C:/OpenSSL-Win32"
"C:/OpenSSL"
"C:/Tools/vcpkg/installed/x86-windows/bin"
"${_programfiles}/OpenSSL"
"${_programfiles}/OpenSSL-Win32"
"C:/OpenSSL/"
"C:/OpenSSL-Win32/"
)
unset(_programfiles)
endif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
else ()
set(_OPENSSL_ROOT_HINTS
${OPENSSL_ROOT_DIR}
ENV OPENSSL_ROOT_DIR
)
endif ()
set(_OPENSSL_ROOT_HINTS_AND_PATHS
HINTS ${_OPENSSL_ROOT_HINTS}
PATHS ${_OPENSSL_ROOT_PATHS}
)
# For OpenSSL < 1.1, they are named libeay32 and ssleay32 and even if the dll is 64bit, it's still suffixed as *32.dll
# For OpenSSL >= 1.1, they are named libcrypto and libssl with no suffix
if( CMAKE_SIZEOF_VOID_P EQUAL 8 )
# target win64
FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libcrypto-1_1-x64.dll libcrypto.dll libeay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES libssl-1_1-x64.dll libssl.dll ssleay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
else( CMAKE_SIZEOF_VOID_P EQUAL 8 )
# target win32
FIND_FILE(WIN32SSLRUNTIME_LIBEAY NAMES libcrypto-1_1.dll libcrypto.dll libeay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
FIND_FILE(WIN32SSLRUNTIME_SSLEAY NAMES libssl-1_1.dll libssl.dll ssleay32.dll ${_OPENSSL_ROOT_HINTS_AND_PATHS})
endif( CMAKE_SIZEOF_VOID_P EQUAL 8 )
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
)
unset(_programfiles)
endif()
message(STATUS "Looking for OpenSSL @ $ENV{CMAKE_GENERATOR_PLATFORM} in ${_OPENSSL_ROOT_PATHS}")
if("$ENV{CMAKE_GENERATOR_PLATFORM}" STREQUAL "x64")
find_file(
WIN32SSLRUNTIME_LIBEAY
NAMES libcrypto-1_1-x64.dll libcrypto.dll
PATHS ${_OPENSSL_ROOT_PATHS}
NO_DEFAULT_PATH
)
find_file(
WIN32SSLRUNTIME_SSLEAY
NAMES libssl-1_1-x64.dll libssl.dll
PATHS ${_OPENSSL_ROOT_PATHS}
NO_DEFAULT_PATH
)
elseif("$ENV{CMAKE_GENERATOR_PLATFORM}" STREQUAL "Win32")
find_file(
WIN32SSLRUNTIME_LIBEAY
NAMES libcrypto-1_1.dll libcrypto.dll
PATHS ${_OPENSSL_ROOT_PATHS}
NO_DEFAULT_PATH
)
find_file(
WIN32SSLRUNTIME_SSLEAY
NAMES libssl-1_1.dll libssl.dll
PATHS ${_OPENSSL_ROOT_PATHS}
NO_DEFAULT_PATH
)
endif()
if(WIN32SSLRUNTIME_LIBEAY AND WIN32SSLRUNTIME_SSLEAY)
set(WIN32SSLRUNTIME_LIBRARIES "${WIN32SSLRUNTIME_LIBEAY}" "${WIN32SSLRUNTIME_SSLEAY}")
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)

View File

@@ -1,21 +1,24 @@
set(VERSION_STRING_CPP "${PROJECT_BINARY_DIR}/version_string.cpp")
set(VERSION_STRING_H "${PROJECT_BINARY_DIR}/version_string.h")
INCLUDE_DIRECTORIES(${PROJECT_BINARY_DIR})
include_directories(${PROJECT_BINARY_DIR})
set( hstring "extern const char *VERSION_STRING\;
set(hstring
"extern const char *VERSION_STRING\;
extern const char *VERSION_COMMIT\;
extern const char *VERSION_DATE\;\n" )
set( cppstring "const char *VERSION_STRING = \"${PROJECT_VERSION_FRIENDLY}\"\;
extern const char *VERSION_DATE\;\n"
)
set(cppstring
"const char *VERSION_STRING = \"${PROJECT_VERSION_FRIENDLY}\"\;
const char *VERSION_COMMIT = \"${GIT_COMMIT_ID}\"\;
const char *VERSION_DATE = \"${GIT_COMMIT_DATE_FRIENDLY}\"\;\n")
file(WRITE ${PROJECT_BINARY_DIR}/version_string.cpp.txt ${cppstring} )
file(WRITE ${PROJECT_BINARY_DIR}/version_string.h.txt ${hstring} )
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_BINARY_DIR}/version_string.h.txt ${VERSION_STRING_H}
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_BINARY_DIR}/version_string.cpp.txt ${VERSION_STRING_CPP}
const char *VERSION_DATE = \"${GIT_COMMIT_DATE_FRIENDLY}\"\;\n"
)
file(WRITE ${PROJECT_BINARY_DIR}/version_string.cpp.txt ${cppstring})
file(WRITE ${PROJECT_BINARY_DIR}/version_string.h.txt ${hstring})
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_BINARY_DIR}/version_string.h.txt ${VERSION_STRING_H}
)
execute_process(
COMMAND ${CMAKE_COMMAND} -E copy_if_different ${PROJECT_BINARY_DIR}/version_string.cpp.txt ${VERSION_STRING_CPP}
)

View File

@@ -1,154 +1,183 @@
# HELPER FUNCTIONS
function(get_commit_id)
# get last commit hash
execute_process(
COMMAND ${GIT_EXECUTABLE} log -1 --abbrev=7 --date=short "--pretty=%h"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE res_var
OUTPUT_VARIABLE GIT_COM_ID
)
if(NOT ${res_var} EQUAL 0)
message(WARNING "Git failed (not a repo, or no tags). Build will not contain git revision info.")
return()
endif()
# get last commit hash
execute_process(
COMMAND ${GIT_EXECUTABLE} log -1 --abbrev=7 --date=short "--pretty=%h"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE res_var
OUTPUT_VARIABLE GIT_COM_ID
)
if(NOT ${res_var} EQUAL 0)
message(WARNING "Git failed (not a repo, or no tags). Build will not contain git revision info.")
return()
endif()
string(REPLACE "\n" "" GIT_COM_ID "${GIT_COM_ID}")
set(GIT_COMMIT_ID "${GIT_COM_ID}" PARENT_SCOPE)
set(PROJECT_VERSION_LABEL "custom(${GIT_COM_ID})" PARENT_SCOPE)
string(REPLACE "\n" "" GIT_COM_ID "${GIT_COM_ID}")
set(GIT_COMMIT_ID
"${GIT_COM_ID}"
PARENT_SCOPE
)
set(PROJECT_VERSION_LABEL
"custom(${GIT_COM_ID})"
PARENT_SCOPE
)
endfunction()
function(get_commit_date)
# get last commit date
execute_process(
COMMAND ${GIT_EXECUTABLE} log -1 --date=short "--pretty=%cd"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE res_var
OUTPUT_VARIABLE GIT_COM_DATE
)
if(NOT ${res_var} EQUAL 0)
message(WARNING "Git failed (not a repo, or no tags). Build will not contain git revision info.")
return()
endif()
# get last commit date
execute_process(
COMMAND ${GIT_EXECUTABLE} log -1 --date=short "--pretty=%cd"
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE res_var
OUTPUT_VARIABLE GIT_COM_DATE
)
if(NOT ${res_var} EQUAL 0)
message(WARNING "Git failed (not a repo, or no tags). Build will not contain git revision info.")
return()
endif()
string(REPLACE "\n" "" GIT_COM_DATE "${GIT_COM_DATE}")
set(GIT_COMMIT_DATE_FRIENDLY "${GIT_COM_DATE}" PARENT_SCOPE)
string(REPLACE "\n" "" GIT_COM_DATE "${GIT_COM_DATE}")
set(GIT_COMMIT_DATE_FRIENDLY
"${GIT_COM_DATE}"
PARENT_SCOPE
)
string(REPLACE "-" "" GIT_COM_DATE "${GIT_COM_DATE}")
set(GIT_COMMIT_DATE "${GIT_COM_DATE}" PARENT_SCOPE)
string(REPLACE "-" "" GIT_COM_DATE "${GIT_COM_DATE}")
set(GIT_COMMIT_DATE
"${GIT_COM_DATE}"
PARENT_SCOPE
)
endfunction()
function(get_tag_name commit)
if(${commit} STREQUAL "unknown")
return()
endif()
if(${commit} STREQUAL "unknown")
return()
endif()
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --exact-match --tags ${commit}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE res_var
OUTPUT_VARIABLE GIT_TAG
ERROR_VARIABLE GIT_TAG_ERR
)
execute_process(
COMMAND ${GIT_EXECUTABLE} describe --exact-match --tags ${commit}
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
RESULT_VARIABLE res_var
OUTPUT_VARIABLE GIT_TAG
ERROR_VARIABLE GIT_TAG_ERR
)
if((NOT ${res_var} EQUAL 0) OR (${GIT_TAG_ERR} MATCHES "fatal: no tag exactly matches.*"))
message(STATUS "Commit is not a release or prerelease (no git tag found)")
return()
endif()
if((NOT ${res_var} EQUAL 0) OR (${GIT_TAG_ERR} MATCHES "fatal: no tag exactly matches.*"))
message(STATUS "Commit is not a release or prerelease (no git tag found)")
return()
endif()
string(REPLACE "\n" "" GIT_TAG "${GIT_TAG}")
message(STATUS "Commit is a release or prerelease, git tag: ${GIT_TAG}")
string(REPLACE "\n" "" GIT_TAG "${GIT_TAG}")
message(STATUS "Commit is a release or prerelease, git tag: ${GIT_TAG}")
# Extract information from tag:
# YYYY-MM-DD-Release-MAJ.MIN.PATCH
# YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X
string(REPLACE "-" ";" GIT_TAG_EXPLODED "${GIT_TAG}")
string(REPLACE "." ";" GIT_TAG_EXPLODED "${GIT_TAG_EXPLODED}")
# Extract information from tag: YYYY-MM-DD-Release-MAJ.MIN.PATCH YYYY-MM-DD-Development-MAJ.MIN.PATCH-beta.X
string(REPLACE "-" ";" GIT_TAG_EXPLODED "${GIT_TAG}")
string(REPLACE "." ";" GIT_TAG_EXPLODED "${GIT_TAG_EXPLODED}")
# Sanity checks: length
list(LENGTH GIT_TAG_EXPLODED GIT_TAG_LISTCOUNT)
if(${GIT_TAG_LISTCOUNT} LESS 7 OR ${GIT_TAG_LISTCOUNT} GREATER 9)
message(WARNING "Invalid tag format, got ${GIT_TAG_LISTCOUNT} tokens")
return()
endif()
# Sanity checks: length
list(LENGTH GIT_TAG_EXPLODED GIT_TAG_LISTCOUNT)
if(${GIT_TAG_LISTCOUNT} LESS 7 OR ${GIT_TAG_LISTCOUNT} GREATER 9)
message(WARNING "Invalid tag format, got ${GIT_TAG_LISTCOUNT} tokens")
return()
endif()
# Year
list(GET GIT_TAG_EXPLODED 0 GIT_TAG_YEAR)
if(${GIT_TAG_YEAR} LESS 2017 OR ${GIT_TAG_LISTCOUNT} GREATER 2100)
message(WARNING "Invalid tag year ${GIT_TAG_YEAR}")
return()
endif()
# Year
list(GET GIT_TAG_EXPLODED 0 GIT_TAG_YEAR)
if(${GIT_TAG_YEAR} LESS 2017 OR ${GIT_TAG_LISTCOUNT} GREATER 2100)
message(WARNING "Invalid tag year ${GIT_TAG_YEAR}")
return()
endif()
# Month
list(GET GIT_TAG_EXPLODED 1 GIT_TAG_MONTH)
if(${GIT_TAG_MONTH} LESS 1 OR ${GIT_TAG_MONTH} GREATER 12)
message(WARNING "Invalid tag month ${GIT_TAG_MONTH}")
return()
endif()
# Month
list(GET GIT_TAG_EXPLODED 1 GIT_TAG_MONTH)
if(${GIT_TAG_MONTH} LESS 1 OR ${GIT_TAG_MONTH} GREATER 12)
message(WARNING "Invalid tag month ${GIT_TAG_MONTH}")
return()
endif()
# Day
list(GET GIT_TAG_EXPLODED 2 GIT_TAG_DAY)
if(${GIT_TAG_DAY} LESS 1 OR ${GIT_TAG_DAY} GREATER 31)
message(WARNING "Invalid tag day ${GIT_TAG_DAY}")
return()
endif()
# Day
list(GET GIT_TAG_EXPLODED 2 GIT_TAG_DAY)
if(${GIT_TAG_DAY} LESS 1 OR ${GIT_TAG_DAY} GREATER 31)
message(WARNING "Invalid tag day ${GIT_TAG_DAY}")
return()
endif()
# Type
list(GET GIT_TAG_EXPLODED 3 GIT_TAG_TYPE)
if(NOT(${GIT_TAG_TYPE} STREQUAL "Release" OR ${GIT_TAG_TYPE} STREQUAL "Development"))
message(WARNING "Invalid tag type ${GIT_TAG_TYPE}")
return()
endif()
# Type
list(GET GIT_TAG_EXPLODED 3 GIT_TAG_TYPE)
if(NOT (${GIT_TAG_TYPE} STREQUAL "Release" OR ${GIT_TAG_TYPE} STREQUAL "Development"))
message(WARNING "Invalid tag type ${GIT_TAG_TYPE}")
return()
endif()
# Major
list(GET GIT_TAG_EXPLODED 4 GIT_TAG_MAJOR)
if(${GIT_TAG_MAJOR} LESS 0 OR ${GIT_TAG_MAJOR} GREATER 99)
message(WARNING "Invalid tag major version ${GIT_TAG_MAJOR}")
return()
endif()
# Major
list(GET GIT_TAG_EXPLODED 4 GIT_TAG_MAJOR)
if(${GIT_TAG_MAJOR} LESS 0 OR ${GIT_TAG_MAJOR} GREATER 99)
message(WARNING "Invalid tag major version ${GIT_TAG_MAJOR}")
return()
endif()
# Minor
list(GET GIT_TAG_EXPLODED 5 GIT_TAG_MINOR)
if(${GIT_TAG_MINOR} LESS 0 OR ${GIT_TAG_MINOR} GREATER 99)
message(WARNING "Invalid tag minor version ${GIT_TAG_MINOR}")
return()
endif()
# Minor
list(GET GIT_TAG_EXPLODED 5 GIT_TAG_MINOR)
if(${GIT_TAG_MINOR} LESS 0 OR ${GIT_TAG_MINOR} GREATER 99)
message(WARNING "Invalid tag minor version ${GIT_TAG_MINOR}")
return()
endif()
# Patch
list(GET GIT_TAG_EXPLODED 6 GIT_TAG_PATCH)
if(${GIT_TAG_PATCH} LESS 0 OR ${GIT_TAG_PATCH} GREATER 99)
message(WARNING "Invalid tag patch version ${GIT_TAG_PATCH}")
return()
endif()
# Patch
list(GET GIT_TAG_EXPLODED 6 GIT_TAG_PATCH)
if(${GIT_TAG_PATCH} LESS 0 OR ${GIT_TAG_PATCH} GREATER 99)
message(WARNING "Invalid tag patch version ${GIT_TAG_PATCH}")
return()
endif()
# Label
# 7 = Stable release
# 8 = Dev release, first beta so only "beta" attached
# 9 = Dev release, subsequent beta so "beta.N" attached (N>=2)
if(${GIT_TAG_LISTCOUNT} EQUAL 8)
list(GET GIT_TAG_EXPLODED 7 GIT_TAG_LABEL)
elseif(${GIT_TAG_LISTCOUNT} EQUAL 9)
list(GET GIT_TAG_EXPLODED 7 GIT_TAG_LABEL)
list(GET GIT_TAG_EXPLODED 8 GIT_TAG_LABEL_NUM)
set(GIT_TAG_LABEL ${GIT_TAG_LABEL} ${GIT_TAG_LABEL_NUM})
string(REPLACE ";" "." GIT_TAG_LABEL "${GIT_TAG_LABEL}")
else()
SET(GIT_TAG_LABEL "")
endif()
# Label 7 = Stable release 8 = Dev release, first beta so only "beta" attached 9 = Dev release, subsequent beta so
# "beta.N" attached (N>=2)
if(${GIT_TAG_LISTCOUNT} EQUAL 8)
list(GET GIT_TAG_EXPLODED 7 GIT_TAG_LABEL)
elseif(${GIT_TAG_LISTCOUNT} EQUAL 9)
list(GET GIT_TAG_EXPLODED 7 GIT_TAG_LABEL)
list(GET GIT_TAG_EXPLODED 8 GIT_TAG_LABEL_NUM)
set(GIT_TAG_LABEL ${GIT_TAG_LABEL} ${GIT_TAG_LABEL_NUM})
string(REPLACE ";" "." GIT_TAG_LABEL "${GIT_TAG_LABEL}")
else()
set(GIT_TAG_LABEL "")
endif()
# Override hardcoded version with the informations from the tag
set(PROJECT_VERSION_MAJOR ${GIT_TAG_MAJOR} PARENT_SCOPE)
set(PROJECT_VERSION_MINOR ${GIT_TAG_MINOR} PARENT_SCOPE)
set(PROJECT_VERSION_PATCH ${GIT_TAG_PATCH} PARENT_SCOPE)
set(PROJECT_VERSION_LABEL ${GIT_TAG_LABEL} PARENT_SCOPE)
# Override hardcoded version with the informations from the tag
set(PROJECT_VERSION_MAJOR
${GIT_TAG_MAJOR}
PARENT_SCOPE
)
set(PROJECT_VERSION_MINOR
${GIT_TAG_MINOR}
PARENT_SCOPE
)
set(PROJECT_VERSION_PATCH
${GIT_TAG_PATCH}
PARENT_SCOPE
)
set(PROJECT_VERSION_LABEL
${GIT_TAG_LABEL}
PARENT_SCOPE
)
if(${GIT_TAG_TYPE} STREQUAL "Development")
set(PROJECT_VERSION_LABEL ${GIT_TAG_LABEL} PARENT_SCOPE)
elseif(${GIT_TAG_TYPE} STREQUAL "Release")
set(PROJECT_VERSION_LABEL "" PARENT_SCOPE)
# set release name from env var
set(PROJECT_VERSION_RELEASENAME "${GIT_TAG_RELEASENAME}" PARENT_SCOPE)
endif()
if(${GIT_TAG_TYPE} STREQUAL "Development")
set(PROJECT_VERSION_LABEL
${GIT_TAG_LABEL}
PARENT_SCOPE
)
elseif(${GIT_TAG_TYPE} STREQUAL "Release")
set(PROJECT_VERSION_LABEL
""
PARENT_SCOPE
)
# set release name from env var
set(PROJECT_VERSION_RELEASENAME
"${GIT_TAG_RELEASENAME}"
PARENT_SCOPE
)
endif()
endfunction()
@@ -163,16 +192,16 @@ set(PROJECT_VERSION_RELEASENAME "")
find_package(Git)
if(GIT_FOUND)
get_commit_id()
get_commit_date()
get_tag_name(${GIT_COMMIT_ID})
get_commit_id()
get_commit_date()
get_tag_name(${GIT_COMMIT_ID})
else()
message( WARNING "Git not found. Build will not contain git revision info." )
message(WARNING "Git not found. Build will not contain git revision info.")
endif()
set(PROJECT_VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
if(PROJECT_VERSION_LABEL)
set(PROJECT_VERSION "${PROJECT_VERSION}-${PROJECT_VERSION_LABEL}")
set(PROJECT_VERSION "${PROJECT_VERSION}-${PROJECT_VERSION_LABEL}")
endif()
set(PROJECT_VERSION_FRIENDLY "${PROJECT_VERSION} (${GIT_COMMIT_DATE_FRIENDLY})")
@@ -180,7 +209,7 @@ set(PROJECT_VERSION_FRIENDLY "${PROJECT_VERSION} (${GIT_COMMIT_DATE_FRIENDLY})")
# Format: <program name>[-ReleaseName]-MAJ.MIN.PATCH[-prerelease_label]
set(PROJECT_VERSION_FILENAME "${PROJECT_NAME}")
if(PROJECT_VERSION_RELEASENAME)
set(PROJECT_VERSION_FILENAME "${PROJECT_VERSION_FILENAME}-${PROJECT_VERSION_RELEASENAME}")
set(PROJECT_VERSION_FILENAME "${PROJECT_VERSION_FILENAME}-${PROJECT_VERSION_RELEASENAME}")
endif()
set(PROJECT_VERSION_FILENAME "${PROJECT_VERSION_FILENAME}-${PROJECT_VERSION}")

14
cmakeify.sh Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
# 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.
# CMake-Format
cmake_format_cmd="cmake-format"
if ! hash $cmake_format_cmd 2>/dev/null; then
echo "could not find $cmake_format_cmd, skipping" >&2
return
fi
$cmake_format_cmd -i cmake/*.cmake */CMakeLists.txt CMakeLists.txt

View File

@@ -2,284 +2,391 @@
#
# provides the cockatrice binary
PROJECT(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
project(Cockatrice VERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH}")
SET(cockatrice_SOURCES
set(cockatrice_SOURCES
src/abstractcarddragitem.cpp
src/abstractcarditem.cpp
src/abstractclient.cpp
src/abstractcounter.cpp
src/abstractgraphicsitem.cpp
src/arrowitem.cpp
src/arrowtarget.cpp
src/carddatabase.cpp
src/carddatabasemodel.cpp
src/carddbparser/carddatabaseparser.cpp
src/carddbparser/cockatricexml3.cpp
src/carddbparser/cockatricexml4.cpp
src/carddragitem.cpp
src/cardfilter.cpp
src/cardframe.cpp
src/cardinfopicture.cpp
src/cardinfotext.cpp
src/cardinfowidget.cpp
src/carditem.cpp
src/cardlist.cpp
src/cardzone.cpp
src/chatview/chatview.cpp
src/counter_general.cpp
src/dlg_creategame.cpp
src/dlg_filter_games.cpp
src/customlineedit.cpp
src/deck_loader.cpp
src/decklistmodel.cpp
src/deckstats_interface.cpp
src/deckview.cpp
src/dlg_connect.cpp
src/dlg_create_token.cpp
src/dlg_creategame.cpp
src/dlg_edit_avatar.cpp
src/dlg_edit_password.cpp
src/dlg_edit_tokens.cpp
src/dlg_edit_user.cpp
src/dlg_filter_games.cpp
src/dlg_forgotpasswordchallenge.cpp
src/dlg_forgotpasswordrequest.cpp
src/dlg_forgotpasswordreset.cpp
src/dlg_forgotpasswordchallenge.cpp
src/dlg_manage_sets.cpp
src/dlg_register.cpp
src/dlg_tip_of_the_day.cpp
src/tip_of_the_day.cpp
src/dlg_update.cpp
src/dlg_viewlog.cpp
src/abstractclient.cpp
src/remoteclient.cpp
src/main.cpp
src/window_main.cpp
src/gamesmodel.cpp
src/player.cpp
src/playertarget.cpp
src/cardzone.cpp
src/selectzone.cpp
src/cardlist.cpp
src/abstractcarditem.cpp
src/carditem.cpp
src/tablezone.cpp
src/handzone.cpp
src/handcounter.cpp
src/carddatabase.cpp
src/keysignals.cpp
src/gameview.cpp
src/gameselector.cpp
src/decklistmodel.cpp
src/deck_loader.cpp
src/dlg_load_deck_from_clipboard.cpp
src/dlg_load_remote_deck.cpp
src/cardinfowidget.cpp
src/cardframe.cpp
src/cardinfopicture.cpp
src/cardinfotext.cpp
src/filterbuilder.cpp
src/cardfilter.cpp
src/filtertreemodel.cpp
src/filtertree.cpp
src/messagelogwidget.cpp
src/zoneviewzone.cpp
src/zoneviewwidget.cpp
src/pilezone.cpp
src/stackzone.cpp
src/carddragitem.cpp
src/carddatabasemodel.cpp
src/setsmodel.cpp
src/abstractgraphicsitem.cpp
src/abstractcarddragitem.cpp
src/dlg_manage_sets.cpp
src/dlg_register.cpp
src/dlg_settings.cpp
src/phasestoolbar.cpp
src/dlg_tip_of_the_day.cpp
src/dlg_update.cpp
src/dlg_viewlog.cpp
src/filter_string.cpp
src/filterbuilder.cpp
src/filtertree.cpp
src/filtertreemodel.cpp
src/gamescene.cpp
src/arrowitem.cpp
src/arrowtarget.cpp
src/tab.cpp
src/tab_server.cpp
src/tab_room.cpp
src/tab_message.cpp
src/tab_game.cpp
src/tab_deck_storage.cpp
src/tab_replays.cpp
src/tab_supervisor.cpp
src/tab_admin.cpp
src/tab_account.cpp
src/tab_deck_editor.cpp
src/tab_logs.cpp
src/replay_timeline_widget.cpp
src/deckstats_interface.cpp
src/tappedout_interface.cpp
src/chatview/chatview.cpp
src/userlist.cpp
src/userinfobox.cpp
src/user_context_menu.cpp
src/remotedecklist_treewidget.cpp
src/remotereplaylist_treewidget.cpp
src/deckview.cpp
src/playerlistwidget.cpp
src/pixmapgenerator.cpp
src/settingscache.cpp
src/thememanager.cpp
src/gameselector.cpp
src/gamesmodel.cpp
src/gameview.cpp
src/gettextwithmax.cpp
src/handcounter.cpp
src/handle_public_servers.cpp
src/handzone.cpp
src/keysignals.cpp
src/lineeditcompleter.cpp
src/localclient.cpp
src/localserver.cpp
src/localserverinterface.cpp
src/localclient.cpp
src/soundengine.cpp
src/logger.cpp
src/main.cpp
src/messagelogwidget.cpp
src/pending_command.cpp
src/phase.cpp
src/phasestoolbar.cpp
src/pictureloader.cpp
src/shortcutssettings.cpp
src/pilezone.cpp
src/pixmapgenerator.cpp
src/player.cpp
src/playerlistwidget.cpp
src/playertarget.cpp
src/releasechannel.cpp
src/remoteclient.cpp
src/remotedecklist_treewidget.cpp
src/remotereplaylist_treewidget.cpp
src/replay_timeline_widget.cpp
src/selectzone.cpp
src/sequenceEdit/sequenceedit.cpp
src/lineeditcompleter.cpp
src/settings/settingsmanager.cpp
src/setsmodel.cpp
src/settings/carddatabasesettings.cpp
src/settings/serverssettings.cpp
src/settings/messagesettings.cpp
src/settings/downloadsettings.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/settings/messagesettings.cpp
src/settings/serverssettings.cpp
src/settings/settingsmanager.cpp
src/settingscache.cpp
src/shortcutssettings.cpp
src/soundengine.cpp
src/spoilerbackgroundupdater.cpp
src/handle_public_servers.cpp
src/carddbparser/carddatabaseparser.cpp
src/carddbparser/cockatricexml3.cpp
src/carddbparser/cockatricexml4.cpp
src/filter_string.cpp
src/phase.cpp
src/customlineedit.cpp
src/stackzone.cpp
src/tab.cpp
src/tab_account.cpp
src/tab_admin.cpp
src/tab_deck_editor.cpp
src/tab_deck_storage.cpp
src/tab_game.cpp
src/tab_logs.cpp
src/tab_message.cpp
src/tab_replays.cpp
src/tab_room.cpp
src/tab_server.cpp
src/tab_supervisor.cpp
src/tablezone.cpp
src/tappedout_interface.cpp
src/thememanager.cpp
src/tip_of_the_day.cpp
src/translatecountername.cpp
src/update_downloader.cpp
src/user_context_menu.cpp
src/userconnection_information.cpp
src/userinfobox.cpp
src/userlist.cpp
src/window_main.cpp
src/zoneviewwidget.cpp
src/zoneviewzone.cpp
${VERSION_STRING_CPP}
)
)
add_subdirectory(sounds)
add_subdirectory(themes)
set(cockatrice_RESOURCES cockatrice.qrc)
IF(UPDATE_TRANSLATIONS)
FILE(GLOB_RECURSE translate_cockatrice_SRCS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp ${CMAKE_SOURCE_DIR}/cockatrice/src/*.h)
FILE(GLOB_RECURSE translate_common_SRCS ${CMAKE_SOURCE_DIR}/common/*.cpp ${CMAKE_SOURCE_DIR}/common/*.h)
SET(translate_SRCS ${translate_cockatrice_SRCS} ${translate_common_SRCS})
SET(cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/cockatrice_en.ts")
ELSE()
FILE(GLOB cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts")
ENDIF(UPDATE_TRANSLATIONS)
if(UPDATE_TRANSLATIONS)
file(GLOB_RECURSE translate_cockatrice_SRCS ${CMAKE_SOURCE_DIR}/cockatrice/src/*.cpp
${CMAKE_SOURCE_DIR}/cockatrice/src/*.h
)
file(GLOB_RECURSE translate_common_SRCS ${CMAKE_SOURCE_DIR}/common/*.cpp ${CMAKE_SOURCE_DIR}/common/*.h)
set(translate_SRCS ${translate_cockatrice_SRCS} ${translate_common_SRCS})
set(cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/cockatrice_en@source.ts")
else()
file(GLOB cockatrice_TS "${CMAKE_CURRENT_SOURCE_DIR}/translations/*.ts")
endif(UPDATE_TRANSLATIONS)
if(WIN32)
set(cockatrice_SOURCES ${cockatrice_SOURCES} cockatrice.rc)
set(cockatrice_SOURCES ${cockatrice_SOURCES} cockatrice.rc)
endif(WIN32)
if(APPLE)
set(MACOSX_BUNDLE_ICON_FILE appicon.icns)
set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns)
ENDIF(APPLE)
set(MACOSX_BUNDLE_ICON_FILE appicon.icns)
set_source_files_properties(
${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns PROPERTIES MACOSX_PACKAGE_LOCATION Resources
)
set(cockatrice_SOURCES ${cockatrice_SOURCES} ${CMAKE_CURRENT_SOURCE_DIR}/resources/appicon.icns)
endif(APPLE)
# Qt5
find_package(Qt5 COMPONENTS Concurrent Multimedia Network PrintSupport Svg WebSockets Widgets REQUIRED)
set(COCKATRICE_QT_MODULES Qt5::Concurrent Qt5::Multimedia Qt5::Network Qt5::PrintSupport Qt5::Svg Qt5::Widgets Qt5::WebSockets)
# Qt5LinguistTools
find_package(Qt5LinguistTools)
if(Qt5LinguistTools_FOUND)
list(APPEND COCKATRICE_LIBS Qt5::LinguistTools)
if(NOT Qt5_LRELEASE_EXECUTABLE)
MESSAGE(WARNING "Qt's lrelease not found.")
endif()
if(UPDATE_TRANSLATIONS)
if(NOT Qt5_LUPDATE_EXECUTABLE)
MESSAGE(WARNING "Qt's lupdate not found.")
endif()
QT5_CREATE_TRANSLATION(cockatrice_QM ${translate_SRCS} ${cockatrice_TS})
else()
QT5_ADD_TRANSLATION(cockatrice_QM ${cockatrice_TS})
endif()
if(Qt6_FOUND)
qt6_add_resources(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES})
elseif(Qt5_FOUND)
qt5_add_resources(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES})
endif()
QT5_ADD_RESOURCES(cockatrice_RESOURCES_RCC ${cockatrice_RESOURCES})
# Declare path variables
set(ICONDIR share/icons CACHE STRING "icon dir")
set(DESKTOPDIR share/applications CACHE STRING "desktop file destination")
set(ICONDIR
share/icons
CACHE STRING "icon dir"
)
set(DESKTOPDIR
share/applications
CACHE STRING "desktop file destination"
)
# Include directories
INCLUDE_DIRECTORIES(../common)
INCLUDE_DIRECTORIES(${PROTOBUF_INCLUDE_DIR})
INCLUDE_DIRECTORIES(${CMAKE_BINARY_DIR}/common)
INCLUDE_DIRECTORIES(${CMAKE_CURRENT_BINARY_DIR})
include_directories(../common)
include_directories(${PROTOBUF_INCLUDE_DIR})
include_directories(${CMAKE_BINARY_DIR}/common)
include_directories(${CMAKE_CURRENT_BINARY_DIR})
# Build cockatrice binary and link it
ADD_EXECUTABLE(cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_SOURCES} ${cockatrice_QM} ${cockatrice_RESOURCES_RCC} ${cockatrice_MOC_SRCS})
set(COCKATRICE_MAC_QM_INSTALL_DIR "cockatrice.app/Contents/Resources/translations")
set(COCKATRICE_UNIX_QM_INSTALL_DIR "share/cockatrice/translations")
set(COCKATRICE_WIN32_QM_INSTALL_DIR "translations")
TARGET_LINK_LIBRARIES(cockatrice cockatrice_common ${COCKATRICE_QT_MODULES})
if(Qt6_FOUND)
qt6_add_executable(
cockatrice
WIN32
MACOSX_BUNDLE
${cockatrice_SOURCES}
${cockatrice_RESOURCES_RCC}
${cockatrice_MOC_SRCS}
MANUAL_FINALIZATION
)
elseif(Qt5_FOUND)
# Qt5 Translations need to be linked at executable creation time
if(Qt5LinguistTools_FOUND)
if(UPDATE_TRANSLATIONS)
qt5_create_translation(cockatrice_QM ${translate_SRCS} ${cockatrice_TS})
else()
qt5_add_translation(cockatrice_QM ${cockatrice_TS})
endif()
endif()
add_executable(
cockatrice WIN32 MACOSX_BUNDLE ${cockatrice_MOC_SRCS} ${cockatrice_QM} ${cockatrice_RESOURCES_RCC}
${cockatrice_SOURCES}
)
if(UNIX)
if(APPLE)
install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_MAC_QM_INSTALL_DIR})
else()
install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_UNIX_QM_INSTALL_DIR})
endif()
elseif(WIN32)
install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_WIN32_QM_INSTALL_DIR})
endif()
endif()
if(Qt5_FOUND)
target_link_libraries(cockatrice cockatrice_common ${COCKATRICE_QT_MODULES})
else()
target_link_libraries(cockatrice PUBLIC cockatrice_common ${COCKATRICE_QT_MODULES})
endif()
if(UNIX)
if(APPLE)
set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.cockatrice.${PROJECT_NAME}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME}-${PROJECT_VERSION}")
set(MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION})
set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION})
if(APPLE)
set(MACOSX_BUNDLE_INFO_STRING "${PROJECT_NAME}")
set(MACOSX_BUNDLE_GUI_IDENTIFIER "com.cockatrice.${PROJECT_NAME}")
set(MACOSX_BUNDLE_LONG_VERSION_STRING "${PROJECT_NAME}-${PROJECT_VERSION}")
set(MACOSX_BUNDLE_BUNDLE_NAME "${PROJECT_NAME}")
set(MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION})
set(MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION})
set_target_properties(cockatrice PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/Info.plist)
set_target_properties(cockatrice PROPERTIES MACOSX_BUNDLE_INFO_PLIST ${CMAKE_SOURCE_DIR}/cmake/Info.plist)
INSTALL(TARGETS cockatrice BUNDLE DESTINATION ./)
INSTALL(FILES ${cockatrice_QM} DESTINATION ./cockatrice.app/Contents/Resources/translations)
else()
# Assume linux
INSTALL(TARGETS cockatrice RUNTIME DESTINATION bin/)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.png DESTINATION ${ICONDIR}/hicolor/48x48/apps)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.svg DESTINATION ${ICONDIR}/hicolor/scalable/apps)
INSTALL(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cockatrice.desktop DESTINATION ${DESKTOPDIR})
INSTALL(FILES ${cockatrice_QM} DESTINATION share/cockatrice/translations)
endif()
install(TARGETS cockatrice BUNDLE DESTINATION ./)
else()
# Assume linux
install(TARGETS cockatrice RUNTIME DESTINATION bin/)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.png DESTINATION ${ICONDIR}/hicolor/48x48/apps)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/resources/cockatrice.svg DESTINATION ${ICONDIR}/hicolor/scalable/apps)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/cockatrice.desktop DESTINATION ${DESKTOPDIR})
endif()
elseif(WIN32)
INSTALL(TARGETS cockatrice RUNTIME DESTINATION ./)
INSTALL(FILES ${cockatrice_QM} DESTINATION ./translations)
install(TARGETS cockatrice RUNTIME DESTINATION ./)
endif()
if(APPLE)
# these needs to be relative to CMAKE_INSTALL_PREFIX
set(plugin_dest_dir cockatrice.app/Contents/Plugins)
set(qtconf_dest_dir cockatrice.app/Contents/Resources)
get_filename_component(QT_LIBRARY_DIR "${QT_LIBRARY_DIR}/.." ABSOLUTE)
# these needs to be relative to CMAKE_INSTALL_PREFIX
set(plugin_dest_dir cockatrice.app/Contents/Plugins)
set(qtconf_dest_dir cockatrice.app/Contents/Resources)
# qt5 plugins: audio, iconengines, imageformats, platforms, printsupport
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
FILES_MATCHING
PATTERN "*.dSYM" EXCLUDE
PATTERN "*_debug.dylib" EXCLUDE
PATTERN "audio/*.dylib"
PATTERN "iconengines/*.dylib"
PATTERN "imageformats/*.dylib"
PATTERN "platforms/*.dylib"
PATTERN "printsupport/*.dylib"
PATTERN "styles/*.dylib"
)
# Qt plugins: audio (Qt5), iconengines, imageformats, platforms, printsupport (Qt5), styles, tls (Qt6)
install(
DIRECTORY "${QT_PLUGINS_DIR}/"
DESTINATION ${plugin_dest_dir}
COMPONENT Runtime
FILES_MATCHING
PATTERN "*.dSYM" EXCLUDE
PATTERN "*_debug.dylib" EXCLUDE
PATTERN "audio/*.dylib"
PATTERN "iconengines/*.dylib"
PATTERN "imageformats/*.dylib"
PATTERN "platforms/*.dylib"
PATTERN "printsupport/*.dylib"
PATTERN "styles/*.dylib"
PATTERN "tls/*.dylib"
)
install(CODE "
install(
CODE "
file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"[Paths]
Plugins = Plugins
Translations = Resources/translations
Data = Resources\")
" COMPONENT Runtime)
"
COMPONENT Runtime
)
install(CODE "
install(
CODE "
file(GLOB_RECURSE QTPLUGINS
\"\${CMAKE_INSTALL_PREFIX}/${plugin_dest_dir}/*.dylib\")
set(BU_CHMOD_BUNDLE_ITEMS ON)
include(BundleUtilities)
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/cockatrice.app\" \"\${QTPLUGINS}\" \"${QT_LIBRARY_DIR}\")
" COMPONENT Runtime)
"
COMPONENT Runtime
)
endif()
if(WIN32)
# these needs to be relative to CMAKE_INSTALL_PREFIX
set(plugin_dest_dir Plugins)
set(qtconf_dest_dir .)
# these needs to be relative to CMAKE_INSTALL_PREFIX
set(plugin_dest_dir Plugins)
set(qtconf_dest_dir .)
install(DIRECTORY "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${CMAKE_BUILD_TYPE}/" DESTINATION ./ FILES_MATCHING PATTERN "*.dll")
install(
DIRECTORY "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/${CMAKE_BUILD_TYPE}/"
DESTINATION ./
FILES_MATCHING
PATTERN "*.dll"
)
# qt5 plugins: audio, iconengines, imageformats, platforms, printsupport
install(DIRECTORY "${QT_PLUGINS_DIR}/" DESTINATION ${plugin_dest_dir} COMPONENT Runtime
FILES_MATCHING REGEX "(audio|iconengines|imageformats|platforms|printsupport|styles)/.*[^d]\\.dll")
# Qt plugins: audio (Qt5), iconengines, imageformats, platforms, printsupport (Qt5), styles, tls (Qt6)
install(
DIRECTORY "${QT_PLUGINS_DIR}/"
DESTINATION ${plugin_dest_dir}
COMPONENT Runtime
FILES_MATCHING
PATTERN "audio/qtaudio_wasapi.dll"
PATTERN "audio/qtaudio_windows.dll"
PATTERN "iconengines/qsvgicon.dll"
PATTERN "imageformats/qgif.dll"
PATTERN "imageformats/qicns.dll"
PATTERN "imageformats/qico.dll"
PATTERN "imageformats/qjpeg.dll"
PATTERN "imageformats/qsvg.dll"
PATTERN "imageformats/qtga.dll"
PATTERN "imageformats/qtiff.dll"
PATTERN "imageformats/qwbmp.dll"
PATTERN "imageformats/qwebp.dll"
PATTERN "platforms/qdirect2d.dll"
PATTERN "platforms/qminimal.dll"
PATTERN "platforms/qoffscreen.dll"
PATTERN "platforms/qwindows.dll"
PATTERN "printsupport/windowsprintersupport.dll"
PATTERN "styles/qcertonlybackend.dll"
PATTERN "styles/qopensslbackend.dll"
PATTERN "styles/qschannelbackend.dll"
PATTERN "styles/qwindowsvistastyle.dll"
PATTERN "tls/qcertonlybackend.dll"
PATTERN "tls/qopensslbackend.dll"
PATTERN "tls/qschannelbackend.dll"
)
install(CODE "
install(
CODE "
file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${qtconf_dest_dir}/qt.conf\" \"[Paths]
Plugins = Plugins
Translations = Resources/translations
Data = Resources\")
" COMPONENT Runtime)
"
COMPONENT Runtime
)
install(CODE "
install(
CODE "
file(GLOB_RECURSE QTPLUGINS
\"\${CMAKE_INSTALL_PREFIX}/${plugin_dest_dir}/*.dll\")
set(BU_CHMOD_BUNDLE_ITEMS ON)
include(BundleUtilities)
fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/Cockatrice.exe\" \"\${QTPLUGINS}\" \"${QT_LIBRARY_DIR}\")
" COMPONENT Runtime)
"
COMPONENT Runtime
)
if(WIN32SSLRUNTIME_FOUND)
install(FILES ${WIN32SSLRUNTIME_LIBRARIES} DESTINATION ./)
endif()
if(WIN32SSLRUNTIME_FOUND)
install(FILES ${WIN32SSLRUNTIME_LIBRARIES} DESTINATION ./)
endif()
endif()
if(Qt6LinguistTools_FOUND)
# Qt6 Translations happen after the executable is built up
if(UPDATE_TRANSLATIONS)
qt6_add_translations(
cockatrice
TS_FILES
${cockatrice_TS}
SOURCES
${translate_SRCS}
QM_FILES_OUTPUT_VARIABLE
cockatrice_QM
)
else()
qt6_add_translations(cockatrice TS_FILES ${cockatrice_TS} QM_FILES_OUTPUT_VARIABLE cockatrice_QM)
endif()
if(UNIX)
if(APPLE)
install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_MAC_QM_INSTALL_DIR})
else()
install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_UNIX_QM_INSTALL_DIR})
endif()
elseif(WIN32)
install(FILES ${cockatrice_QM} DESTINATION ${COCKATRICE_WIN32_QM_INSTALL_DIR})
endif()
endif()
if(Qt6_FOUND)
qt6_finalize_target(cockatrice)
endif()

View File

@@ -126,6 +126,7 @@
<file>resources/countries/er.svg</file>
<file>resources/countries/es.svg</file>
<file>resources/countries/et.svg</file>
<file>resources/countries/eu.svg</file>
<file>resources/countries/fi.svg</file>
<file>resources/countries/fj.svg</file>
<file>resources/countries/fk.svg</file>
@@ -301,16 +302,13 @@
<file>resources/countries/vu.svg</file>
<file>resources/countries/wf.svg</file>
<file>resources/countries/ws.svg</file>
<file>resources/countries/xk.svg</file>
<file>resources/countries/ye.svg</file>
<file>resources/countries/yt.svg</file>
<file>resources/countries/za.svg</file>
<file>resources/countries/zm.svg</file>
<file>resources/countries/zw.svg</file>
<file>resources/genders/male.svg</file>
<file>resources/genders/female.svg</file>
<file>resources/genders/unknown.svg</file>
<file>resources/phases/untap.svg</file>
<file>resources/phases/upkeep.svg</file>
<file>resources/phases/draw.svg</file>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

View File

@@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
version="1.0"
width="75"
height="75"
id="svg34864">
<defs
id="defs34866" />
<g
transform="translate(-348.7552,-478.0905)"
id="layer1">
<g
transform="matrix(1.071197,0,0,1.075147,-13.30677,-36.99488)"
id="g3773">
<path
d="M 176 33 A 11 11 0 1 1 154,33 A 11 11 0 1 1 176 33 z"
transform="matrix(1.540096,0,0,1.5384,118.8893,454.0543)"
style="color:black;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:3;stroke-linecap:butt;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
id="path3939" />
<path
d="M 373.00525,521.74399 L 373.00525,543.28159"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:4.61774349;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path3941" />
<path
d="M 363.76467,534.05119 L 382.24582,534.05119"
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:black;stroke-width:4.61774349;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
id="path4816" />
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,12 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.0" width="75" height="75" id="svg34864">
<defs id="defs34866"/>
<g transform="translate(-348.755, -478.091)" id="layer1">
<g transform="matrix(1.94812, 0, 0, 1.93731, -342.43, -460.01)" id="g1872">
<path d="M 387.95009,489.60348 L 378.66214,498.89143" style="opacity: 1; color: black; fill: none; fill-opacity: 0.75; fill-rule: evenodd; stroke: black; stroke-width: 3; stroke-linecap: butt; stroke-linejoin: miter; marker: none; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1; visibility: visible; display: inline; overflow: visible;" id="path26867"/>
<path d="M 49.396475 36.70454 A 15.623922 16.319134 0 1 1 18.14863,36.70454 A 15.623922 16.319134 0 1 1 49.396475 36.70454 z" transform="matrix(0.48802, 0.48802, -0.467594, 0.467594, 371.609, 473.136)" style="opacity: 1; color: black; fill: none; fill-opacity: 1; fill-rule: evenodd; stroke: black; stroke-width: 4.44072; stroke-linecap: butt; stroke-linejoin: miter; marker: none; stroke-miterlimit: 4; stroke-dasharray: none; stroke-dashoffset: 0pt; stroke-opacity: 1; visibility: visible; display: inline; overflow: visible;" id="path26871"/>
<path d="M 379.92823,489.70212 C 387.842,489.70212 387.842,489.70212 387.842,489.70212 L 387.842,497.61589" style="fill: none; fill-rule: evenodd; stroke: black; stroke-width: 3; stroke-linecap: butt; stroke-linejoin: miter; stroke-miterlimit: 4; stroke-dasharray: none; stroke-opacity: 1;" id="path27759"/>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,10 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Intersexual/Transgendered symbol by Gregory Maxwell. Copyright 2005. GFDL-1.2 only -->
<svg
xmlns="http://www.w3.org/2000/svg"
version="1.1"
width="210"
height="280">
<path d="M 188,38 v 20 l 14,-8 v -42 h -42 l -8,14 h 20 l -37,37 a 79,79 0 1,0 -59,141 v 22 h -27 v 23 h 27 v 27 h 23 v -27 h 27 v -23 h -27 v -22 a 79,79 0 0,0 52,-125 zm -100,27 a 57,57 0 1,1 0,114 a 57,57 0 1,1 0,-114 z"/>
<!-- 88,65 // -63,-10 -->
</svg>

Before

Width:  |  Height:  |  Size: 500 B

View File

@@ -2,18 +2,15 @@
#
# add sounds subfolders
SET(defsounds
Default
Legacy
)
set(defsounds Default Legacy)
if(UNIX)
if(APPLE)
INSTALL(DIRECTORY ${defsounds} DESTINATION Cockatrice.app/Contents/Resources/sounds/)
else()
# Assume linux
INSTALL(DIRECTORY ${defsounds} DESTINATION share/cockatrice/sounds/)
endif()
if(APPLE)
install(DIRECTORY ${defsounds} DESTINATION Cockatrice.app/Contents/Resources/sounds/)
else()
# Assume linux
install(DIRECTORY ${defsounds} DESTINATION share/cockatrice/sounds/)
endif()
elseif(WIN32)
INSTALL(DIRECTORY ${defsounds} DESTINATION sounds/)
install(DIRECTORY ${defsounds} DESTINATION sounds/)
endif()

View File

@@ -1,19 +1,17 @@
#include <QCursor>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <algorithm>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
#include "abstractcarditem.h"
#include "carddatabase.h"
#include "gamescene.h"
#include "main.h"
#include "pictureloader.h"
#include "settingscache.h"
#include <QCursor>
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <algorithm>
AbstractCardItem::AbstractCardItem(const QString &_name, Player *_owner, int _id, QGraphicsItem *parent)
: ArrowTarget(_owner, parent), id(_id), name(_name), tapped(false), facedown(false), tapAngle(0),
bgColor(Qt::transparent), isHovered(false), realZValue(0)

View File

@@ -22,7 +22,8 @@
#include <google/protobuf/descriptor.h>
AbstractClient::AbstractClient(QObject *parent) : QObject(parent), nextCmdId(0), status(StatusDisconnected)
AbstractClient::AbstractClient(QObject *parent)
: QObject(parent), nextCmdId(0), status(StatusDisconnected), serverSupportsPasswordHash(false)
{
qRegisterMetaType<QVariant>("QVariant");
qRegisterMetaType<CommandContainer>("CommandContainer");
@@ -47,6 +48,7 @@ AbstractClient::AbstractClient(QObject *parent) : QObject(parent), nextCmdId(0),
qRegisterMetaType<QList<ServerInfo_User>>("QList<ServerInfo_User>");
qRegisterMetaType<Event_ReplayAdded>("Event_ReplayAdded");
qRegisterMetaType<QList<QString>>("missingFeatures");
qRegisterMetaType<PendingCommand *>("pendingCommand");
FeatureSet features;
features.initalizeFeatureList(clientFeatures);

View File

@@ -40,6 +40,7 @@ enum ClientStatus
StatusRequestingForgotPassword,
StatusSubmitForgotPasswordReset,
StatusSubmitForgotPasswordChallenge,
StatusGettingPasswordSalt,
};
class AbstractClient : public QObject
@@ -87,7 +88,7 @@ protected slots:
protected:
QMap<int, PendingCommand *> pendingCommands;
QString userName, password, email, country, realName, token;
int gender;
bool serverSupportsPasswordHash;
void setStatus(ClientStatus _status);
int getNewCmdId()
{
@@ -107,7 +108,11 @@ public:
void sendCommand(const CommandContainer &cont);
void sendCommand(PendingCommand *pend);
const QString getUserName()
bool getServerSupportsPasswordHash() const
{
return serverSupportsPasswordHash;
}
const QString &getUserName() const
{
return userName;
}

View File

@@ -16,7 +16,7 @@
#include <QGraphicsScene>
#include <QGraphicsSceneMouseEvent>
#include <QPainter>
#include <cmath>
#include <QtMath>
ArrowItem::ArrowItem(Player *_player, int _id, ArrowTarget *_startItem, ArrowTarget *_targetItem, const QColor &_color)
: QGraphicsItem(), player(_player), id(_id), startItem(_startItem), targetItem(_targetItem), color(_color),
@@ -71,7 +71,7 @@ void ArrowItem::updatePath(const QPointF &endPoint)
const double arrowWidth = 15.0;
const double headWidth = 40.0;
const double headLength =
headWidth / pow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++
headWidth / qPow(2, 0.5); // aka headWidth / sqrt (2) but this produces a compile error with MSVC++
const double phi = 15;
if (!startItem)
@@ -86,7 +86,7 @@ void ArrowItem::updatePath(const QPointF &endPoint)
if (lineLength < 30)
path = QPainterPath();
else {
QPointF c(lineLength / 2, tan(phi * M_PI / 180) * lineLength);
QPointF c(lineLength / 2, qTan(phi * M_PI / 180) * lineLength);
QPainterPath centerLine;
centerLine.moveTo(0, 0);
@@ -97,22 +97,22 @@ void ArrowItem::updatePath(const QPointF &endPoint)
QLineF testLine(arrowBodyEndPoint, centerLine.pointAtPercent(percentage + 0.001));
qreal alpha = testLine.angle() - 90;
QPointF endPoint1 =
arrowBodyEndPoint + arrowWidth / 2 * QPointF(cos(alpha * M_PI / 180), -sin(alpha * M_PI / 180));
arrowBodyEndPoint + arrowWidth / 2 * QPointF(qCos(alpha * M_PI / 180), -qSin(alpha * M_PI / 180));
QPointF endPoint2 =
arrowBodyEndPoint + arrowWidth / 2 * QPointF(-cos(alpha * M_PI / 180), sin(alpha * M_PI / 180));
arrowBodyEndPoint + arrowWidth / 2 * QPointF(-qCos(alpha * M_PI / 180), qSin(alpha * M_PI / 180));
QPointF point1 =
endPoint1 + (headWidth - arrowWidth) / 2 * QPointF(cos(alpha * M_PI / 180), -sin(alpha * M_PI / 180));
endPoint1 + (headWidth - arrowWidth) / 2 * QPointF(qCos(alpha * M_PI / 180), -qSin(alpha * M_PI / 180));
QPointF point2 =
endPoint2 + (headWidth - arrowWidth) / 2 * QPointF(-cos(alpha * M_PI / 180), sin(alpha * M_PI / 180));
endPoint2 + (headWidth - arrowWidth) / 2 * QPointF(-qCos(alpha * M_PI / 180), qSin(alpha * M_PI / 180));
path = QPainterPath(-arrowWidth / 2 * QPointF(cos((phi - 90) * M_PI / 180), sin((phi - 90) * M_PI / 180)));
path = QPainterPath(-arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180)));
path.quadTo(c, endPoint1);
path.lineTo(point1);
path.lineTo(QPointF(lineLength, 0));
path.lineTo(point2);
path.lineTo(endPoint2);
path.quadTo(c, arrowWidth / 2 * QPointF(cos((phi - 90) * M_PI / 180), sin((phi - 90) * M_PI / 180)));
path.lineTo(-arrowWidth / 2 * QPointF(cos((phi - 90) * M_PI / 180), sin((phi - 90) * M_PI / 180)));
path.quadTo(c, arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180)));
path.lineTo(-arrowWidth / 2 * QPointF(qCos((phi - 90) * M_PI / 180), qSin((phi - 90) * M_PI / 180)));
}
setPos(startPoint);

View File

@@ -43,9 +43,8 @@ public:
}
void removeArrowFrom(ArrowItem *arrow)
{
arrowsFrom.removeAt(arrowsFrom.indexOf(arrow));
arrowsFrom.removeOne(arrow);
}
const QList<ArrowItem *> &getArrowsTo() const
{
return arrowsTo;
@@ -56,8 +55,7 @@ public:
}
void removeArrowTo(ArrowItem *arrow)
{
arrowsTo.removeAt(arrowsTo.indexOf(arrow));
arrowsTo.removeOne(arrow);
}
};
#endif

View File

@@ -23,7 +23,7 @@ bool CockatriceXml3Parser::getCanParseFile(const QString &fileName, QIODevice &d
QXmlStreamReader xml(&device);
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::StartElement) {
if (xml.name() == COCKATRICE_XML3_TAGNAME) {
if (xml.name().toString() == COCKATRICE_XML3_TAGNAME) {
int version = xml.attributes().value("version").toString().toInt();
if (version == COCKATRICE_XML3_TAGVER) {
return true;
@@ -52,12 +52,13 @@ void CockatriceXml3Parser::parseFile(QIODevice &device)
break;
}
if (xml.name() == "sets") {
auto name = xml.name().toString();
if (name == "sets") {
loadSetsFromXml(xml);
} else if (xml.name() == "cards") {
} else if (name == "cards") {
loadCardsFromXml(xml);
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml3Parser] Unknown item" << xml.name() << ", trying to continue anyway";
} else if (!name.isEmpty()) {
qDebug() << "[CockatriceXml3Parser] Unknown item" << name << ", trying to continue anyway";
xml.skipCurrentElement();
}
}
@@ -72,26 +73,27 @@ void CockatriceXml3Parser::loadSetsFromXml(QXmlStreamReader &xml)
break;
}
if (xml.name() == "set") {
auto name = xml.name().toString();
if (name == "set") {
QString shortName, longName, setType;
QDate releaseDate;
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
name = xml.name().toString();
if (xml.name() == "name") {
if (name == "name") {
shortName = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "longname") {
} else if (name == "longname") {
longName = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "settype") {
} else if (name == "settype") {
setType = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "releasedate") {
} else if (name == "releasedate") {
releaseDate =
QDate::fromString(xml.readElementText(QXmlStreamReader::IncludeChildElements), Qt::ISODate);
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml3Parser] Unknown set property" << xml.name()
<< ", trying to continue anyway";
} else if (!name.isEmpty()) {
qDebug() << "[CockatriceXml3Parser] Unknown set property" << name << ", trying to continue anyway";
xml.skipCurrentElement();
}
}
@@ -146,7 +148,8 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
break;
}
if (xml.name() == "card") {
auto xmlName = xml.name().toString();
if (xmlName == "card") {
QString name = QString("");
QString text = QString("");
QVariantHash properties = QVariantHash();
@@ -162,37 +165,39 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
xmlName = xml.name().toString();
// variable - assigned properties
if (xml.name() == "name") {
if (xmlName == "name") {
name = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "text") {
} else if (xmlName == "text") {
text = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "color") {
} else if (xmlName == "color") {
colors.append(xml.readElementText(QXmlStreamReader::IncludeChildElements));
} else if (xml.name() == "token") {
} else if (xmlName == "token") {
isToken = static_cast<bool>(xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt());
// generic properties
} else if (xml.name() == "manacost") {
} else if (xmlName == "manacost") {
properties.insert("manacost", xml.readElementText(QXmlStreamReader::IncludeChildElements));
} else if (xml.name() == "cmc") {
} else if (xmlName == "cmc") {
properties.insert("cmc", xml.readElementText(QXmlStreamReader::IncludeChildElements));
} else if (xml.name() == "type") {
} else if (xmlName == "type") {
QString type = xml.readElementText(QXmlStreamReader::IncludeChildElements);
properties.insert("type", type);
properties.insert("maintype", getMainCardType(type));
} else if (xml.name() == "pt") {
} else if (xmlName == "pt") {
properties.insert("pt", xml.readElementText(QXmlStreamReader::IncludeChildElements));
} else if (xml.name() == "loyalty") {
} else if (xmlName == "loyalty") {
properties.insert("loyalty", xml.readElementText(QXmlStreamReader::IncludeChildElements));
// positioning info
} else if (xml.name() == "tablerow") {
} else if (xmlName == "tablerow") {
tableRow = xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt();
} else if (xml.name() == "cipt") {
} else if (xmlName == "cipt") {
cipt = (xml.readElementText(QXmlStreamReader::IncludeChildElements) == "1");
} else if (xml.name() == "upsidedown") {
} else if (xmlName == "upsidedown") {
upsideDown = (xml.readElementText(QXmlStreamReader::IncludeChildElements) == "1");
// sets
} else if (xml.name() == "set") {
} else if (xmlName == "set") {
// NOTE: attributes must be read before readElementText()
QXmlStreamAttributes attrs = xml.attributes();
QString setName = xml.readElementText(QXmlStreamReader::IncludeChildElements);
@@ -217,8 +222,8 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
setInfo.setProperty("rarity", attrs.value("rarity").toString());
}
sets.insert(setName, setInfo);
// relatd cards
} else if (xml.name() == "related" || xml.name() == "reverse-related") {
// related cards
} else if (xmlName == "related" || xmlName == "reverse-related") {
bool attach = false;
bool exclude = false;
bool variable = false;
@@ -249,13 +254,13 @@ void CockatriceXml3Parser::loadCardsFromXml(QXmlStreamReader &xml)
}
auto *relation = new CardRelation(cardName, attach, exclude, variable, count);
if (xml.name() == "reverse-related") {
if (xmlName == "reverse-related") {
reverseRelatedCards << relation;
} else {
relatedCards << relation;
}
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml3Parser] Unknown card property" << xml.name()
} else if (!xmlName.isEmpty()) {
qDebug() << "[CockatriceXml3Parser] Unknown card property" << xmlName
<< ", trying to continue anyway";
xml.skipCurrentElement();
}

View File

@@ -23,7 +23,7 @@ bool CockatriceXml4Parser::getCanParseFile(const QString &fileName, QIODevice &d
QXmlStreamReader xml(&device);
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::StartElement) {
if (xml.name() == COCKATRICE_XML4_TAGNAME) {
if (xml.name().toString() == COCKATRICE_XML4_TAGNAME) {
int version = xml.attributes().value("version").toString().toInt();
if (version == COCKATRICE_XML4_TAGVER) {
return true;
@@ -52,12 +52,13 @@ void CockatriceXml4Parser::parseFile(QIODevice &device)
break;
}
if (xml.name() == "sets") {
auto xmlName = xml.name().toString();
if (xmlName == "sets") {
loadSetsFromXml(xml);
} else if (xml.name() == "cards") {
} else if (xmlName == "cards") {
loadCardsFromXml(xml);
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml4Parser] Unknown item" << xml.name() << ", trying to continue anyway";
} else if (!xmlName.isEmpty()) {
qDebug() << "[CockatriceXml4Parser] Unknown item" << xmlName << ", trying to continue anyway";
xml.skipCurrentElement();
}
}
@@ -72,25 +73,27 @@ void CockatriceXml4Parser::loadSetsFromXml(QXmlStreamReader &xml)
break;
}
if (xml.name() == "set") {
auto xmlName = xml.name().toString();
if (xmlName == "set") {
QString shortName, longName, setType;
QDate releaseDate;
while (!xml.atEnd()) {
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
xmlName = xml.name().toString();
if (xml.name() == "name") {
if (xmlName == "name") {
shortName = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "longname") {
} else if (xmlName == "longname") {
longName = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "settype") {
} else if (xmlName == "settype") {
setType = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "releasedate") {
} else if (xmlName == "releasedate") {
releaseDate =
QDate::fromString(xml.readElementText(QXmlStreamReader::IncludeChildElements), Qt::ISODate);
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml4Parser] Unknown set property" << xml.name()
} else if (!xmlName.isEmpty()) {
qDebug() << "[CockatriceXml4Parser] Unknown set property" << xmlName
<< ", trying to continue anyway";
xml.skipCurrentElement();
}
@@ -109,8 +112,9 @@ QVariantHash CockatriceXml4Parser::loadCardPropertiesFromXml(QXmlStreamReader &x
break;
}
if (xml.name() != "") {
properties.insert(xml.name().toString(), xml.readElementText(QXmlStreamReader::IncludeChildElements));
auto xmlName = xml.name().toString();
if (!xmlName.isEmpty()) {
properties.insert(xmlName, xml.readElementText(QXmlStreamReader::IncludeChildElements));
}
}
return properties;
@@ -123,7 +127,9 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
break;
}
if (xml.name() == "card") {
auto xmlName = xml.name().toString();
if (xmlName == "card") {
QString name = QString("");
QString text = QString("");
QVariantHash properties = QVariantHash();
@@ -138,25 +144,28 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
if (xml.readNext() == QXmlStreamReader::EndElement) {
break;
}
xmlName = xml.name().toString();
// variable - assigned properties
if (xml.name() == "name") {
if (xmlName == "name") {
name = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "text") {
} else if (xmlName == "text") {
text = xml.readElementText(QXmlStreamReader::IncludeChildElements);
} else if (xml.name() == "token") {
} else if (xmlName == "token") {
isToken = static_cast<bool>(xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt());
// generic properties
} else if (xml.name() == "prop") {
} else if (xmlName == "prop") {
properties = loadCardPropertiesFromXml(xml);
// positioning info
} else if (xml.name() == "tablerow") {
} else if (xmlName == "tablerow") {
tableRow = xml.readElementText(QXmlStreamReader::IncludeChildElements).toInt();
} else if (xml.name() == "cipt") {
} else if (xmlName == "cipt") {
cipt = (xml.readElementText(QXmlStreamReader::IncludeChildElements) == "1");
} else if (xml.name() == "upsidedown") {
} else if (xmlName == "upsidedown") {
upsideDown = (xml.readElementText(QXmlStreamReader::IncludeChildElements) == "1");
// sets
} else if (xml.name() == "set") {
} else if (xmlName == "set") {
// NOTE: attributes but be read before readElementText()
QXmlStreamAttributes attrs = xml.attributes();
QString setName = xml.readElementText(QXmlStreamReader::IncludeChildElements);
@@ -171,8 +180,8 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
}
sets.insert(setName, setInfo);
}
// relatd cards
} else if (xml.name() == "related" || xml.name() == "reverse-related") {
// related cards
} else if (xmlName == "related" || xmlName == "reverse-related") {
bool attach = false;
bool exclude = false;
bool variable = false;
@@ -203,13 +212,13 @@ void CockatriceXml4Parser::loadCardsFromXml(QXmlStreamReader &xml)
}
auto *relation = new CardRelation(cardName, attach, exclude, variable, count);
if (xml.name() == "reverse-related") {
if (xmlName == "reverse-related") {
reverseRelatedCards << relation;
} else {
relatedCards << relation;
}
} else if (xml.name() != "") {
qDebug() << "[CockatriceXml4Parser] Unknown card property" << xml.name()
} else if (!xmlName.isEmpty()) {
qDebug() << "[CockatriceXml4Parser] Unknown card property" << xmlName
<< ", trying to continue anyway";
xml.skipCurrentElement();
}

View File

@@ -6,13 +6,9 @@
#include "main.h"
#include <QApplication>
#include <utility>
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
#include <QScreen>
#else
#include <QDesktopWidget>
#endif
#include <QVBoxLayout>
#include <utility>
CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::WindowFlags flags)
: QFrame(parent, flags), aspectRatio((qreal)CARD_HEIGHT / (qreal)CARD_WIDTH), info(nullptr)
@@ -34,12 +30,7 @@ CardInfoWidget::CardInfoWidget(const QString &cardName, QWidget *parent, Qt::Win
setFrameStyle(QFrame::Panel | QFrame::Raised);
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
int pixmapHeight = qApp->primaryScreen()->geometry().height() / 3;
#else
QDesktopWidget desktopWidget;
int pixmapHeight = desktopWidget.screenGeometry().height() / 3;
#endif
int pixmapHeight = QGuiApplication::primaryScreen()->geometry().height() / 3;
int pixmapWidth = static_cast<int>(pixmapHeight / aspectRatio);
pic->setFixedWidth(pixmapWidth);
pic->setFixedHeight(pixmapHeight);

View File

@@ -2,6 +2,7 @@
#define CARDITEM_H
#include "abstractcarditem.h"
#include "server_card.h"
class CardDatabase;
class CardDragItem;
@@ -130,7 +131,7 @@ public:
}
void removeAttachedCard(CardItem *card)
{
attachedCards.removeAt(attachedCards.indexOf(card));
attachedCards.removeOne(card);
}
const QList<CardItem *> &getAttachedCards() const
{

View File

@@ -187,7 +187,7 @@ CardItem *CardZone::takeCard(int position, int cardId, bool /*canResize*/)
void CardZone::removeCard(CardItem *card)
{
cards.removeAt(cards.indexOf(card));
cards.removeOne(card);
reorganizeCards();
emit cardCountChanged();
player->deleteCard(card);

View File

@@ -12,8 +12,6 @@
#include <QDesktopServices>
#include <QMouseEvent>
#include <QScrollBar>
#include <QTextDocumentFragment>
#include <QTextEdit>
const QColor DEFAULT_MENTION_COLOR = QColor(194, 31, 47);
@@ -323,7 +321,7 @@ void ChatView::checkTag(QTextCursor &cursor, QString &message)
void ChatView::checkMention(QTextCursor &cursor, QString &message, const QString &userName, UserLevelFlags userLevel)
{
const QRegExp notALetterOrNumber = QRegExp("[^a-zA-Z0-9]");
const static auto notALetterOrNumber = QRegularExpression("[^a-zA-Z0-9]");
int firstSpace = message.indexOf(' ');
QString fullMentionUpToSpaceOrEnd = (firstSpace == -1) ? message.mid(1) : message.mid(1, firstSpace - 1);
@@ -512,7 +510,11 @@ void ChatView::redactMessages(const QString &userName, int amount)
}
}
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
void ChatView::enterEvent(QEnterEvent * /*event*/)
#else
void ChatView::enterEvent(QEvent * /*event*/)
#endif
{
setMouseTracking(true);
}
@@ -568,7 +570,11 @@ void ChatView::mousePressEvent(QMouseEvent *event)
switch (hoveredItemType) {
case HoveredCard: {
if ((event->button() == Qt::MiddleButton) || (event->button() == Qt::LeftButton))
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
emit showCardInfoPopup(event->globalPosition().toPoint(), hoveredContent);
#else
emit showCardInfoPopup(event->globalPos(), hoveredContent);
#endif
break;
}
case HoveredUser: {
@@ -578,7 +584,11 @@ void ChatView::mousePressEvent(QMouseEvent *event)
switch (event->button()) {
case Qt::RightButton: {
UserLevelFlags userLevel(hoveredContent.left(delimiterIndex).toInt());
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
userContextMenu->showContextMenu(event->globalPosition().toPoint(), userName, userLevel, this);
#else
userContextMenu->showContextMenu(event->globalPos(), userName, userLevel, this);
#endif
break;
}
case Qt::LeftButton: {

View File

@@ -103,7 +103,11 @@ public:
void redactMessages(const QString &userName, int amount);
protected:
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
void enterEvent(QEnterEvent *event);
#else
void enterEvent(QEvent *event);
#endif
void leaveEvent(QEvent *event);
void mouseMoveEvent(QMouseEvent *event);
void mousePressEvent(QMouseEvent *event);

View File

@@ -1,4 +1,3 @@
#include "customlineedit.h"
#include "settingscache.h"
@@ -38,8 +37,8 @@ bool LineEditUnfocusable::isUnfocusShortcut(QKeyEvent *event)
QKeySequence key(modifier + keyNoMod);
QList<QKeySequence> unfocusShortcut = SettingsCache::instance().shortcuts().getShortcut("Textbox/unfocusTextBox");
for (QList<QKeySequence>::iterator i = unfocusShortcut.begin(); i != unfocusShortcut.end(); ++i) {
if (key.matches(*i) == QKeySequence::ExactMatch)
for (const auto &unfocusKey : unfocusShortcut) {
if (key.matches(unfocusKey) == QKeySequence::ExactMatch)
return true;
}
return false;

View File

@@ -12,12 +12,13 @@ class QString;
// shortcuts and other shortcuts
class LineEditUnfocusable : public QLineEdit
{
Q_OBJECT
public:
LineEditUnfocusable(QWidget *parent = nullptr);
LineEditUnfocusable(const QString &contents, QWidget *parent = nullptr);
explicit LineEditUnfocusable(QWidget *parent = nullptr);
explicit LineEditUnfocusable(const QString &contents, QWidget *parent = nullptr);
private:
bool isUnfocusShortcut(QKeyEvent *key);
static bool isUnfocusShortcut(QKeyEvent *key);
protected:
void keyPressEvent(QKeyEvent *event) override;

View File

@@ -6,6 +6,7 @@
#include <QDebug>
#include <QFile>
#include <QRegularExpression>
#include <QStringList>
const QStringList DeckLoader::fileNameFilters = QStringList()
@@ -208,7 +209,7 @@ void DeckLoader::saveToStream_DeckHeader(QTextStream &out)
}
if (!getComments().isEmpty()) {
QStringList commentRows = getComments().split(QRegExp("\n|\r\n|\r"));
QStringList commentRows = getComments().split(QRegularExpression("\n|\r\n|\r"));
foreach (QString row, commentRows) {
out << "// " << row << "\n";
}

View File

@@ -9,8 +9,8 @@
#include <QApplication>
#include <QGraphicsSceneMouseEvent>
#include <QMouseEvent>
#include <QtMath>
#include <algorithm>
#include <math.h>
DeckViewCardDragItem::DeckViewCardDragItem(DeckViewCard *_item,
const QPointF &_hotSpot,
@@ -216,7 +216,7 @@ void DeckViewCardContainer::addCard(DeckViewCard *card)
void DeckViewCardContainer::removeCard(DeckViewCard *card)
{
cards.removeAt(cards.indexOf(card));
cards.removeOne(card);
cardsByType.remove(card->getInfo() ? card->getInfo()->getMainCardType() : "", card);
}
@@ -238,11 +238,9 @@ int DeckViewCardContainer::getCardTypeTextWidth() const
QFontMetrics fm(f);
int maxCardTypeWidth = 0;
QMapIterator<QString, DeckViewCard *> i(cardsByType);
while (i.hasNext()) {
int cardTypeWidth = fm.size(Qt::TextSingleLine, i.next().key()).width();
if (cardTypeWidth > maxCardTypeWidth)
maxCardTypeWidth = cardTypeWidth;
for (const auto &key : cardsByType.keys()) {
int cardTypeWidth = fm.size(Qt::TextSingleLine, key).width();
maxCardTypeWidth = qMax(maxCardTypeWidth, cardTypeWidth);
}
return maxCardTypeWidth + 15;
@@ -440,7 +438,7 @@ void DeckViewScene::rearrangeItems()
const int maxRows = rowsAndColsList[maxIndex1][maxIndex2].first;
const int maxCardCount = cardCountList[maxIndex1][maxIndex2];
rowsAndColsList[maxIndex1][maxIndex2] =
QPair<int, int>(maxRows + 1, (int)ceil((qreal)maxCardCount / (qreal)(maxRows + 1)));
QPair<int, int>(maxRows + 1, (int)qCeil((qreal)maxCardCount / (qreal)(maxRows + 1)));
}
totalHeight = -spacing;

View File

@@ -1,6 +1,7 @@
#include "dlg_connect.h"
#include "settingscache.h"
#include "stringsizes.h"
#include "userconnection_information.h"
#include <QCheckBox>
@@ -39,22 +40,27 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
saveLabel = new QLabel(tr("Name:"));
saveEdit = new QLineEdit;
saveEdit->setMaxLength(MAX_NAME_LENGTH);
saveLabel->setBuddy(saveEdit);
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit;
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit;
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit;
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
passwordLabel = new QLabel(tr("P&assword:"));
passwordEdit = new QLineEdit;
passwordEdit->setMaxLength(MAX_NAME_LENGTH);
passwordLabel->setBuddy(passwordEdit);
passwordEdit->setEchoMode(QLineEdit::Password);
@@ -156,8 +162,7 @@ DlgConnect::DlgConnect(QWidget *parent) : QDialog(parent)
previousHostButton->setChecked(true);
connect(previousHosts, SIGNAL(currentIndexChanged(const QString &)), this,
SLOT(updateDisplayInfo(const QString &)));
connect(previousHosts, SIGNAL(currentTextChanged(const QString &)), this, SLOT(updateDisplayInfo(const QString &)));
playernameEdit->setFocus();
}

View File

@@ -5,6 +5,7 @@
#include "decklist.h"
#include "main.h"
#include "settingscache.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QCloseEvent>
@@ -28,6 +29,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
nameLabel = new QLabel(tr("&Name:"));
nameEdit = new QLineEdit(tr("Token"));
nameEdit->setMaxLength(MAX_NAME_LENGTH);
nameEdit->selectAll();
connect(nameEdit, SIGNAL(textChanged(const QString &)), this, SLOT(updateSearch(const QString &)));
nameLabel->setBuddy(nameEdit);
@@ -45,10 +47,12 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
ptLabel = new QLabel(tr("&P/T:"));
ptEdit = new QLineEdit;
ptEdit->setMaxLength(MAX_NAME_LENGTH);
ptLabel->setBuddy(ptEdit);
annotationLabel = new QLabel(tr("&Annotation:"));
annotationEdit = new QLineEdit;
annotationEdit->setMaxLength(MAX_NAME_LENGTH);
annotationLabel->setBuddy(annotationEdit);
destroyCheckBox = new QCheckBox(tr("&Destroy token when it leaves the table"));

View File

@@ -3,6 +3,7 @@
#include "pb/serverinfo_game.pb.h"
#include "pending_command.h"
#include "settingscache.h"
#include "stringsizes.h"
#include "tab_room.h"
#include <QApplication>
@@ -24,8 +25,8 @@ void DlgCreateGame::sharedCtor()
rememberGameSettings = new QCheckBox(tr("Re&member settings"));
descriptionLabel = new QLabel(tr("&Description:"));
descriptionEdit = new QLineEdit;
descriptionEdit->setMaxLength(MAX_NAME_LENGTH);
descriptionLabel->setBuddy(descriptionEdit);
descriptionEdit->setMaxLength(60);
maxPlayersLabel = new QLabel(tr("P&layers:"));
maxPlayersEdit = new QSpinBox();
@@ -57,6 +58,7 @@ void DlgCreateGame::sharedCtor()
passwordLabel = new QLabel(tr("&Password:"));
passwordEdit = new QLineEdit;
passwordEdit->setMaxLength(MAX_NAME_LENGTH);
passwordLabel->setBuddy(passwordEdit);
onlyBuddiesCheckBox = new QCheckBox(tr("Only &buddies can join"));

View File

@@ -1,5 +1,7 @@
#include "dlg_edit_avatar.h"
#include "stringsizes.h"
#include <QBuffer>
#include <QDebug>
#include <QDialogButtonBox>
@@ -72,9 +74,15 @@ QByteArray DlgEditAvatar::getImage()
return QByteArray();
}
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "JPG");
return ba;
for (;;) {
QByteArray ba;
QBuffer buffer(&ba);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "JPG");
if (ba.length() > MAX_FILE_LENGTH) {
image = image.scaledToWidth(image.width() / 2); // divide the amount of pixels in four to get the size down
} else {
return ba;
}
}
}

View File

@@ -1,6 +1,7 @@
#include "dlg_edit_password.h"
#include "settingscache.h"
#include "stringsizes.h"
#include <QDialogButtonBox>
#include <QGridLayout>
@@ -12,6 +13,7 @@ DlgEditPassword::DlgEditPassword(QWidget *parent) : QDialog(parent)
{
oldPasswordLabel = new QLabel(tr("Old password:"));
oldPasswordEdit = new QLineEdit();
oldPasswordEdit->setMaxLength(MAX_NAME_LENGTH);
auto &servers = SettingsCache::instance().servers();
if (servers.getSavePassword()) {
@@ -23,11 +25,13 @@ DlgEditPassword::DlgEditPassword(QWidget *parent) : QDialog(parent)
newPasswordLabel = new QLabel(tr("New password:"));
newPasswordEdit = new QLineEdit();
newPasswordEdit->setMaxLength(MAX_NAME_LENGTH);
newPasswordLabel->setBuddy(newPasswordLabel);
newPasswordEdit->setEchoMode(QLineEdit::Password);
newPasswordLabel2 = new QLabel(tr("Confirm new password:"));
newPasswordEdit2 = new QLineEdit();
newPasswordEdit2->setMaxLength(MAX_NAME_LENGTH);
newPasswordLabel2->setBuddy(newPasswordLabel2);
newPasswordEdit2->setEchoMode(QLineEdit::Password);
@@ -55,7 +59,11 @@ DlgEditPassword::DlgEditPassword(QWidget *parent) : QDialog(parent)
void DlgEditPassword::actOk()
{
if (newPasswordEdit->text() != newPasswordEdit2->text()) {
// TODO this stuff should be using qvalidators
if (newPasswordEdit->text().length() < 8) {
QMessageBox::critical(this, tr("Error"), tr("Your password is too short."));
return;
} else if (newPasswordEdit->text() != newPasswordEdit2->text()) {
QMessageBox::warning(this, tr("Error"), tr("The new passwords don't match."));
return;
}

View File

@@ -2,7 +2,9 @@
#include "carddatabase.h"
#include "carddatabasemodel.h"
#include "gettextwithmax.h"
#include "main.h"
#include "stringsizes.h"
#include <QAction>
#include <QComboBox>
@@ -23,6 +25,7 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(nul
{
nameLabel = new QLabel(tr("&Name:"));
nameEdit = new QLineEdit;
nameEdit->setMaxLength(MAX_NAME_LENGTH);
nameEdit->setEnabled(false);
nameLabel->setBuddy(nameEdit);
@@ -40,11 +43,13 @@ DlgEditTokens::DlgEditTokens(QWidget *parent) : QDialog(parent), currentCard(nul
ptLabel = new QLabel(tr("&P/T:"));
ptEdit = new QLineEdit;
ptEdit->setMaxLength(MAX_NAME_LENGTH);
ptLabel->setBuddy(ptEdit);
connect(ptEdit, SIGNAL(textChanged(QString)), this, SLOT(ptChanged(QString)));
annotationLabel = new QLabel(tr("&Annotation:"));
annotationEdit = new QLineEdit;
annotationEdit->setMaxLength(MAX_NAME_LENGTH);
annotationLabel->setBuddy(annotationEdit);
connect(annotationEdit, SIGNAL(textChanged(QString)), this, SLOT(annotationChanged(QString)));
@@ -142,9 +147,8 @@ void DlgEditTokens::tokenSelectionChanged(const QModelIndex &current, const QMod
void DlgEditTokens::actAddToken()
{
QString name;
bool askAgain = true;
do {
name = QInputDialog::getText(this, tr("Add token"), tr("Please enter the name of the token:"));
for (;;) {
name = getTextWithMax(this, tr("Add token"), tr("Please enter the name of the token:"));
if (name.isEmpty())
return;
if (databaseModel->getDatabase()->getCard(name)) {
@@ -152,9 +156,9 @@ void DlgEditTokens::actAddToken()
tr("The chosen name conflicts with an existing card or token.\nMake sure to enable "
"the 'Token' set in the \"Manage sets\" dialog to display them correctly."));
} else {
askAgain = false;
break;
}
} while (askAgain);
}
QString setName = CardDatabase::TOKENS_SETNAME;
CardInfoPerSetMap sets;

View File

@@ -1,6 +1,7 @@
#include "dlg_edit_user.h"
#include "settingscache.h"
#include "stringsizes.h"
#include <QDebug>
#include <QDialogButtonBox>
@@ -12,6 +13,7 @@ DlgEditUser::DlgEditUser(QWidget *parent, QString email, QString country, QStrin
{
emailLabel = new QLabel(tr("Email:"));
emailEdit = new QLineEdit();
emailEdit->setMaxLength(MAX_NAME_LENGTH);
emailLabel->setBuddy(emailEdit);
emailEdit->setText(email);
@@ -33,6 +35,7 @@ DlgEditUser::DlgEditUser(QWidget *parent, QString email, QString country, QStrin
realnameLabel = new QLabel(tr("Real name:"));
realnameEdit = new QLineEdit();
realnameEdit->setMaxLength(MAX_NAME_LENGTH);
realnameLabel->setBuddy(realnameEdit);
realnameEdit->setText(realName);

View File

@@ -21,10 +21,6 @@ public:
{
return emailEdit->text();
}
int getGender() const
{
return -1;
} // This will return GenderUnknown for protocol purposes.
QString getCountry() const
{
return countryEdit->currentIndex() == 0 ? "" : countryEdit->currentText();

View File

@@ -1,6 +1,7 @@
#include "dlg_forgotpasswordchallenge.h"
#include "settingscache.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QDebug>
@@ -38,18 +39,22 @@ DlgForgotPasswordChallenge::DlgForgotPasswordChallenge(QWidget *parent) : QDialo
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit(lastfphost);
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit(lastfpport);
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit(lastfpplayername);
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
emailLabel = new QLabel(tr("Email:"));
emailEdit = new QLineEdit();
emailEdit->setMaxLength(MAX_NAME_LENGTH);
emailLabel->setBuddy(emailLabel);
if (!servers.getFPHostname().isEmpty() && !servers.getFPPort().isEmpty() && !servers.getFPPlayerName().isEmpty()) {

View File

@@ -1,6 +1,7 @@
#include "dlg_forgotpasswordrequest.h"
#include "settingscache.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QDebug>
@@ -31,14 +32,17 @@ DlgForgotPasswordRequest::DlgForgotPasswordRequest(QWidget *parent) : QDialog(pa
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit(lastfphost);
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit(lastfpport);
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit(lastfpplayername);
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
QGridLayout *grid = new QGridLayout;

View File

@@ -1,6 +1,7 @@
#include "dlg_forgotpasswordreset.h"
#include "settingscache.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QDebug>
@@ -37,27 +38,33 @@ DlgForgotPasswordReset::DlgForgotPasswordReset(QWidget *parent) : QDialog(parent
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit(lastfphost);
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit(lastfpport);
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit(lastfpplayername);
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
tokenLabel = new QLabel(tr("Token:"));
tokenEdit = new QLineEdit();
tokenEdit->setMaxLength(MAX_NAME_LENGTH);
tokenLabel->setBuddy(tokenLabel);
newpasswordLabel = new QLabel(tr("New Password:"));
newpasswordEdit = new QLineEdit();
newpasswordEdit->setMaxLength(MAX_NAME_LENGTH);
newpasswordLabel->setBuddy(newpasswordEdit);
newpasswordEdit->setEchoMode(QLineEdit::Password);
newpasswordverifyLabel = new QLabel(tr("New Password:"));
newpasswordverifyEdit = new QLineEdit();
newpasswordverifyEdit->setMaxLength(MAX_NAME_LENGTH);
newpasswordverifyLabel->setBuddy(newpasswordEdit);
newpasswordverifyEdit->setEchoMode(QLineEdit::Password);
@@ -116,7 +123,11 @@ void DlgForgotPasswordReset::actOk()
return;
}
if (newpasswordEdit->text() != newpasswordverifyEdit->text()) {
// TODO this stuff should be using qvalidators
if (newpasswordEdit->text().length() < 8) {
QMessageBox::critical(this, tr("Error"), tr("Your password is too short."));
return;
} else if (newpasswordEdit->text() != newpasswordverifyEdit->text()) {
QMessageBox::critical(this, tr("Reset Password Error"), tr("The passwords do not match."));
return;
}

View File

@@ -121,7 +121,12 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
connect(disableSomeButton, SIGNAL(clicked()), this, SLOT(actDisableSome()));
connect(view->selectionModel(), SIGNAL(selectionChanged(const QItemSelection &, const QItemSelection &)), this,
SLOT(actToggleButtons(const QItemSelection &, const QItemSelection &)));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
connect(searchField, SIGNAL(textChanged(const QString &)), displayModel,
SLOT(setFilterRegularExpression(const QString &)));
#else
connect(searchField, SIGNAL(textChanged(const QString &)), displayModel, SLOT(setFilterRegExp(const QString &)));
#endif
connect(view->header(), SIGNAL(sortIndicatorChanged(int, Qt::SortOrder)), this, SLOT(actDisableSortButtons(int)));
connect(searchField, SIGNAL(textChanged(const QString &)), this, SLOT(actDisableResetButton(const QString &)));
@@ -139,7 +144,6 @@ WndSets::WndSets(QWidget *parent) : QMainWindow(parent)
tr("How to use custom card art") + "</a>"));
QGridLayout *hintsGrid = new QGridLayout;
hintsGrid->setMargin(2);
hintsGrid->addWidget(labNotes, 0, 0);
hintsGroupBox = new QGroupBox(tr("Hints"));
hintsGroupBox->setLayout(hintsGrid);

View File

@@ -2,6 +2,7 @@
#include "pb/serverinfo_user.pb.h"
#include "settingscache.h"
#include "stringsizes.h"
#include <QCheckBox>
#include <QDebug>
@@ -20,32 +21,39 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
hostLabel = new QLabel(tr("&Host:"));
hostEdit = new QLineEdit(servers.getHostname());
hostEdit->setMaxLength(MAX_NAME_LENGTH);
hostLabel->setBuddy(hostEdit);
portLabel = new QLabel(tr("&Port:"));
portEdit = new QLineEdit(servers.getPort());
portEdit->setValidator(new QIntValidator(0, 0xffff, portEdit));
portLabel->setBuddy(portEdit);
playernameLabel = new QLabel(tr("Player &name:"));
playernameEdit = new QLineEdit(servers.getPlayerName());
playernameEdit->setMaxLength(MAX_NAME_LENGTH);
playernameLabel->setBuddy(playernameEdit);
passwordLabel = new QLabel(tr("P&assword:"));
passwordEdit = new QLineEdit();
passwordEdit->setMaxLength(MAX_NAME_LENGTH);
passwordLabel->setBuddy(passwordEdit);
passwordEdit->setEchoMode(QLineEdit::Password);
passwordConfirmationLabel = new QLabel(tr("Password (again):"));
passwordConfirmationEdit = new QLineEdit();
passwordConfirmationEdit->setMaxLength(MAX_NAME_LENGTH);
passwordConfirmationLabel->setBuddy(passwordConfirmationEdit);
passwordConfirmationEdit->setEchoMode(QLineEdit::Password);
emailLabel = new QLabel(tr("Email:"));
emailEdit = new QLineEdit();
emailEdit->setMaxLength(MAX_NAME_LENGTH);
emailLabel->setBuddy(emailEdit);
emailConfirmationLabel = new QLabel(tr("Email (again):"));
emailConfirmationEdit = new QLineEdit();
emailConfirmationEdit->setMaxLength(MAX_NAME_LENGTH);
emailConfirmationLabel->setBuddy(emailConfirmationEdit);
countryLabel = new QLabel(tr("Country:"));
@@ -121,6 +129,7 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
countryEdit->addItem(QPixmap("theme:countries/er"), "er");
countryEdit->addItem(QPixmap("theme:countries/es"), "es");
countryEdit->addItem(QPixmap("theme:countries/et"), "et");
countryEdit->addItem(QPixmap("theme:countries/eu"), "eu");
countryEdit->addItem(QPixmap("theme:countries/fi"), "fi");
countryEdit->addItem(QPixmap("theme:countries/fj"), "fj");
countryEdit->addItem(QPixmap("theme:countries/fk"), "fk");
@@ -296,6 +305,7 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
countryEdit->addItem(QPixmap("theme:countries/vu"), "vu");
countryEdit->addItem(QPixmap("theme:countries/wf"), "wf");
countryEdit->addItem(QPixmap("theme:countries/ws"), "ws");
countryEdit->addItem(QPixmap("theme:countries/xk"), "xk");
countryEdit->addItem(QPixmap("theme:countries/ye"), "ye");
countryEdit->addItem(QPixmap("theme:countries/yt"), "yt");
countryEdit->addItem(QPixmap("theme:countries/za"), "za");
@@ -308,6 +318,7 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
realnameLabel = new QLabel(tr("Real name:"));
realnameEdit = new QLineEdit();
realnameEdit->setMaxLength(MAX_NAME_LENGTH);
realnameLabel->setBuddy(realnameEdit);
QGridLayout *grid = new QGridLayout;
@@ -347,7 +358,11 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
void DlgRegister::actOk()
{
if (passwordEdit->text() != passwordConfirmationEdit->text()) {
// TODO this stuff should be using qvalidators
if (passwordEdit->text().length() < 8) {
QMessageBox::critical(this, tr("Registration Warning"), tr("Your password is too short."));
return;
} else if (passwordEdit->text() != passwordConfirmationEdit->text()) {
QMessageBox::critical(this, tr("Registration Warning"), tr("Your passwords do not match, please try again."));
return;
} else if (emailConfirmationEdit->text() != emailEdit->text()) {

View File

@@ -34,10 +34,6 @@ public:
{
return emailEdit->text();
}
int getGender() const
{
return -1;
} // This will return GenderUnknown for the protocol.
QString getCountry() const
{
return countryEdit->currentIndex() == 0 ? "" : countryEdit->currentText();

View File

@@ -1,6 +1,7 @@
#include "dlg_settings.h"
#include "carddatabase.h"
#include "gettextwithmax.h"
#include "main.h"
#include "releasechannel.h"
#include "sequenceEdit/sequenceedit.h"
@@ -16,7 +17,6 @@
#include <QComboBox>
#include <QDebug>
#include <QDesktopServices>
#include <QDesktopWidget>
#include <QDialogButtonBox>
#include <QFileDialog>
#include <QGridLayout>
@@ -43,18 +43,22 @@
GeneralSettingsPage::GeneralSettingsPage()
{
SettingsCache &settings = SettingsCache::instance();
QString setLanguage = settings.getLang();
QStringList qmFiles = findQmFiles();
for (int i = 0; i < qmFiles.size(); i++) {
QString langName = languageName(qmFiles[i]);
languageBox.addItem(langName, qmFiles[i]);
if ((qmFiles[i] == setLanguage) ||
(setLanguage.isEmpty() && langName == QCoreApplication::translate("i18n", DEFAULT_LANG_NAME)))
languageBox.setCurrentIndex(i);
QStringList languageCodes = findQmFiles();
for (const QString &code : languageCodes) {
QString langName = languageName(code);
languageBox.addItem(langName, code);
}
QString setLanguage = QCoreApplication::translate("i18n", DEFAULT_LANG_NAME);
int index = languageBox.findText(setLanguage, Qt::MatchExactly);
if (index == -1) {
qWarning() << "could not find language" << setLanguage;
} else {
languageBox.setCurrentIndex(index);
}
// updates
SettingsCache &settings = SettingsCache::instance();
QList<ReleaseChannel *> channels = settings.getUpdateReleaseChannels();
foreach (ReleaseChannel *chan, channels) {
updateReleaseChannelBox.insertItem(chan->getIndex(), tr(chan->getName().toUtf8()));
@@ -76,12 +80,9 @@ GeneralSettingsPage::GeneralSettingsPage()
connect(&languageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(languageBoxChanged(int)));
connect(&pixmapCacheEdit, SIGNAL(valueChanged(int)), &settings, SLOT(setPixmapCacheSize(int)));
connect(&updateReleaseChannelBox, SIGNAL(currentIndexChanged(int)), &settings,
SLOT(setUpdateReleaseChannel(int)));
connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), &settings,
SLOT(setNotifyAboutUpdate(int)));
connect(&newVersionOracleCheckBox, SIGNAL(stateChanged(int)), &settings,
SLOT(setNotifyAboutNewVersion(int)));
connect(&updateReleaseChannelBox, SIGNAL(currentIndexChanged(int)), &settings, SLOT(setUpdateReleaseChannel(int)));
connect(&updateNotificationCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setNotifyAboutUpdate(int)));
connect(&newVersionOracleCheckBox, SIGNAL(stateChanged(int)), &settings, SLOT(setNotifyAboutNewVersion(int)));
connect(&showTipsOnStartup, SIGNAL(clicked(bool)), &settings, SLOT(setShowTipsOnStartup(bool)));
auto *personalGrid = new QGridLayout;
@@ -179,6 +180,7 @@ GeneralSettingsPage::GeneralSettingsPage()
auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(personalGroupBox);
mainLayout->addWidget(pathsGroupBox);
mainLayout->addStretch();
setLayout(mainLayout);
}
@@ -187,19 +189,21 @@ QStringList GeneralSettingsPage::findQmFiles()
{
QDir dir(translationPath);
QStringList fileNames = dir.entryList(QStringList(translationPrefix + "_*.qm"), QDir::Files, QDir::Name);
fileNames.replaceInStrings(QRegExp(translationPrefix + "_(.*)\\.qm"), "\\1");
fileNames.replaceInStrings(QRegularExpression(translationPrefix + "_(.*)\\.qm"), "\\1");
return fileNames;
}
QString GeneralSettingsPage::languageName(const QString &qmFile)
QString GeneralSettingsPage::languageName(const QString &lang)
{
if (qmFile == DEFAULT_LANG_CODE)
return DEFAULT_LANG_NAME;
QTranslator qTranslator;
QTranslator translator;
translator.load(translationPrefix + "_" + qmFile + ".qm", translationPath);
QString appNameHint = translationPrefix + "_" + lang;
bool appTranslationLoaded = qTranslator.load(appNameHint, translationPath);
if (!appTranslationLoaded) {
qDebug() << "Unable to load" << translationPrefix << "translation" << appNameHint << "at" << translationPath;
}
return translator.translate("i18n", DEFAULT_LANG_NAME);
return qTranslator.translate("i18n", DEFAULT_LANG_NAME);
}
void GeneralSettingsPage::deckPathButtonClicked()
@@ -386,6 +390,7 @@ AppearanceSettingsPage::AppearanceSettingsPage()
mainLayout->addWidget(cardsGroupBox);
mainLayout->addWidget(handGroupBox);
mainLayout->addWidget(tableGroupBox);
mainLayout->addStretch();
setLayout(mainLayout);
}
@@ -493,6 +498,7 @@ UserInterfaceSettingsPage::UserInterfaceSettingsPage()
mainLayout->addWidget(generalGroupBox);
mainLayout->addWidget(notificationsGroupBox);
mainLayout->addWidget(animationGroupBox);
mainLayout->addStretch();
setLayout(mainLayout);
}
@@ -563,12 +569,15 @@ DeckEditorSettingsPage::DeckEditorSettingsPage()
auto aAdd = new QAction(this);
aAdd->setIcon(QPixmap("theme:icons/increment"));
aAdd->setToolTip(tr("Add New URL"));
connect(aAdd, SIGNAL(triggered()), this, SLOT(actAddURL()));
auto aEdit = new QAction(this);
aEdit->setIcon(QPixmap("theme:icons/pencil"));
aEdit->setToolTip(tr("Edit URL"));
connect(aEdit, SIGNAL(triggered()), this, SLOT(actEditURL()));
auto aRemove = new QAction(this);
aRemove->setIcon(QPixmap("theme:icons/decrement"));
aRemove->setToolTip(tr("Remove URL"));
connect(aRemove, SIGNAL(triggered()), this, SLOT(actRemoveURL()));
auto *messageToolBar = new QToolBar;
@@ -856,16 +865,15 @@ MessagesSettingsPage::MessagesSettingsPage()
aAdd = new QAction(this);
aAdd->setIcon(QPixmap("theme:icons/increment"));
aAdd->setStatusTip(tr("Add New URL"));
aAdd->setToolTip(tr("Add New Message"));
connect(aAdd, SIGNAL(triggered()), this, SLOT(actAdd()));
aEdit = new QAction(this);
aEdit->setIcon(QPixmap("theme:icons/pencil"));
aEdit->setStatusTip(tr("Edit URL"));
aEdit->setToolTip(tr("Edit Message"));
connect(aEdit, SIGNAL(triggered()), this, SLOT(actEdit()));
aRemove = new QAction(this);
aRemove->setIcon(QPixmap("theme:icons/decrement"));
aRemove->setStatusTip(tr("Remove URL"));
aRemove->setToolTip(tr("Remove Message"));
connect(aRemove, SIGNAL(triggered()), this, SLOT(actRemove()));
auto *messageToolBar = new QToolBar;
@@ -949,7 +957,8 @@ void MessagesSettingsPage::storeSettings()
void MessagesSettingsPage::actAdd()
{
bool ok;
QString msg = QInputDialog::getText(this, tr("Add message"), tr("Message:"), QLineEdit::Normal, QString(), &ok);
QString msg =
getTextWithMax(this, tr("Add message"), tr("Message:"), QLineEdit::Normal, QString(), &ok, MAX_TEXT_LENGTH);
if (ok) {
messageList->addItem(msg);
storeSettings();
@@ -961,7 +970,8 @@ void MessagesSettingsPage::actEdit()
if (messageList->currentItem()) {
QString oldText = messageList->currentItem()->text();
bool ok;
QString msg = QInputDialog::getText(this, tr("Edit message"), tr("Message:"), QLineEdit::Normal, oldText, &ok);
QString msg =
getTextWithMax(this, tr("Edit message"), tr("Message:"), QLineEdit::Normal, oldText, &ok, MAX_TEXT_LENGTH);
if (ok) {
messageList->currentItem()->setText(msg);
storeSettings();
@@ -1043,6 +1053,7 @@ SoundSettingsPage::SoundSettingsPage()
auto *mainLayout = new QVBoxLayout;
mainLayout->addWidget(soundGroupBox);
mainLayout->addStretch();
setLayout(mainLayout);
}
@@ -1232,13 +1243,8 @@ void ShortcutSettingsPage::retranslateUi()
DlgSettings::DlgSettings(QWidget *parent) : QDialog(parent)
{
#if (QT_VERSION >= QT_VERSION_CHECK(5, 13, 0))
QRect rec = qApp->primaryScreen()->availableGeometry();
#else
QRect rec = QApplication::desktop()->availableGeometry();
#endif
this->setMinimumSize(rec.width() / 2, rec.height() - 100);
this->setBaseSize(rec.width(), rec.height());
auto rec = QGuiApplication::primaryScreen()->availableGeometry();
this->setMinimumSize(qMin(700, rec.width()), qMin(700, rec.height()));
connect(&SettingsCache::instance(), SIGNAL(langChanged()), this, SLOT(updateLanguage()));

View File

@@ -49,7 +49,7 @@ private slots:
private:
QStringList findQmFiles();
QString languageName(const QString &qmFile);
QString languageName(const QString &lang);
QLineEdit *deckPathEdit;
QLineEdit *replaysPathEdit;
QLineEdit *picsPathEdit;

View File

@@ -4,7 +4,6 @@
#include <QByteArray>
#include <QString>
#include <cmath>
#include <functional>
peg::parser search(R"(
@@ -337,7 +336,7 @@ static void setupParserRules()
FilterString::FilterString(const QString &expr)
{
QByteArray ba = expr.toLocal8Bit();
QByteArray ba = expr.simplified().toUtf8();
std::call_once(init, setupParserRules);

View File

@@ -13,7 +13,7 @@
#include <QGraphicsSceneMouseEvent>
#include <QGraphicsView>
#include <QSet>
#include <math.h>
#include <QtMath>
GameScene::GameScene(PhasesToolbar *_phasesToolbar, QObject *parent)
: QGraphicsScene(parent), phasesToolbar(_phasesToolbar), viewSize(QSize()), playerRotation(0)
@@ -53,7 +53,7 @@ void GameScene::removePlayer(Player *player)
zone->close();
}
}
players.removeAt(players.indexOf(player));
players.removeOne(player);
removeItem(player);
rearrange();
}
@@ -97,7 +97,7 @@ void GameScene::rearrange()
const int playersCount = playersPlaying.size();
const int columns = playersCount < SettingsCache::instance().getMinPlayersForMultiColumnLayout() ? 1 : 2;
const int rows = ceil((qreal)playersCount / columns);
const int rows = qCeil((qreal)playersCount / columns);
qreal sceneHeight = 0, sceneWidth = -playerAreaSpacing;
QList<int> columnWidth;
@@ -178,7 +178,7 @@ void GameScene::addRevealedZoneView(Player *player,
void GameScene::removeZoneView(ZoneViewWidget *item)
{
zoneViews.removeAt(zoneViews.indexOf(item));
zoneViews.removeOne(item);
removeItem(item);
}

View File

@@ -4,6 +4,7 @@
#include "dlg_creategame.h"
#include "dlg_filter_games.h"
#include "gamesmodel.h"
#include "gettextwithmax.h"
#include "pb/response.pb.h"
#include "pb/room_commands.pb.h"
#include "pb/serverinfo_game.pb.h"
@@ -243,7 +244,7 @@ void GameSelector::actJoin()
QString password;
if (game.with_password() && !(spectator && !game.spectators_need_password()) && !overrideRestrictions) {
bool ok;
password = QInputDialog::getText(this, tr("Join game"), tr("Password:"), QLineEdit::Password, QString(), &ok);
password = getTextWithMax(this, tr("Join game"), tr("Password:"), QLineEdit::Password, QString(), &ok);
if (!ok)
return;
}

View File

@@ -93,11 +93,7 @@ QVariant GamesModel::data(const QModelIndex &index, int role) const
case CREATED: {
switch (role) {
case Qt::DisplayRole: {
#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
QDateTime then = QDateTime::fromSecsSinceEpoch(gameentry.start_time(), Qt::UTC);
#else
QDateTime then = QDateTime::fromTime_t(gameentry.start_time(), Qt::UTC);
#endif
int secs = then.secsTo(QDateTime::currentDateTimeUtc());
return getGameCreatedString(secs);
}

View File

@@ -0,0 +1,32 @@
#include "gettextwithmax.h"
QString getTextWithMax(QWidget *parent,
const QString &title,
const QString &label,
QLineEdit::EchoMode mode,
const QString &text,
bool *ok,
int max,
Qt::WindowFlags flags,
Qt::InputMethodHints inputMethodHints)
{
auto *dialog = new QInputDialog(parent, flags);
dialog->setWindowTitle(title);
dialog->setLabelText(label);
dialog->setTextValue(text);
dialog->setTextEchoMode(mode);
dialog->setInputMethodHints(inputMethodHints);
// find the qlineedit that this dialog holds, there should be only one
dialog->findChild<QLineEdit *>()->setMaxLength(max);
const int ret = dialog->exec();
if (ok != nullptr) {
*ok = !!ret;
}
if (ret) {
return dialog->textValue();
} else {
return QString();
}
}

View File

@@ -0,0 +1,23 @@
// custom QInputDialog::getText implementation that allows configuration of the max length
#ifndef GETTEXTWITHMAX_H
#define GETTEXTWITHMAX_H
#include "stringsizes.h"
#include <QInputDialog>
QString getTextWithMax(QWidget *parent,
const QString &title,
const QString &label,
QLineEdit::EchoMode echo = QLineEdit::Normal,
const QString &text = QString(),
bool *ok = nullptr,
int max = MAX_NAME_LENGTH,
Qt::WindowFlags flags = Qt::WindowFlags(),
Qt::InputMethodHints inputMethodHints = Qt::ImhNone);
static inline QString getTextWithMax(QWidget *parent, const QString &title, const QString &label, int max)
{
return getTextWithMax(parent, title, label, QLineEdit::Normal, QString(), nullptr, max);
}
#endif // GETTEXTWITHMAX_H

View File

@@ -24,8 +24,10 @@ void HandZone::updateBg()
void HandZone::addCardImpl(CardItem *card, int x, int /*y*/)
{
if (x == -1)
// if x is negative set it to add at end
if (x < 0 || x >= cards.size()) {
x = cards.size();
}
cards.insert(x, card);
if (!cards.getContentsKnown()) {

View File

@@ -12,8 +12,9 @@ LocalServer::LocalServer(QObject *parent) : Server(parent)
LocalServer::~LocalServer()
{
// LocalServer is single threaded so it doesn't need locks on this
while (!clients.isEmpty())
clients.first()->prepareDestroy();
for (auto *client : clients) {
client->prepareDestroy();
}
prepareDestroy();
}
@@ -42,7 +43,8 @@ AuthenticationResult LocalServer_DatabaseInterface::checkUserPassword(Server_Pro
const QString & /* password */,
const QString & /* clientId */,
QString & /* reasonStr */,
int & /* secondsLeft */)
int & /* banSecondsLeft */,
bool /* passwordNeedsHash */)
{
return UnknownUser;
}

View File

@@ -27,12 +27,14 @@ protected:
public:
LocalServer_DatabaseInterface(LocalServer *_localServer);
~LocalServer_DatabaseInterface() = default;
AuthenticationResult checkUserPassword(Server_ProtocolHandler *handler,
const QString &user,
const QString &password,
const QString &clientId,
QString &reasonStr,
int &secondsLeft);
int &secondsLeft,
bool passwordNeedsHash);
int getNextGameId()
{
return localServer->getNextLocalGameId();

View File

@@ -67,11 +67,29 @@ void installNewTranslator()
{
QString lang = SettingsCache::instance().getLang();
qtTranslator->load("qt_" + lang, QLibraryInfo::location(QLibraryInfo::TranslationsPath));
QString qtNameHint = "qt_" + lang;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
QString qtTranslationPath = QLibraryInfo::path(QLibraryInfo::TranslationsPath);
#else
QString qtTranslationPath = QLibraryInfo::location(QLibraryInfo::TranslationsPath);
#endif
bool qtTranslationLoaded = qtTranslator->load(qtNameHint, qtTranslationPath);
if (!qtTranslationLoaded) {
qDebug() << "Unable to load qt translation" << qtNameHint << "at" << qtTranslationPath;
} else {
qDebug() << "Loaded qt translation" << qtNameHint << "at" << qtTranslationPath;
}
qApp->installTranslator(qtTranslator);
translator->load(translationPrefix + "_" + lang, translationPath);
QString appNameHint = translationPrefix + "_" + lang;
bool appTranslationLoaded = qtTranslator->load(appNameHint, translationPath);
if (!appTranslationLoaded) {
qDebug() << "Unable to load" << translationPrefix << "translation" << appNameHint << "at" << translationPath;
} else {
qDebug() << "Loaded" << translationPrefix << "translation" << appNameHint << "at" << translationPath;
}
qApp->installTranslator(translator);
qDebug() << "Language changed:" << lang;
}
QString const generateClientID()
@@ -165,7 +183,9 @@ int main(int argc, char *argv[])
ui.show();
qDebug("main(): ui.show() finished");
#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
app.setAttribute(Qt::AA_UseHighDpiPixmaps);
#endif
app.exec();
qDebug("Event loop finished, terminating...");

View File

@@ -1,18 +1,16 @@
#include "phasestoolbar.h"
#include "pb/command_draw_cards.pb.h"
#include "pb/command_next_turn.pb.h"
#include "pb/command_set_active_phase.pb.h"
#include "pb/command_set_card_attr.pb.h"
#include "pixmapgenerator.h"
#include <QAction>
#include <QDebug>
#include <QPainter>
#include <QPen>
#include <QTimer>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
#include "pb/command_draw_cards.pb.h"
#include "pb/command_next_turn.pb.h"
#include "pb/command_set_active_phase.pb.h"
#include "pb/command_set_card_attr.pb.h"
#include "phasestoolbar.h"
#include "pixmapgenerator.h"
PhaseButton::PhaseButton(const QString &_name, QGraphicsItem *parent, QAction *_doubleClickAction, bool _highlightable)
: QObject(), QGraphicsItem(parent), name(_name), active(false), highlightable(_highlightable),
@@ -38,8 +36,7 @@ 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(static_cast<int>(round(translatedIconRect.height())), name);
QPixmap iconPixmap = PhasePixmapGenerator::generatePixmap(qRound(translatedIconRect.height()), name);
painter->setBrush(QColor(static_cast<int>(220 * (activeAnimationCounter / 10.0)),
static_cast<int>(220 * (activeAnimationCounter / 10.0)),
@@ -48,9 +45,8 @@ void PhaseButton::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*op
painter->drawRect(0, 0, static_cast<int>(width - 1), static_cast<int>(width - 1));
painter->save();
resetPainterTransform(painter);
painter->drawPixmap(iconPixmap.rect().translated(static_cast<int>(round(3 * scaleFactor)),
static_cast<int>(round(3 * scaleFactor))),
iconPixmap, iconPixmap.rect());
painter->drawPixmap(iconPixmap.rect().translated(qRound(3 * scaleFactor), qRound(3 * scaleFactor)), iconPixmap,
iconPixmap.rect());
painter->restore();
painter->setBrush(QColor(0, 0, 0, static_cast<int>(255 * ((10 - activeAnimationCounter) / 15.0))));

View File

@@ -6,6 +6,7 @@
#include "thememanager.h"
#include <QApplication>
#include <QScreen>
#include <QCryptographicHash>
#include <QDebug>
#include <QDir>
@@ -572,7 +573,10 @@ void PictureLoader::getPixmap(QPixmap &pixmap, CardInfoPtr card, QSize size)
// 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);
QScreen * screen = qApp->primaryScreen();
int dpr = screen->devicePixelRatio();
pixmap = bigPixmap.scaled(size * dpr, Qt::KeepAspectRatio, Qt::SmoothTransformation);
pixmap.setDevicePixelRatio(dpr);
QPixmapCache::insert(sizeKey, pixmap);
return;
}

View File

@@ -44,6 +44,10 @@ void PileZone::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*optio
void PileZone::addCardImpl(CardItem *card, int x, int /*y*/)
{
connect(card, SIGNAL(sigPixmapUpdated()), this, SLOT(callUpdate()));
// if x is negative set it to add at end
if (x < 0 || x >= cards.size()) {
x = cards.size();
}
cards.insert(x, card);
card->setPos(0, 0);
if (!contentsKnown()) {

View File

@@ -3,13 +3,9 @@
#include "pb/serverinfo_user.pb.h"
#include <QApplication>
#include <QDebug>
#include <QPainter>
#include <QPalette>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
#include <QDebug>
QMap<QString, QPixmap> PhasePixmapGenerator::pmCache;
@@ -78,25 +74,6 @@ QPixmap PingPixmapGenerator::generatePixmap(int size, int value, int max)
QMap<int, QPixmap> PingPixmapGenerator::pmCache;
QPixmap GenderPixmapGenerator::generatePixmap(int height)
{
ServerInfo_User::Gender gender = ServerInfo_User::GenderUnknown;
int key = gender * 100000 + height;
if (pmCache.contains(key))
return pmCache.value(key);
QString genderStr;
genderStr = "unknown";
QPixmap pixmap =
QPixmap("theme:genders/" + genderStr).scaled(height, height, Qt::KeepAspectRatio, Qt::SmoothTransformation);
pmCache.insert(key, pixmap);
return pixmap;
}
QMap<int, QPixmap> GenderPixmapGenerator::pmCache;
QPixmap CountryPixmapGenerator::generatePixmap(int height, const QString &countryCode)
{
if (countryCode.size() != 2)
@@ -122,7 +99,7 @@ QMap<QString, QPixmap> CountryPixmapGenerator::pmCache;
QPixmap UserLevelPixmapGenerator::generatePixmap(int height, UserLevelFlags userLevel, bool isBuddy, QString privLevel)
{
QString key = QString::number(height * 10000) + ":" + (int)userLevel + ":" + (int)isBuddy + ":" + privLevel;
QString key = QString::number(height * 10000) + ":" + (short)userLevel + ":" + (short)isBuddy + ":" + privLevel;
if (pmCache.contains(key))
return pmCache.value(key);

View File

@@ -45,19 +45,6 @@ public:
}
};
class GenderPixmapGenerator
{
private:
static QMap<int, QPixmap> pmCache;
public:
static QPixmap generatePixmap(int height);
static void clear()
{
pmCache.clear();
}
};
class CountryPixmapGenerator
{
private:

View File

@@ -10,6 +10,7 @@
#include "deck_loader.h"
#include "dlg_create_token.h"
#include "gamescene.h"
#include "gettextwithmax.h"
#include "handcounter.h"
#include "handzone.h"
#include "main.h"
@@ -56,6 +57,7 @@
#include "playertarget.h"
#include "settingscache.h"
#include "stackzone.h"
#include "stringsizes.h"
#include "tab_game.h"
#include "tablezone.h"
#include "thememanager.h"
@@ -64,6 +66,7 @@
#include <QDebug>
#include <QMenu>
#include <QMetaType>
#include <QPainter>
#include <QRegularExpression>
#include <QRegularExpressionMatch>
@@ -1844,11 +1847,32 @@ void Player::eventShuffle(const Event_Shuffle &event)
if (!zone) {
return;
}
auto &cardList = zone->getCards();
int absStart = event.start();
if (absStart < 0) { // negative indexes start from the end
absStart += cardList.length();
}
// close all views that contain shuffled cards
for (auto *view : zone->getViews()) {
if (view != nullptr) {
emit view->beingDeleted();
int length = view->getCards().length();
// we want to close empty views as well
if (length == 0 || length > absStart) { // note this assumes views always start at the top of the library
view->deleteLater();
break;
}
} else {
qWarning() << zone->getName() << "of" << getName() << "holds empty zoneview!";
}
}
// remove revealed card name on top of decks
if (absStart == 0 && !cardList.isEmpty()) {
cardList.first()->setName("");
zone->update();
}
emit logShuffle(this, zone, event.start(), event.end());
}
@@ -1924,7 +1948,7 @@ void Player::eventSetCardAttr(const Event_SetCardAttr &event, const GameEventCon
} else {
CardItem *card = zone->getCard(event.card_id(), QString());
if (!card) {
qDebug() << "Player::eventSetCardAttr: card id=" << event.card_id() << "not found";
qWarning() << "Player::eventSetCardAttr: card id=" << event.card_id() << "not found";
return;
}
setCardAttrHelper(context, card, event.attribute(), QString::fromStdString(event.attr_value()), false);
@@ -2324,7 +2348,7 @@ void Player::processGameEvent(GameEvent::GameEventType type, const GameEvent &ev
eventChangeZoneProperties(event.GetExtension(Event_ChangeZoneProperties::ext));
break;
default: {
qDebug() << "unhandled game event" << type;
qWarning() << "unhandled game event" << type;
}
}
}
@@ -2499,7 +2523,6 @@ AbstractCounter *Player::addCounter(const ServerInfo_Counter &counter)
AbstractCounter *Player::addCounter(int counterId, const QString &name, QColor color, int radius, int value)
{
qDebug() << "addCounter:" << getName() << counterId << name;
if (counters.contains(counterId)) {
return nullptr;
}
@@ -2613,15 +2636,6 @@ void Player::clearArrows()
void Player::rearrangeCounters()
{
qreal marginTop = 80;
// Determine total height of bounding rectangles
qreal totalHeight = 0;
for (const auto &counter : counters) {
if (counter->getShownInCounterArea()) {
totalHeight += counter->boundingRect().height();
}
}
const qreal padding = 5;
qreal ySize = boundingRect().y() + marginTop;
@@ -3034,8 +3048,8 @@ void Player::actSetPT()
}
bool ok;
dialogSemaphore = true;
QString pt = QInputDialog::getText(nullptr, tr("Change power/toughness"), tr("Change stats to:"), QLineEdit::Normal,
oldPT, &ok);
QString pt =
getTextWithMax(game, tr("Change power/toughness"), tr("Change stats to:"), QLineEdit::Normal, oldPT, &ok);
dialogSemaphore = false;
if (clearCardsToDelete() || !ok) {
return;
@@ -3053,7 +3067,11 @@ void Player::actSetPT()
const auto oldpt = parsePT(card->getPT());
int ptIter = 0;
for (const auto &item : ptList) {
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
if (item.typeId() == QMetaType::Type::Int) {
#else
if (item.type() == QVariant::Int) {
#endif
int oldItem = ptIter < oldpt.size() ? oldpt.at(ptIter).toInt() : 0;
newpt += '/' + QString::number(oldItem + item.toInt());
} else {
@@ -3140,8 +3158,9 @@ void Player::actSetAnnotation()
bool ok;
dialogSemaphore = true;
QString annotation = QInputDialog::getText(nullptr, tr("Set annotation"), tr("Please enter the new annotation:"),
QLineEdit::Normal, oldAnnotation, &ok);
QString annotation = QInputDialog::getMultiLineText(game, tr("Set annotation"),
tr("Please enter the new annotation:"), oldAnnotation, &ok)
.left(MAX_NAME_LENGTH);
dialogSemaphore = false;
if (clearCardsToDelete() || !ok) {
return;

View File

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

View File

@@ -7,10 +7,7 @@
#include <QDebug>
#include <QPainter>
#include <QPixmapCache>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
#include <QtMath>
PlayerCounter::PlayerCounter(Player *_player,
int _id,
@@ -49,7 +46,7 @@ void PlayerCounter::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*
QSize translatedSize = translatedRect.size().toSize();
QFont font("Serif");
font.setWeight(QFont::Bold);
font.setPixelSize(qMax((int)round(translatedSize.height() / 1.3), 9));
font.setPixelSize(qMax(qRound(translatedSize.height() / 1.3), 9));
painter->setFont(font);
painter->setPen(Qt::white);
painter->drawText(translatedRect, Qt::AlignCenter, QString::number(value));
@@ -96,9 +93,9 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o
QPainter tempPainter(&cachedPixmap);
// pow(foo, 0.5) equals to sqrt(foo), but using sqrt(foo) in this context will produce a compile error with
// MSVC++
QRadialGradient grad(translatedRect.center(), pow(translatedSize.width() * translatedSize.width() +
translatedSize.height() * translatedSize.height(),
0.5) /
QRadialGradient grad(translatedRect.center(), qPow(translatedSize.width() * translatedSize.width() +
translatedSize.height() * translatedSize.height(),
0.5) /
2);
grad.setColorAt(1, Qt::black);
grad.setColorAt(0, QColor(180, 180, 180));
@@ -135,7 +132,7 @@ void PlayerTarget::paint(QPainter *painter, const QStyleOptionGraphicsItem * /*o
name = name.mid(0, 10) + "...";
QFont font;
font.setPixelSize(qMax((int)round(translatedNameRect.height() / 1.5), 9));
font.setPixelSize(qMax(qRound(translatedNameRect.height() / 1.5), 9));
painter->setFont(font);
painter->setPen(Qt::white);
painter->drawText(translatedNameRect, Qt::AlignVCenter | Qt::AlignLeft, " " + name);

View File

@@ -23,10 +23,9 @@
int ReleaseChannel::sharedIndex = 0;
ReleaseChannel::ReleaseChannel() : response(nullptr), lastRelease(nullptr)
ReleaseChannel::ReleaseChannel() : netMan(new QNetworkAccessManager(this)), response(nullptr), lastRelease(nullptr)
{
index = sharedIndex++;
netMan = new QNetworkAccessManager(this);
}
ReleaseChannel::~ReleaseChannel()

View File

@@ -78,7 +78,7 @@ class ReleaseChannel : public QObject
{
Q_OBJECT
public:
ReleaseChannel();
explicit ReleaseChannel();
~ReleaseChannel() override;
protected:
@@ -117,7 +117,7 @@ class StableReleaseChannel : public ReleaseChannel
{
Q_OBJECT
public:
StableReleaseChannel() = default;
explicit StableReleaseChannel() = default;
~StableReleaseChannel() override = default;
QString getManualDownloadUrl() const override;

View File

@@ -1,11 +1,13 @@
#include "remoteclient.h"
#include "debug_pb_message.h"
#include "main.h"
#include "pb/commands.pb.h"
#include "passwordhasher.h"
#include "pb/event_server_identification.pb.h"
#include "pb/response_activate.pb.h"
#include "pb/response_forgotpasswordrequest.pb.h"
#include "pb/response_login.pb.h"
#include "pb/response_password_salt.pb.h"
#include "pb/response_register.pb.h"
#include "pb/server_message.pb.h"
#include "pb/session_commands.pb.h"
@@ -26,7 +28,7 @@ static const unsigned int protocolVersion = 14;
RemoteClient::RemoteClient(QObject *parent)
: AbstractClient(parent), timeRunning(0), lastDataReceived(0), messageInProgress(false), handshakeStarted(false),
usingWebSocket(false), messageLength(0)
usingWebSocket(false), messageLength(0), hashedPassword()
{
clearNewClientFeatures();
@@ -39,8 +41,13 @@ RemoteClient::RemoteClient(QObject *parent)
socket->setSocketOption(QAbstractSocket::LowDelayOption, 1);
connect(socket, SIGNAL(connected()), this, SLOT(slotConnected()));
connect(socket, SIGNAL(readyRead()), this, SLOT(readData()));
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
connect(socket, &QTcpSocket::errorOccurred, this, &RemoteClient::slotSocketError);
#else
connect(socket, SIGNAL(error(QAbstractSocket::SocketError)), this,
SLOT(slotSocketError(QAbstractSocket::SocketError)));
#endif
websocket = new QWebSocket(QString(), QWebSocketProtocol::VersionLatest, this);
connect(websocket, &QWebSocket::binaryMessageReceived, this, &RemoteClient::websocketMessageReceived);
@@ -55,8 +62,8 @@ RemoteClient::RemoteClient(QObject *parent)
connect(this, SIGNAL(sigConnectToServer(QString, unsigned int, QString, QString)), this,
SLOT(doConnectToServer(QString, unsigned int, QString, QString)));
connect(this, SIGNAL(sigDisconnectFromServer()), this, SLOT(doDisconnectFromServer()));
connect(this, SIGNAL(sigRegisterToServer(QString, unsigned int, QString, QString, QString, int, QString, QString)),
this, SLOT(doRegisterToServer(QString, unsigned int, QString, QString, QString, int, QString, QString)));
connect(this, SIGNAL(sigRegisterToServer(QString, unsigned int, QString, QString, QString, QString, QString)), this,
SLOT(doRegisterToServer(QString, unsigned int, QString, QString, QString, QString, QString)));
connect(this, SIGNAL(sigActivateToServer(QString)), this, SLOT(doActivateToServer(QString)));
connect(this, SIGNAL(sigRequestForgotPasswordToServer(QString, unsigned int, QString)), this,
SLOT(doRequestForgotPasswordToServer(QString, unsigned int, QString)));
@@ -109,6 +116,7 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica
setStatus(StatusDisconnecting);
return;
}
serverSupportsPasswordHash = event.server_options() & Event_ServerIdentification::SupportsPasswordHash;
if (getStatus() == StatusRequestingForgotPassword) {
Command_ForgotPasswordRequest cmdForgotPasswordRequest;
@@ -126,7 +134,14 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica
cmdForgotPasswordReset.set_user_name(userName.toStdString());
cmdForgotPasswordReset.set_clientid(getSrvClientID(lastHostname).toStdString());
cmdForgotPasswordReset.set_token(token.toStdString());
cmdForgotPasswordReset.set_new_password(password.toStdString());
if (!password.isEmpty() && serverSupportsPasswordHash) {
auto passwordSalt = PasswordHasher::generateRandomSalt();
hashedPassword = PasswordHasher::computeHash(password, passwordSalt);
cmdForgotPasswordReset.set_hashed_new_password(hashedPassword.toStdString());
} else if (!password.isEmpty()) {
qWarning() << "using plain text password to reset password";
cmdForgotPasswordReset.set_new_password(password.toStdString());
}
PendingCommand *pend = prepareSessionCommand(cmdForgotPasswordReset);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this,
SLOT(submitForgotPasswordResetResponse(Response)));
@@ -149,9 +164,15 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica
if (getStatus() == StatusRegistering) {
Command_Register cmdRegister;
cmdRegister.set_user_name(userName.toStdString());
cmdRegister.set_password(password.toStdString());
if (!password.isEmpty() && serverSupportsPasswordHash) {
auto passwordSalt = PasswordHasher::generateRandomSalt();
hashedPassword = PasswordHasher::computeHash(password, passwordSalt);
cmdRegister.set_hashed_password(hashedPassword.toStdString());
} else if (!password.isEmpty()) {
qWarning() << "using plain text password to register";
cmdRegister.set_password(password.toStdString());
}
cmdRegister.set_email(email.toStdString());
cmdRegister.set_gender((ServerInfo_User_Gender)gender);
cmdRegister.set_country(country.toStdString());
cmdRegister.set_real_name(realName.toStdString());
cmdRegister.set_clientid(getSrvClientID(lastHostname).toStdString());
@@ -178,12 +199,21 @@ void RemoteClient::processServerIdentificationEvent(const Event_ServerIdentifica
doLogin();
}
void RemoteClient::doLogin()
void RemoteClient::doRequestPasswordSalt()
{
setStatus(StatusGettingPasswordSalt);
Command_RequestPasswordSalt cmdRqSalt;
cmdRqSalt.set_user_name(userName.toStdString());
PendingCommand *pend = prepareSessionCommand(cmdRqSalt);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(passwordSaltResponse(Response)));
sendCommand(pend);
}
Command_Login RemoteClient::generateCommandLogin()
{
setStatus(StatusLoggingIn);
Command_Login cmdLogin;
cmdLogin.set_user_name(userName.toStdString());
cmdLogin.set_password(password.toStdString());
cmdLogin.set_clientid(getSrvClientID(lastHostname).toStdString());
cmdLogin.set_clientver(VERSION_STRING);
@@ -192,6 +222,41 @@ void RemoteClient::doLogin()
for (i = clientFeatures.begin(); i != clientFeatures.end(); ++i)
cmdLogin.add_clientfeatures(i.key().toStdString().c_str());
}
return cmdLogin;
}
void RemoteClient::doLogin()
{
if (!password.isEmpty() && serverSupportsPasswordHash) {
// TODO store and log in using stored hashed password
if (hashedPassword.isEmpty()) {
doRequestPasswordSalt(); // ask salt to create hashedPassword, then log in
} else {
doHashedLogin(); // log in using hashed password instead
}
} else {
// TODO add setting for client to reject unhashed logins
setStatus(StatusLoggingIn);
Command_Login cmdLogin = generateCommandLogin();
if (!password.isEmpty()) {
qWarning() << "using plain text password to log in";
cmdLogin.set_password(password.toStdString());
}
PendingCommand *pend = prepareSessionCommand(cmdLogin);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(loginResponse(Response)));
sendCommand(pend);
}
}
void RemoteClient::doHashedLogin()
{
setStatus(StatusLoggingIn);
Command_Login cmdLogin = generateCommandLogin();
cmdLogin.set_hashed_password(hashedPassword.toStdString());
PendingCommand *pend = prepareSessionCommand(cmdLogin);
connect(pend, SIGNAL(finished(Response, CommandContainer, QVariant)), this, SLOT(loginResponse(Response)));
sendCommand(pend);
@@ -202,6 +267,23 @@ void RemoteClient::processConnectionClosedEvent(const Event_ConnectionClosed & /
doDisconnectFromServer();
}
void RemoteClient::passwordSaltResponse(const Response &response)
{
if (response.response_code() == Response::RespOk) {
const Response_PasswordSalt &resp = response.GetExtension(Response_PasswordSalt::ext);
auto passwordSalt = QString::fromStdString(resp.password_salt());
if (passwordSalt.isEmpty()) { // the server does not recognize the user but allows them to enter unregistered
password.clear(); // the password will not be used
doLogin();
} else {
hashedPassword = PasswordHasher::computeHash(password, passwordSalt);
doHashedLogin();
}
} else if (response.response_code() != Response::RespNotConnected) {
emit loginError(response.response_code(), {}, 0, {});
}
}
void RemoteClient::loginResponse(const Response &response)
{
const Response_Login &resp = response.GetExtension(Response_Login::ext);
@@ -311,7 +393,7 @@ void RemoteClient::readData()
ServerMessage newServerMessage;
newServerMessage.ParseFromArray(inputBuffer.data(), messageLength);
#ifdef QT_DEBUG
qDebug() << "IN" << messageLength << QString::fromStdString(newServerMessage.ShortDebugString());
qDebug().noquote() << "IN" << getSafeDebugString(newServerMessage);
#endif
inputBuffer.remove(0, messageLength);
messageInProgress = false;
@@ -329,7 +411,7 @@ void RemoteClient::websocketMessageReceived(const QByteArray &message)
ServerMessage newServerMessage;
newServerMessage.ParseFromArray(message.data(), message.length());
#ifdef QT_DEBUG
qDebug() << "IN" << messageLength << QString::fromStdString(newServerMessage.ShortDebugString());
qDebug().noquote() << "IN" << getSafeDebugString(newServerMessage);
#endif
processProtocolItem(newServerMessage);
}
@@ -342,7 +424,7 @@ void RemoteClient::sendCommandContainer(const CommandContainer &cont)
auto size = static_cast<unsigned int>(cont.ByteSize());
#endif
#ifdef QT_DEBUG
qDebug() << "OUT" << size << QString::fromStdString(cont.ShortDebugString());
qDebug().noquote() << "OUT" << getSafeDebugString(cont);
#endif
QByteArray buf;
@@ -384,6 +466,7 @@ void RemoteClient::doConnectToServer(const QString &hostname,
password = _password;
lastHostname = hostname;
lastPort = port;
hashedPassword.clear();
connectToHost(hostname, port);
setStatus(StatusConnecting);
@@ -394,7 +477,6 @@ void RemoteClient::doRegisterToServer(const QString &hostname,
const QString &_userName,
const QString &_password,
const QString &_email,
const int _gender,
const QString &_country,
const QString &_realname)
{
@@ -403,11 +485,11 @@ void RemoteClient::doRegisterToServer(const QString &hostname,
userName = _userName;
password = _password;
email = _email;
gender = _gender;
country = _country;
realName = _realname;
lastHostname = hostname;
lastPort = port;
hashedPassword.clear();
connectToHost(hostname, port);
setStatus(StatusRegistering);
@@ -484,11 +566,10 @@ void RemoteClient::registerToServer(const QString &hostname,
const QString &_userName,
const QString &_password,
const QString &_email,
const int _gender,
const QString &_country,
const QString &_realname)
{
emit sigRegisterToServer(hostname, port, _userName, _password, _email, _gender, _country, _realname);
emit sigRegisterToServer(hostname, port, _userName, _password, _email, _country, _realname);
}
void RemoteClient::activateToServer(const QString &_token)
@@ -510,7 +591,7 @@ QString RemoteClient::getSrvClientID(const QString &_hostname)
QHostAddress hostAddress = hostInfo.addresses().first();
srvClientID += hostAddress.toString();
} else {
qDebug() << "Warning: ClientID generation host lookup failure [" << hostInfo.errorString() << "]";
qWarning() << "ClientID generation host lookup failure [" << hostInfo.errorString() << "]";
srvClientID += _hostname;
}
QString uniqueServerClientID =
@@ -597,6 +678,7 @@ void RemoteClient::doSubmitForgotPasswordResetToServer(const QString &hostname,
lastPort = port;
token = _token.trimmed();
password = _newpassword;
hashedPassword.clear();
connectToHost(lastHostname, lastPort);
setStatus(StatusSubmitForgotPasswordReset);

View File

@@ -2,6 +2,7 @@
#define REMOTECLIENT_H
#include "abstractclient.h"
#include "pb/commands.pb.h"
#include <QTcpSocket>
#include <QWebSocket>
@@ -26,7 +27,6 @@ signals:
const QString &_userName,
const QString &_password,
const QString &_email,
int _gender,
const QString &_country,
const QString &_realname);
void sigActivateToServer(const QString &_token);
@@ -55,6 +55,7 @@ private slots:
void ping();
void processServerIdentificationEvent(const Event_ServerIdentification &event);
void processConnectionClosedEvent(const Event_ConnectionClosed &event);
void passwordSaltResponse(const Response &response);
void loginResponse(const Response &response);
void registerResponse(const Response &response);
void activateResponse(const Response &response);
@@ -65,10 +66,12 @@ private slots:
const QString &_userName,
const QString &_password,
const QString &_email,
int _gender,
const QString &_country,
const QString &_realname);
void doRequestPasswordSalt();
void doLogin();
void doHashedLogin();
Command_Login generateCommandLogin();
void doDisconnectFromServer();
void doActivateToServer(const QString &_token);
void doRequestForgotPasswordToServer(const QString &hostname, unsigned int port, const QString &_userName);
@@ -98,6 +101,7 @@ private:
QWebSocket *websocket;
QString lastHostname;
unsigned int lastPort;
QString hashedPassword;
QString getSrvClientID(const QString &_hostname);
bool newMissingFeatureFound(const QString &_serversMissingFeatures);
@@ -125,7 +129,6 @@ public:
const QString &_userName,
const QString &_password,
const QString &_email,
int _gender,
const QString &_country,
const QString &_realname);
void activateToServer(const QString &_token);

View File

@@ -221,7 +221,7 @@ void RemoteDeckList_TreeModel::addFileToTree(const ServerInfo_DeckStorage_TreeIt
{
const ServerInfo_DeckStorage_File &fileInfo = file.file();
QDateTime time;
time.setTime_t(fileInfo.creation_time());
time.setSecsSinceEpoch(fileInfo.creation_time());
beginInsertRows(nodeToIndex(parent), parent->size(), parent->size());
parent->append(new FileNode(QString::fromStdString(file.name()), file.id(), time, parent));

View File

@@ -111,7 +111,7 @@ QVariant RemoteReplayList_TreeModel::data(const QModelIndex &index, int role) co
return playerList.join(", ");
}
case 4:
return QDateTime::fromTime_t(matchInfo.time_started());
return QDateTime::fromSecsSinceEpoch(matchInfo.time_started());
case 5:
return matchInfo.length();
default:

View File

@@ -4,10 +4,6 @@
#include <QPainterPath>
#include <QPalette>
#include <QTimer>
#include <cmath>
#ifdef _WIN32
#include "round.h"
#endif /* _WIN32 */
ReplayTimelineWidget::ReplayTimelineWidget(QWidget *parent)
: QWidget(parent), maxBinValue(1), maxTime(1), timeScaleFactor(1.0), currentTime(0), currentEvent(0)
@@ -54,7 +50,7 @@ void ReplayTimelineWidget::paintEvent(QPaintEvent * /* event */)
QPainterPath path;
path.moveTo(0, height() - 1);
for (int i = 0; i < histogram.size(); ++i)
path.lineTo(round(i * binWidth), (height() - 1) * (1.0 - (qreal)histogram[i] / maxBinValue));
path.lineTo(qRound(i * binWidth), (height() - 1) * (1.0 - (qreal)histogram[i] / maxBinValue));
path.lineTo(width() - 1, height() - 1);
path.lineTo(0, height() - 1);
painter.fillPath(path, Qt::black);
@@ -66,7 +62,11 @@ void ReplayTimelineWidget::paintEvent(QPaintEvent * /* event */)
void ReplayTimelineWidget::mousePressEvent(QMouseEvent *event)
{
int newTime = static_cast<int>((long)maxTime * (long)event->x() / width());
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
int newTime = static_cast<int>((qint64)maxTime * (qint64)event->position().x() / width());
#else
int newTime = static_cast<int>((qint64)maxTime * (qint64)event->x() / width());
#endif
newTime -= newTime % 200; // Time should always be a multiple of 200
if (newTime < currentTime) {
currentTime = 0;

View File

@@ -1,13 +0,0 @@
#ifndef MSVC_ROUND_FIX
#define MSVC_ROUND_FIX
/**
* This helper function exists only because MS VC++ 2010 does not support round() in
* <cmath>. round() works with g++ and clang++ but is formally a C++11 extension.
* So this file exists for MS VC++ only.
*/
inline double round(double val)
{
return floor(val + 0.5);
}
#endif /* MSVC_ROUND_FIX */

View File

@@ -1,5 +1,7 @@
#include "setsmodel.h"
#include <QSortFilterProxyModel>
SetsModel::SetsModel(CardDatabase *_db, QObject *parent) : QAbstractTableModel(parent), sets(_db->getSetList())
{
sets.sortByKey();
@@ -274,9 +276,15 @@ bool SetsDisplayModel::filterAcceptsRow(int sourceRow, const QModelIndex &source
auto nameIndex = sourceModel()->index(sourceRow, SetsModel::LongNameCol, sourceParent);
auto shortNameIndex = sourceModel()->index(sourceRow, SetsModel::ShortNameCol, sourceParent);
return (sourceModel()->data(typeIndex).toString().contains(filterRegExp()) ||
sourceModel()->data(nameIndex).toString().contains(filterRegExp()) ||
sourceModel()->data(shortNameIndex).toString().contains(filterRegExp()));
#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0))
const auto filter = filterRegularExpression();
#else
const auto filter = filterRegExp();
#endif
return (sourceModel()->data(typeIndex).toString().contains(filter) ||
sourceModel()->data(nameIndex).toString().contains(filter) ||
sourceModel()->data(shortNameIndex).toString().contains(filter));
}
bool SetsDisplayModel::lessThan(const QModelIndex &left, const QModelIndex &right) const

View File

@@ -18,7 +18,7 @@ QString SettingsCache::getDataPath()
if (isPortableBuild)
return qApp->applicationDirPath() + "/data";
else
return QStandardPaths::writableLocation(QStandardPaths::DataLocation);
return QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
}
QString SettingsCache::getSettingsPath()
@@ -692,6 +692,7 @@ QStringList SettingsCache::getCountries() const
<< "er"
<< "es"
<< "et"
<< "eu"
<< "fi"
<< "fj"
<< "fk"
@@ -867,6 +868,7 @@ QStringList SettingsCache::getCountries() const
<< "vu"
<< "wf"
<< "ws"
<< "xk"
<< "ye"
<< "yt"
<< "za"

View File

@@ -20,7 +20,6 @@ class ReleaseChannel;
#define PIXMAPCACHE_SIZE_MIN 64
#define PIXMAPCACHE_SIZE_MAX 2047
#define DEFAULT_LANG_CODE "en"
#define DEFAULT_LANG_NAME "English"
#define CLIENT_INFO_NOT_SET "notset"

View File

@@ -2,21 +2,15 @@
#include "settingscache.h"
#include <QApplication>
#include <QAudioOutput>
#include <QBuffer>
#include <QDebug>
#include <QFileInfo>
#include <QLibraryInfo>
#include <QStandardPaths>
#include <QDir>
#include <QMediaPlayer>
#define DEFAULT_THEME_NAME "Default"
#define TEST_SOUND_FILENAME "player_join"
SoundEngine::SoundEngine(QObject *parent) : QObject(parent), player(0)
{
inputBuffer = new QBuffer(this);
ensureThemeDirectoryExists();
connect(&SettingsCache::instance(), SIGNAL(soundThemeChanged()), this, SLOT(themeChangedSlot()));
connect(&SettingsCache::instance(), SIGNAL(soundEnabledChanged()), this, SLOT(soundEnabledChanged()));
@@ -31,8 +25,6 @@ SoundEngine::~SoundEngine()
player->deleteLater();
player = 0;
}
inputBuffer->deleteLater();
}
void SoundEngine::soundEnabledChanged()
@@ -40,14 +32,11 @@ void SoundEngine::soundEnabledChanged()
if (SettingsCache::instance().getSoundEnabled()) {
qDebug("SoundEngine: enabling sound");
if (!player) {
QAudioFormat format;
format.setSampleRate(44100);
format.setChannelCount(1);
format.setSampleSize(16);
format.setCodec("audio/pcm");
format.setByteOrder(QAudioFormat::LittleEndian);
format.setSampleType(QAudioFormat::SignedInt);
player = new QAudioOutput(format, this);
player = new QMediaPlayer;
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
auto qAudioOutput = new QAudioOutput;
player->setAudioOutput(qAudioOutput);
#endif
}
} else {
qDebug("SoundEngine: disabling sound");
@@ -61,25 +50,35 @@ void SoundEngine::soundEnabledChanged()
void SoundEngine::playSound(QString fileName)
{
if (!player)
if (!player) {
return;
}
// still playing the previous sound?
if (player->state() == QAudio::ActiveState)
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
if (player->playbackState() == QMediaPlayer::PlaybackState::PlayingState) {
#else
if (player->state() == QMediaPlayer::PlayingState) {
#endif
return;
}
if (!audioData.contains(fileName))
if (!audioData.contains(fileName)) {
return;
}
qDebug() << "playing" << fileName;
inputBuffer->close();
inputBuffer->setData(audioData[fileName]);
inputBuffer->open(QIODevice::ReadOnly);
player->setVolume(SettingsCache::instance().getMasterVolume() / 100.0);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0))
player->audioOutput()->setVolume(SettingsCache::instance().getMasterVolume());
player->stop();
player->start(inputBuffer);
player->setSource(QUrl::fromLocalFile(audioData[fileName]));
#else
player->setVolume(SettingsCache::instance().getMasterVolume());
player->stop();
player->setMedia(QUrl::fromLocalFile(audioData[fileName]));
#endif
player->play();
}
void SoundEngine::testSound()
@@ -105,7 +104,7 @@ QStringMap &SoundEngine::getAvailableThemes()
dir.setPath(SettingsCache::instance().getDataPath() + "/sounds");
foreach (QString themeName, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
if (!availableThemes.contains(themeName))
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
}
@@ -121,7 +120,7 @@ QStringMap &SoundEngine::getAvailableThemes()
#endif
);
foreach (QString themeName, dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
for (const QString &themeName : dir.entryList(QDir::AllDirs | QDir::NoDotAndDotDot, QDir::Name)) {
if (!availableThemes.contains(themeName))
availableThemes.insert(themeName, dir.absoluteFilePath(themeName));
}
@@ -181,10 +180,7 @@ void SoundEngine::themeChangedSlot()
continue;
QFile file(dir.filePath(fileNames[i] + ".wav"));
file.open(QIODevice::ReadOnly);
// 44 = length of wav header
audioData.insert(fileNames[i], file.readAll().mid(44));
file.close();
audioData.insert(fileNames[i], file.fileName());
}
soundEnabledChanged();

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