mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-07-09 17:44:01 -07:00
Merge branch 'master' into 6269/ci/strip-fat-bins
This commit is contained in:
commit
04509150ae
183 changed files with 3199 additions and 2758 deletions
|
|
@ -122,7 +122,7 @@ if [[ $MAKE_SERVER ]]; then
|
||||||
flags+=("-DWITH_SERVER=1")
|
flags+=("-DWITH_SERVER=1")
|
||||||
fi
|
fi
|
||||||
if [[ $MAKE_NO_CLIENT ]]; then
|
if [[ $MAKE_NO_CLIENT ]]; then
|
||||||
flags+=("-DWITH_CLIENT=0" "-DWITH_ORACLE=0" "-DWITH_DBCONVERTER=0")
|
flags+=("-DWITH_CLIENT=0" "-DWITH_ORACLE=0")
|
||||||
fi
|
fi
|
||||||
if [[ $MAKE_TEST ]]; then
|
if [[ $MAKE_TEST ]]; then
|
||||||
flags+=("-DTEST=1")
|
flags+=("-DTEST=1")
|
||||||
|
|
@ -258,7 +258,7 @@ fi
|
||||||
|
|
||||||
if [[ $RUNNER_OS == macOS ]]; then
|
if [[ $RUNNER_OS == macOS ]]; then
|
||||||
echo "::group::Inspect Mach-O binaries"
|
echo "::group::Inspect Mach-O binaries"
|
||||||
for app in cockatrice oracle servatrice dbconverter; do
|
for app in cockatrice oracle servatrice; do
|
||||||
binary="$GITHUB_WORKSPACE/build/$app/$app.app/Contents/MacOS/$app"
|
binary="$GITHUB_WORKSPACE/build/$app/$app.app/Contents/MacOS/$app"
|
||||||
echo "Inspecting $app..."
|
echo "Inspecting $app..."
|
||||||
vtool -show-build "$binary"
|
vtool -show-build "$binary"
|
||||||
|
|
|
||||||
43
.github/workflows/desktop-build.yml
vendored
43
.github/workflows/desktop-build.yml
vendored
|
|
@ -142,7 +142,6 @@ jobs:
|
||||||
- distro: Ubuntu
|
- distro: Ubuntu
|
||||||
version: 22.04
|
version: 22.04
|
||||||
package: DEB
|
package: DEB
|
||||||
test: skip # Running tests on all distros is superfluous
|
|
||||||
|
|
||||||
- distro: Ubuntu
|
- distro: Ubuntu
|
||||||
version: 24.04
|
version: 24.04
|
||||||
|
|
@ -166,7 +165,7 @@ jobs:
|
||||||
|
|
||||||
- name: Restore compiler cache (ccache)
|
- name: Restore compiler cache (ccache)
|
||||||
id: ccache_restore
|
id: ccache_restore
|
||||||
uses: actions/cache/restore@v4
|
uses: actions/cache/restore@v5
|
||||||
env:
|
env:
|
||||||
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
with:
|
with:
|
||||||
|
|
@ -205,7 +204,7 @@ jobs:
|
||||||
|
|
||||||
- name: Save compiler cache (ccache)
|
- name: Save compiler cache (ccache)
|
||||||
if: github.ref == 'refs/heads/master'
|
if: github.ref == 'refs/heads/master'
|
||||||
uses: actions/cache/save@v4
|
uses: actions/cache/save@v5
|
||||||
with:
|
with:
|
||||||
path: ${{env.CACHE}}
|
path: ${{env.CACHE}}
|
||||||
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
key: ${{ steps.ccache_restore.outputs.cache-primary-key }}
|
||||||
|
|
@ -213,7 +212,7 @@ jobs:
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
id: upload_artifact
|
id: upload_artifact
|
||||||
if: matrix.package != 'skip'
|
if: matrix.package != 'skip'
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{matrix.distro}}${{matrix.version}}-package
|
name: ${{matrix.distro}}${{matrix.version}}-package
|
||||||
path: ${{steps.build.outputs.path}}
|
path: ${{steps.build.outputs.path}}
|
||||||
|
|
@ -336,6 +335,11 @@ jobs:
|
||||||
name: ${{matrix.os}} ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
name: ${{matrix.os}} ${{matrix.target}}${{ matrix.soc == 'Intel' && ' Intel' || '' }}${{ matrix.type == 'Debug' && ' Debug' || '' }}
|
||||||
needs: configure
|
needs: configure
|
||||||
runs-on: ${{matrix.runner}}
|
runs-on: ${{matrix.runner}}
|
||||||
|
env:
|
||||||
|
CCACHE_DIR: ${{github.workspace}}/.cache/
|
||||||
|
# Cache size over the entire repo is 10Gi:
|
||||||
|
# https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows#usage-limits-and-eviction-policy
|
||||||
|
CCACHE_SIZE: 500M
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
|
|
@ -350,16 +354,20 @@ jobs:
|
||||||
with:
|
with:
|
||||||
msbuild-architecture: x64
|
msbuild-architecture: x64
|
||||||
|
|
||||||
# Using jianmingyong/ccache-action to setup ccache without using brew
|
|
||||||
# It tries to download a binary of ccache from GitHub Release and falls back to building from source if it fails
|
|
||||||
- name: Setup ccache
|
- name: Setup ccache
|
||||||
|
if: matrix.use_ccache == 1 && matrix.os == 'macOS'
|
||||||
|
run: brew install ccache
|
||||||
|
|
||||||
|
- name: Restore compiler cache (ccache)
|
||||||
if: matrix.use_ccache == 1
|
if: matrix.use_ccache == 1
|
||||||
uses: jianmingyong/ccache-action@v1
|
id: ccache_restore
|
||||||
|
uses: actions/cache/restore@v5
|
||||||
|
env:
|
||||||
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
with:
|
with:
|
||||||
install-type: "binary"
|
path: ${{env.CCACHE_DIR}}
|
||||||
ccache-key-prefix: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}
|
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
||||||
max-size: 500M
|
restore-keys: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-
|
||||||
gh-token: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
|
|
||||||
- name: Restore thin Qt ${{matrix.qt_version}} libraries
|
- name: Restore thin Qt ${{matrix.qt_version}} libraries
|
||||||
if: matrix.os == 'macOS'
|
if: matrix.os == 'macOS'
|
||||||
|
|
@ -429,6 +437,15 @@ jobs:
|
||||||
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
TARGET_MACOS_VERSION: ${{ matrix.override_target }}
|
||||||
run: .ci/compile.sh --server --test --vcpkg
|
run: .ci/compile.sh --server --test --vcpkg
|
||||||
|
|
||||||
|
- name: Save compiler cache (ccache)
|
||||||
|
if: github.ref == 'refs/heads/master' && matrix.use_ccache == 1
|
||||||
|
uses: actions/cache/save@v5
|
||||||
|
env:
|
||||||
|
BRANCH_NAME: ${{ github.head_ref || github.ref_name }}
|
||||||
|
with:
|
||||||
|
path: ${{env.CCACHE_DIR}}
|
||||||
|
key: ccache-${{matrix.runner}}-${{matrix.soc}}-${{matrix.type}}-${{env.BRANCH_NAME}}
|
||||||
|
|
||||||
- name: Sign app bundle
|
- name: Sign app bundle
|
||||||
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
if: matrix.os == 'macOS' && matrix.make_package && (github.ref == 'refs/heads/master' || needs.configure.outputs.tag != null)
|
||||||
env:
|
env:
|
||||||
|
|
@ -476,7 +493,7 @@ jobs:
|
||||||
- name: Upload artifact
|
- name: Upload artifact
|
||||||
id: upload_artifact
|
id: upload_artifact
|
||||||
if: matrix.make_package
|
if: matrix.make_package
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: ${{matrix.artifact_name}}
|
name: ${{matrix.artifact_name}}
|
||||||
path: ${{steps.build.outputs.path}}
|
path: ${{steps.build.outputs.path}}
|
||||||
|
|
@ -484,7 +501,7 @@ jobs:
|
||||||
|
|
||||||
- name: Upload pdb database
|
- name: Upload pdb database
|
||||||
if: matrix.os == 'Windows'
|
if: matrix.os == 'Windows'
|
||||||
uses: actions/upload-artifact@v5
|
uses: actions/upload-artifact@v6
|
||||||
with:
|
with:
|
||||||
name: Windows${{matrix.target}}-debug-pdbs
|
name: Windows${{matrix.target}}-debug-pdbs
|
||||||
path: |
|
path: |
|
||||||
|
|
|
||||||
2
.github/workflows/translations-pull.yml
vendored
2
.github/workflows/translations-pull.yml
vendored
|
|
@ -33,7 +33,7 @@ jobs:
|
||||||
- name: Create pull request
|
- name: Create pull request
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
id: create_pr
|
id: create_pr
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v8
|
||||||
with:
|
with:
|
||||||
add-paths: |
|
add-paths: |
|
||||||
cockatrice/translations/*.ts
|
cockatrice/translations/*.ts
|
||||||
|
|
|
||||||
2
.github/workflows/translations-push.yml
vendored
2
.github/workflows/translations-push.yml
vendored
|
|
@ -57,7 +57,7 @@ jobs:
|
||||||
- name: Create pull request
|
- name: Create pull request
|
||||||
if: github.event_name != 'pull_request'
|
if: github.event_name != 'pull_request'
|
||||||
id: create_pr
|
id: create_pr
|
||||||
uses: peter-evans/create-pull-request@v7
|
uses: peter-evans/create-pull-request@v8
|
||||||
with:
|
with:
|
||||||
add-paths: |
|
add-paths: |
|
||||||
cockatrice/cockatrice_en@source.ts
|
cockatrice/cockatrice_en@source.ts
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,6 @@ option(WITH_SERVER "build servatrice" OFF)
|
||||||
option(WITH_CLIENT "build cockatrice" ON)
|
option(WITH_CLIENT "build cockatrice" ON)
|
||||||
# Compile oracle
|
# Compile oracle
|
||||||
option(WITH_ORACLE "build oracle" ON)
|
option(WITH_ORACLE "build oracle" ON)
|
||||||
# Compile dbconverter
|
|
||||||
option(WITH_DBCONVERTER "build dbconverter" ON)
|
|
||||||
# Compile tests
|
# Compile tests
|
||||||
option(TEST "build tests" OFF)
|
option(TEST "build tests" OFF)
|
||||||
# Use vcpkg regardless of OS
|
# Use vcpkg regardless of OS
|
||||||
|
|
@ -356,11 +354,6 @@ if(WITH_ORACLE)
|
||||||
set(CPACK_INSTALL_CMAKE_PROJECTS "Oracle;Oracle;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
|
set(CPACK_INSTALL_CMAKE_PROJECTS "Oracle;Oracle;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WITH_DBCONVERTER)
|
|
||||||
add_subdirectory(dbconverter)
|
|
||||||
set(CPACK_INSTALL_CMAKE_PROJECTS "Dbconverter;Dbconverter;ALL;/" ${CPACK_INSTALL_CMAKE_PROJECTS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(TEST)
|
if(TEST)
|
||||||
include(CTest)
|
include(CTest)
|
||||||
add_subdirectory(tests)
|
add_subdirectory(tests)
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||||
WORKDIR /src
|
WORKDIR /src
|
||||||
COPY . .
|
COPY . .
|
||||||
RUN mkdir build && cd build && \
|
RUN mkdir build && cd build && \
|
||||||
cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 -DWITH_DBCONVERTER=0 && \
|
cmake .. -DWITH_SERVER=1 -DWITH_CLIENT=0 -DWITH_ORACLE=0 && \
|
||||||
make -j$(nproc) && \
|
make -j$(nproc) && \
|
||||||
make install
|
make install
|
||||||
|
|
||||||
|
|
|
||||||
1
Doxyfile
1
Doxyfile
|
|
@ -1068,7 +1068,6 @@ RECURSIVE = YES
|
||||||
|
|
||||||
EXCLUDE = build/ \
|
EXCLUDE = build/ \
|
||||||
cmake/ \
|
cmake/ \
|
||||||
dbconverter/ \
|
|
||||||
vcpkg/ \
|
vcpkg/ \
|
||||||
webclient/
|
webclient/
|
||||||
|
|
||||||
|
|
|
||||||
53
README.md
53
README.md
|
|
@ -44,10 +44,10 @@ Latest <kbd>beta</kbd> version:
|
||||||
|
|
||||||
# Related Repositories
|
# Related Repositories
|
||||||
|
|
||||||
- [Magic-Token](https://github.com/Cockatrice/Magic-Token): MtG token data to use in Cockatrice
|
- [Magic-Token](https://github.com/Cockatrice/Magic-Token): File with MtG token data for use in Cockatrice
|
||||||
- [Magic-Spoiler](https://github.com/Cockatrice/Magic-Spoiler): Script to generate MtG spoiler data from [MTGJSON](https://github.com/mtgjson/mtgjson) to use in Cockatrice
|
- [Magic-Spoiler](https://github.com/Cockatrice/Magic-Spoiler): Code to generate MtG spoiler data from [MTGJSON](https://github.com/mtgjson/mtgjson) for use in Cockatrice
|
||||||
- [cockatrice.github.io](https://github.com/Cockatrice/cockatrice.github.io): Code of the official Cockatrice webpage
|
- [cockatrice.github.io](https://github.com/Cockatrice/cockatrice.github.io): Code of the official Cockatrice webpage
|
||||||
- [Cockatrice @Flathub](https://github.com/flathub/io.github.Cockatrice.cockatrice): Configuration for our Linux `flatpak` package
|
- [io.github.Cockatrice.cockatrice](https://github.com/flathub/io.github.Cockatrice.cockatrice): Configuration of our Linux `flatpak` package hosted at [Flathub](https://flathub.org/en/apps/io.github.Cockatrice.cockatrice)
|
||||||
|
|
||||||
|
|
||||||
# Community Resources [](https://discord.gg/3Z9yzmA)
|
# Community Resources [](https://discord.gg/3Z9yzmA)
|
||||||
|
|
@ -55,15 +55,31 @@ Latest <kbd>beta</kbd> version:
|
||||||
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with other projet contributors (`#dev` channel) or fellow users of the app. Come here to talk about the application, features, or just to hang out.
|
Join our [Discord community](https://discord.gg/3Z9yzmA) to connect with other projet contributors (`#dev` channel) or fellow users of the app. Come here to talk about the application, features, or just to hang out.
|
||||||
- [Official Website](https://cockatrice.github.io)
|
- [Official Website](https://cockatrice.github.io)
|
||||||
- [Official Wiki](https://github.com/Cockatrice/Cockatrice/wiki)
|
- [Official Wiki](https://github.com/Cockatrice/Cockatrice/wiki)
|
||||||
- [Official Code Documentation](https://cockatrice.github.io/docs)
|
|
||||||
- [Official Discord](https://discord.gg/3Z9yzmA)
|
- [Official Discord](https://discord.gg/3Z9yzmA)
|
||||||
- [reddit r/Cockatrice](https://reddit.com/r/cockatrice)
|
- [reddit r/Cockatrice](https://reddit.com/r/cockatrice)
|
||||||
|
|
||||||
>[!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
>For support regarding specific servers, please contact that server's admin/mods and use their dedicated communication channels rather than contacting the team building the software.
|
> For support regarding specific servers, please contact that server's admin/mods and use their dedicated communication channels rather than contacting the team building the software.
|
||||||
|
|
||||||
|
|
||||||
# Contribute
|
# Contribute
|
||||||
|
<p>
|
||||||
|
<a href="#code">Code</a> <b>|</b>
|
||||||
|
<a href="#documentation-">Documentation</a> <b>|</b>
|
||||||
|
<a href="#translation-">Translation</a>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
#### Repository Activity
|
||||||
|

|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Kudos to all our amazing contributors ❤️</b></summary>
|
||||||
|
<br>
|
||||||
|
<a href="https://github.com/Cockatrice/Cockatrice/graphs/contributors">
|
||||||
|
<img src="https://contrib.rocks/image?repo=Cockatrice/Cockatrice" />
|
||||||
|
</a><br>
|
||||||
|
<sub><i>Made with <a href="https://contrib.rocks">contrib.rocks</a></i></sub>
|
||||||
|
</details>
|
||||||
|
|
||||||
### Code
|
### Code
|
||||||
|
|
||||||
|
|
@ -77,18 +93,19 @@ This tag is used for issues that we are looking for somebody to pick up. Often t
|
||||||
For both tags, we're willing to provide help to contributors in showing them where and how they can make changes, as well as code reviews for submitted changes.<br>
|
For both tags, we're willing to provide help to contributors in showing them where and how they can make changes, as well as code reviews for submitted changes.<br>
|
||||||
We'll happily advice on how best to implement a feature, or we can show you where the codebase is doing something similar before you get too far along - put a note on an issue you want to discuss more on!
|
We'll happily advice on how best to implement a feature, or we can show you where the codebase is doing something similar before you get too far along - put a note on an issue you want to discuss more on!
|
||||||
|
|
||||||
|
You can also have a look at our `Todo List` in our [Code Documentation](https://cockatrice.github.io/docs) or search the repo for [`\todo` comments](https://github.com/search?q=repo%3ACockatrice%2FCockatrice%20%5Ctodo&type=code).
|
||||||
|
|
||||||
|
### Documentation [](https://github.com/Cockatrice/Cockatrice/actions/workflows/documentation-build.yml?query=event%3Apush)
|
||||||
|
|
||||||
|
There are various places where useful information for different needs are maintained:
|
||||||
|
- [Official Code Documentation](https://cockatrice.github.io/docs/)
|
||||||
|
- [Official Wiki](https://github.com/Cockatrice/Cockatrice/wiki) `Community supported`
|
||||||
|
- [Official Webpage](https://cockatrice.github.io/)
|
||||||
|
- [Official README](https://github.com/Cockatrice/Cockatrice/blob/master/README.md) `This file`
|
||||||
|
|
||||||
Cockatrice tries to use the [Google Developer Documentation Style Guide](https://developers.google.com/style/) to ensure consistent documentation. We encourage you to improve the documentation by suggesting edits based on this guide.
|
Cockatrice tries to use the [Google Developer Documentation Style Guide](https://developers.google.com/style/) to ensure consistent documentation. We encourage you to improve the documentation by suggesting edits based on this guide.
|
||||||
|
|
||||||
<details>
|
### Translation [](https://explore.transifex.com/cockatrice/cockatrice/)
|
||||||
<summary><b>Kudos to our amazing contributors ❤️</b></summary>
|
|
||||||
<br>
|
|
||||||
<a href="https://github.com/Cockatrice/Cockatrice/graphs/contributors">
|
|
||||||
<img src="https://contrib.rocks/image?repo=Cockatrice/Cockatrice" />
|
|
||||||
</a><br>
|
|
||||||
<sub><i>Made with <a href="https://contrib.rocks">contrib.rocks</a></i></sub>
|
|
||||||
</details>
|
|
||||||
|
|
||||||
### Translations [](https://explore.transifex.com/cockatrice/cockatrice/)
|
|
||||||
|
|
||||||
Cockatrice uses Transifex to manage translations. You can help us bring <kbd>Cockatrice</kbd>, <kbd>Oracle</kbd> and <kbd>Webatrice</kbd> to your language and just adjust single wordings right from within your browser by visiting our [Transifex project page](https://explore.transifex.com/cockatrice/cockatrice/).<br>
|
Cockatrice uses Transifex to manage translations. You can help us bring <kbd>Cockatrice</kbd>, <kbd>Oracle</kbd> and <kbd>Webatrice</kbd> to your language and just adjust single wordings right from within your browser by visiting our [Transifex project page](https://explore.transifex.com/cockatrice/cockatrice/).<br>
|
||||||
|
|
||||||
|
|
@ -126,8 +143,8 @@ You can then
|
||||||
make package
|
make package
|
||||||
```
|
```
|
||||||
|
|
||||||
>[!NOTE]
|
> [!NOTE]
|
||||||
>Detailed compiling instructions can be found in the Cockatrice wiki at [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)
|
> Detailed compiling instructions can be found in the Cockatrice wiki at [Compiling Cockatrice](https://github.com/Cockatrice/Cockatrice/wiki/Compiling-Cockatrice)
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,6 @@ tell disk image_name
|
||||||
set position of item "Cockatrice.app" to { 139, 214 }
|
set position of item "Cockatrice.app" to { 139, 214 }
|
||||||
set position of item "Oracle.app" to { 139, 414 }
|
set position of item "Oracle.app" to { 139, 414 }
|
||||||
set position of item "Servatrice.app" to { 139, 614 }
|
set position of item "Servatrice.app" to { 139, 614 }
|
||||||
set position of item "dbconverter.app" to { 1400, 1400 }
|
|
||||||
set position of item "Applications" to { 861, 414 }
|
set position of item "Applications" to { 861, 414 }
|
||||||
end tell
|
end tell
|
||||||
update without registering applications
|
update without registering applications
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,11 @@
|
||||||
# Find a compatible Qt version
|
# Find a compatible Qt version
|
||||||
# Inputs: WITH_SERVER, WITH_CLIENT, WITH_ORACLE, WITH_DBCONVERTER, FORCE_USE_QT5
|
# Inputs: WITH_SERVER, WITH_CLIENT, WITH_ORACLE, FORCE_USE_QT5
|
||||||
# Optional Input: QT6_DIR -- Hint as to where Qt6 lives on the system
|
# 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
|
# Optional Input: QT5_DIR -- Hint as to where Qt5 lives on the system
|
||||||
# Output: COCKATRICE_QT_VERSION_NAME -- Example values: Qt5, Qt6
|
# Output: COCKATRICE_QT_VERSION_NAME -- Example values: Qt5, Qt6
|
||||||
# Output: SERVATRICE_QT_MODULES
|
# Output: SERVATRICE_QT_MODULES
|
||||||
# Output: COCKATRICE_QT_MODULES
|
# Output: COCKATRICE_QT_MODULES
|
||||||
# Output: ORACLE_QT_MODULES
|
# Output: ORACLE_QT_MODULES
|
||||||
# Output: DBCONVERTER_QT_MODULES
|
|
||||||
# Output: TEST_QT_MODULES
|
# Output: TEST_QT_MODULES
|
||||||
|
|
||||||
set(REQUIRED_QT_COMPONENTS Core)
|
set(REQUIRED_QT_COMPONENTS Core)
|
||||||
|
|
@ -29,15 +28,12 @@ endif()
|
||||||
if(WITH_ORACLE)
|
if(WITH_ORACLE)
|
||||||
set(_ORACLE_NEEDED Concurrent Network Svg Widgets)
|
set(_ORACLE_NEEDED Concurrent Network Svg Widgets)
|
||||||
endif()
|
endif()
|
||||||
if(WITH_DBCONVERTER)
|
|
||||||
set(_DBCONVERTER_NEEDED Network Widgets)
|
|
||||||
endif()
|
|
||||||
if(TEST)
|
if(TEST)
|
||||||
set(_TEST_NEEDED Widgets)
|
set(_TEST_NEEDED Widgets)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
set(REQUIRED_QT_COMPONENTS ${REQUIRED_QT_COMPONENTS} ${_SERVATRICE_NEEDED} ${_COCKATRICE_NEEDED} ${_ORACLE_NEEDED}
|
set(REQUIRED_QT_COMPONENTS ${REQUIRED_QT_COMPONENTS} ${_SERVATRICE_NEEDED} ${_COCKATRICE_NEEDED} ${_ORACLE_NEEDED}
|
||||||
${_DBCONVERTER_NEEDED} ${_TEST_NEEDED}
|
${_TEST_NEEDED}
|
||||||
)
|
)
|
||||||
list(REMOVE_DUPLICATES REQUIRED_QT_COMPONENTS)
|
list(REMOVE_DUPLICATES REQUIRED_QT_COMPONENTS)
|
||||||
|
|
||||||
|
|
@ -63,7 +59,7 @@ if(Qt6_FOUND)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
find_package(
|
find_package(
|
||||||
Qt5 5.8.0
|
Qt5 5.15.2
|
||||||
COMPONENTS ${REQUIRED_QT_COMPONENTS}
|
COMPONENTS ${REQUIRED_QT_COMPONENTS}
|
||||||
QUIET HINTS ${Qt5_DIR}
|
QUIET HINTS ${Qt5_DIR}
|
||||||
)
|
)
|
||||||
|
|
@ -112,7 +108,6 @@ message(DEBUG "QT_LIBRARY_DIR = ${QT_LIBRARY_DIR}")
|
||||||
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" SERVATRICE_QT_MODULES "${_SERVATRICE_NEEDED}")
|
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" 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" 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}")
|
string(REGEX REPLACE "([^;]+)" "${COCKATRICE_QT_VERSION_NAME}::\\1" TEST_QT_MODULES "${_TEST_NEEDED}")
|
||||||
|
|
||||||
# Core-only export (useful for headless libs)
|
# Core-only export (useful for headless libs)
|
||||||
|
|
|
||||||
|
|
@ -213,7 +213,6 @@ ${AndIf} ${FileExists} "$INSTDIR\portable.dat"
|
||||||
Delete "$INSTDIR\uninstall.exe"
|
Delete "$INSTDIR\uninstall.exe"
|
||||||
Delete "$INSTDIR\cockatrice.exe"
|
Delete "$INSTDIR\cockatrice.exe"
|
||||||
Delete "$INSTDIR\oracle.exe"
|
Delete "$INSTDIR\oracle.exe"
|
||||||
Delete "$INSTDIR\dbconverter.exe"
|
|
||||||
Delete "$INSTDIR\servatrice.exe"
|
Delete "$INSTDIR\servatrice.exe"
|
||||||
Delete "$INSTDIR\Qt*.dll"
|
Delete "$INSTDIR\Qt*.dll"
|
||||||
Delete "$INSTDIR\libmysql.dll"
|
Delete "$INSTDIR\libmysql.dll"
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@
|
||||||
string(LENGTH "$ENV{MACOS_CERTIFICATE_NAME}" MACOS_CERTIFICATE_NAME_LEN)
|
string(LENGTH "$ENV{MACOS_CERTIFICATE_NAME}" MACOS_CERTIFICATE_NAME_LEN)
|
||||||
|
|
||||||
if(APPLE AND MACOS_CERTIFICATE_NAME_LEN GREATER 0)
|
if(APPLE AND MACOS_CERTIFICATE_NAME_LEN GREATER 0)
|
||||||
set(APPLICATIONS "cockatrice" "servatrice" "oracle" "dbconverter")
|
set(APPLICATIONS "cockatrice" "servatrice" "oracle")
|
||||||
foreach(app_name IN LISTS APPLICATIONS)
|
foreach(app_name IN LISTS APPLICATIONS)
|
||||||
set(FULL_APP_PATH "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/${app_name}.app")
|
set(FULL_APP_PATH "${CPACK_TEMPORARY_INSTALL_DIRECTORY}/${app_name}.app")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_filter_dock_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
|
src/interface/widgets/deck_editor/deck_editor_printing_selector_dock_widget.cpp
|
||||||
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
|
src/interface/widgets/deck_editor/deck_list_style_proxy.cpp
|
||||||
|
src/interface/widgets/deck_editor/deck_state_manager.cpp
|
||||||
src/interface/widgets/general/background_sources.cpp
|
src/interface/widgets/general/background_sources.cpp
|
||||||
src/interface/widgets/general/display/background_plate_widget.cpp
|
src/interface/widgets/general/display/background_plate_widget.cpp
|
||||||
src/interface/widgets/general/display/banner_widget.cpp
|
src/interface/widgets/general/display/banner_widget.cpp
|
||||||
|
|
@ -230,6 +231,7 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/tabs/abstract_tab_deck_editor.cpp
|
src/interface/widgets/tabs/abstract_tab_deck_editor.cpp
|
||||||
src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp
|
src/interface/widgets/tabs/api/archidekt/tab_archidekt.cpp
|
||||||
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_deck_listing_api_response.cpp
|
||||||
|
src/interface/widgets/tabs/api/archidekt/api_response/archidekt_formats.h
|
||||||
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card.cpp
|
||||||
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_card_entry.cpp
|
||||||
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp
|
src/interface/widgets/tabs/api/archidekt/api_response/card/archidekt_api_response_edition.cpp
|
||||||
|
|
@ -286,6 +288,10 @@ set(cockatrice_SOURCES
|
||||||
src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
|
src/interface/widgets/tabs/visual_deck_storage/tab_deck_storage_visual.cpp
|
||||||
src/interface/key_signals.cpp
|
src/interface/key_signals.cpp
|
||||||
src/interface/logger.cpp
|
src/interface/logger.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_bracket_navigation_widget.h
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.cpp
|
||||||
|
src/interface/widgets/tabs/api/edhrec/display/commander/edhrec_commander_api_response_budget_navigation_widget.h
|
||||||
)
|
)
|
||||||
|
|
||||||
add_subdirectory(sounds)
|
add_subdirectory(sounds)
|
||||||
|
|
|
||||||
|
|
@ -15,15 +15,18 @@ searches are case insensitive.
|
||||||
<dd>[n:red n:deck n:wins](#n:red n:deck n:wins) <small>(Any deck with a name containing the words red, deck, and wins)</small></dd>
|
<dd>[n:red n:deck n:wins](#n:red n:deck n:wins) <small>(Any deck with a name containing the words red, deck, and wins)</small></dd>
|
||||||
<dd>[n:"red deck wins"](#n:%22red deck wins%22) <small>(Any deck with a name containing the exact phrase "red deck wins")</small></dd>
|
<dd>[n:"red deck wins"](#n:%22red deck wins%22) <small>(Any deck with a name containing the exact phrase "red deck wins")</small></dd>
|
||||||
|
|
||||||
<dt><u>F</u>ile Name:</dt>
|
<dt><u>F</u>ile <u>N</u>ame:</dt>
|
||||||
<dd>[f:aggro](#f:aggro) <small>(Any deck with a filename containing the word aggro)</small></dd>
|
<dd>[fn:aggro](#fn:aggro) <small>(Any deck with a filename containing the word aggro)</small></dd>
|
||||||
<dd>[f:red f:deck f:wins](#f:red f:deck f:wins) <small>(Any deck with a filename containing the words red, deck, and wins)</small></dd>
|
<dd>[fn:red fn:deck fn:wins](#fn:red fn:deck fn:wins) <small>(Any deck with a filename containing the words red, deck, and wins)</small></dd>
|
||||||
<dd>[f:"red deck wins"](#f:%22red deck wins%22) <small>(Any deck with a filename containing the exact phrase "red deck wins")</small></dd>
|
<dd>[fn:"red deck wins"](#fn:%22red deck wins%22) <small>(Any deck with a filename containing the exact phrase "red deck wins")</small></dd>
|
||||||
|
|
||||||
<dt>Relative <u>P</u>ath (starting from the deck folder):</dt>
|
<dt>Relative <u>P</u>ath (starting from the deck folder):</dt>
|
||||||
<dd>[p:aggro](#p:aggro) <small>(Any deck that has "aggro" somewhere in its relative path)</small></dd>
|
<dd>[p:aggro](#p:aggro) <small>(Any deck that has "aggro" somewhere in its relative path)</small></dd>
|
||||||
<dd>[p:edh/](#p:edh/) <small>(Any deck with "edh/" in its relative path, A.K.A. decks in the "edh" folder)</small></dd>
|
<dd>[p:edh/](#p:edh/) <small>(Any deck with "edh/" in its relative path, A.K.A. decks in the "edh" folder)</small></dd>
|
||||||
|
|
||||||
|
<dt><u>F</u>ormat:</dt>
|
||||||
|
<dd>[f:standard](#f:standard) <small>(Any deck with format set to standard)</small></dd>
|
||||||
|
|
||||||
<dt>Deck Contents (Uses [card search expressions](#cardSearchSyntaxHelp)):</dt>
|
<dt>Deck Contents (Uses [card search expressions](#cardSearchSyntaxHelp)):</dt>
|
||||||
<dd><a href="#[[plains]]">[[plains]]</a> <small>(Any deck that contains at least one card with "plains" in its name)</small></dd>
|
<dd><a href="#[[plains]]">[[plains]]</a> <small>(Any deck that contains at least one card with "plains" in its name)</small></dd>
|
||||||
<dd><a href="#[[t:legendary]]">[[t:legendary]]</a> <small>(Any deck that contains at least one legendary)</small></dd>
|
<dd><a href="#[[t:legendary]]">[[t:legendary]]</a> <small>(Any deck that contains at least one legendary)</small></dd>
|
||||||
|
|
|
||||||
|
|
@ -43,23 +43,23 @@ void DeckStatsInterface::queryFinished(QNetworkReply *reply)
|
||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckStatsInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
|
void DeckStatsInterface::getAnalyzeRequestData(const DeckList &deck, QByteArray &data)
|
||||||
{
|
{
|
||||||
DeckList deckWithoutTokens;
|
DeckList deckWithoutTokens;
|
||||||
copyDeckWithoutTokens(*deck, deckWithoutTokens);
|
copyDeckWithoutTokens(deck, deckWithoutTokens);
|
||||||
|
|
||||||
QUrl params;
|
QUrl params;
|
||||||
QUrlQuery urlQuery;
|
QUrlQuery urlQuery;
|
||||||
urlQuery.addQueryItem("deck", deckWithoutTokens.writeToString_Plain());
|
urlQuery.addQueryItem("deck", deckWithoutTokens.writeToString_Plain());
|
||||||
urlQuery.addQueryItem("decktitle", deck->getName());
|
urlQuery.addQueryItem("decktitle", deck.getName());
|
||||||
params.setQuery(urlQuery);
|
params.setQuery(urlQuery);
|
||||||
data->append(params.query(QUrl::EncodeReserved).toUtf8());
|
data.append(params.query(QUrl::EncodeReserved).toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckStatsInterface::analyzeDeck(DeckList *deck)
|
void DeckStatsInterface::analyzeDeck(const DeckList &deck)
|
||||||
{
|
{
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
getAnalyzeRequestData(deck, &data);
|
getAnalyzeRequestData(deck, data);
|
||||||
|
|
||||||
QNetworkRequest request(QUrl("https://deckstats.net/index.php"));
|
QNetworkRequest request(QUrl("https://deckstats.net/index.php"));
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
|
@ -68,7 +68,7 @@ void DeckStatsInterface::analyzeDeck(DeckList *deck)
|
||||||
manager->post(request, data);
|
manager->post(request, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckStatsInterface::copyDeckWithoutTokens(DeckList &source, DeckList &destination)
|
void DeckStatsInterface::copyDeckWithoutTokens(const DeckList &source, DeckList &destination)
|
||||||
{
|
{
|
||||||
auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
|
auto copyIfNotAToken = [this, &destination](const auto node, const auto card) {
|
||||||
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
|
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
|
||||||
|
|
|
||||||
|
|
@ -28,15 +28,15 @@ private:
|
||||||
* closest non-token card instead. So we construct a new deck which has no
|
* closest non-token card instead. So we construct a new deck which has no
|
||||||
* tokens.
|
* tokens.
|
||||||
*/
|
*/
|
||||||
void copyDeckWithoutTokens(DeckList &source, DeckList &destination);
|
void copyDeckWithoutTokens(const DeckList &source, DeckList &destination);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void queryFinished(QNetworkReply *reply);
|
void queryFinished(QNetworkReply *reply);
|
||||||
void getAnalyzeRequestData(DeckList *deck, QByteArray *data);
|
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
|
explicit DeckStatsInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
|
||||||
void analyzeDeck(DeckList *deck);
|
void analyzeDeck(const DeckList &deck);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -67,24 +67,24 @@ void TappedOutInterface::queryFinished(QNetworkReply *reply)
|
||||||
deleteLater();
|
deleteLater();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TappedOutInterface::getAnalyzeRequestData(DeckList *deck, QByteArray *data)
|
void TappedOutInterface::getAnalyzeRequestData(const DeckList &deck, QByteArray &data)
|
||||||
{
|
{
|
||||||
DeckList mainboard, sideboard;
|
DeckList mainboard, sideboard;
|
||||||
copyDeckSplitMainAndSide(*deck, mainboard, sideboard);
|
copyDeckSplitMainAndSide(deck, mainboard, sideboard);
|
||||||
|
|
||||||
QUrl params;
|
QUrl params;
|
||||||
QUrlQuery urlQuery;
|
QUrlQuery urlQuery;
|
||||||
urlQuery.addQueryItem("name", deck->getName());
|
urlQuery.addQueryItem("name", deck.getName());
|
||||||
urlQuery.addQueryItem("mainboard", mainboard.writeToString_Plain(false, true));
|
urlQuery.addQueryItem("mainboard", mainboard.writeToString_Plain(false, true));
|
||||||
urlQuery.addQueryItem("sideboard", sideboard.writeToString_Plain(false, true));
|
urlQuery.addQueryItem("sideboard", sideboard.writeToString_Plain(false, true));
|
||||||
params.setQuery(urlQuery);
|
params.setQuery(urlQuery);
|
||||||
data->append(params.query(QUrl::EncodeReserved).toUtf8());
|
data.append(params.query(QUrl::EncodeReserved).toUtf8());
|
||||||
}
|
}
|
||||||
|
|
||||||
void TappedOutInterface::analyzeDeck(DeckList *deck)
|
void TappedOutInterface::analyzeDeck(const DeckList &deck)
|
||||||
{
|
{
|
||||||
QByteArray data;
|
QByteArray data;
|
||||||
getAnalyzeRequestData(deck, &data);
|
getAnalyzeRequestData(deck, data);
|
||||||
|
|
||||||
QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/"));
|
QNetworkRequest request(QUrl("https://tappedout.net/mtg-decks/paste/"));
|
||||||
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
|
||||||
|
|
@ -93,7 +93,7 @@ void TappedOutInterface::analyzeDeck(DeckList *deck)
|
||||||
manager->post(request, data);
|
manager->post(request, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TappedOutInterface::copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard)
|
void TappedOutInterface::copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard)
|
||||||
{
|
{
|
||||||
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
|
auto copyMainOrSide = [this, &mainboard, &sideboard](const auto node, const auto card) {
|
||||||
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
|
CardInfoPtr dbCard = cardDatabase.query()->getCardInfo(card->getName());
|
||||||
|
|
|
||||||
|
|
@ -30,14 +30,14 @@ private:
|
||||||
QNetworkAccessManager *manager;
|
QNetworkAccessManager *manager;
|
||||||
|
|
||||||
CardDatabase &cardDatabase;
|
CardDatabase &cardDatabase;
|
||||||
void copyDeckSplitMainAndSide(DeckList &source, DeckList &mainboard, DeckList &sideboard);
|
void copyDeckSplitMainAndSide(const DeckList &source, DeckList &mainboard, DeckList &sideboard);
|
||||||
private slots:
|
private slots:
|
||||||
void queryFinished(QNetworkReply *reply);
|
void queryFinished(QNetworkReply *reply);
|
||||||
void getAnalyzeRequestData(DeckList *deck, QByteArray *data);
|
void getAnalyzeRequestData(const DeckList &deck, QByteArray &data);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
|
explicit TappedOutInterface(CardDatabase &_cardDatabase, QObject *parent = nullptr);
|
||||||
void analyzeDeck(DeckList *deck);
|
void analyzeDeck(const DeckList &deck);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -18,21 +18,21 @@ class IJsonDeckParser
|
||||||
public:
|
public:
|
||||||
virtual ~IJsonDeckParser() = default;
|
virtual ~IJsonDeckParser() = default;
|
||||||
|
|
||||||
virtual DeckLoader *parse(const QJsonObject &obj) = 0;
|
virtual DeckList parse(const QJsonObject &obj) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ArchidektJsonParser : public IJsonDeckParser
|
class ArchidektJsonParser : public IJsonDeckParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeckLoader *parse(const QJsonObject &obj) override
|
DeckList parse(const QJsonObject &obj) override
|
||||||
{
|
{
|
||||||
DeckLoader *loader = new DeckLoader(nullptr);
|
DeckList deckList;
|
||||||
|
|
||||||
QString deckName = obj.value("name").toString();
|
QString deckName = obj.value("name").toString();
|
||||||
QString deckDescription = obj.value("description").toString();
|
QString deckDescription = obj.value("description").toString();
|
||||||
|
|
||||||
loader->getDeckList()->setName(deckName);
|
deckList.setName(deckName);
|
||||||
loader->getDeckList()->setComments(deckDescription);
|
deckList.setComments(deckDescription);
|
||||||
|
|
||||||
QString outputText;
|
QString outputText;
|
||||||
QTextStream outStream(&outputText);
|
QTextStream outStream(&outputText);
|
||||||
|
|
@ -49,25 +49,25 @@ public:
|
||||||
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
loader->getDeckList()->loadFromStream_Plain(outStream, false);
|
deckList.loadFromStream_Plain(outStream, false);
|
||||||
loader->getDeckList()->forEachCard(CardNodeFunction::ResolveProviderId());
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
|
|
||||||
return loader;
|
return deckList;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class MoxfieldJsonParser : public IJsonDeckParser
|
class MoxfieldJsonParser : public IJsonDeckParser
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeckLoader *parse(const QJsonObject &obj) override
|
DeckList parse(const QJsonObject &obj) override
|
||||||
{
|
{
|
||||||
DeckLoader *loader = new DeckLoader(nullptr);
|
DeckList deckList;
|
||||||
|
|
||||||
QString deckName = obj.value("name").toString();
|
QString deckName = obj.value("name").toString();
|
||||||
QString deckDescription = obj.value("description").toString();
|
QString deckDescription = obj.value("description").toString();
|
||||||
|
|
||||||
loader->getDeckList()->setName(deckName);
|
deckList.setName(deckName);
|
||||||
loader->getDeckList()->setComments(deckDescription);
|
deckList.setComments(deckDescription);
|
||||||
|
|
||||||
QString outputText;
|
QString outputText;
|
||||||
QTextStream outStream(&outputText);
|
QTextStream outStream(&outputText);
|
||||||
|
|
@ -96,8 +96,8 @@ public:
|
||||||
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
outStream << quantity << ' ' << cardName << " (" << setName << ") " << collectorNumber << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
loader->getDeckList()->loadFromStream_Plain(outStream, false);
|
deckList.loadFromStream_Plain(outStream, false);
|
||||||
loader->getDeckList()->forEachCard(CardNodeFunction::ResolveProviderId());
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
|
|
||||||
QJsonObject commandersObj = obj.value("commanders").toObject();
|
QJsonObject commandersObj = obj.value("commanders").toObject();
|
||||||
if (!commandersObj.isEmpty()) {
|
if (!commandersObj.isEmpty()) {
|
||||||
|
|
@ -108,12 +108,12 @@ public:
|
||||||
QString collectorNumber = cardData.value("cn").toString();
|
QString collectorNumber = cardData.value("cn").toString();
|
||||||
QString providerId = cardData.value("scryfall_id").toString();
|
QString providerId = cardData.value("scryfall_id").toString();
|
||||||
|
|
||||||
loader->getDeckList()->setBannerCard({commanderName, providerId});
|
deckList.setBannerCard({commanderName, providerId});
|
||||||
loader->getDeckList()->addCard(commanderName, DECK_ZONE_MAIN, -1, setName, collectorNumber, providerId);
|
deckList.addCard(commanderName, DECK_ZONE_MAIN, -1, setName, collectorNumber, providerId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return loader;
|
return deckList;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "../network/update/client/release_channel.h"
|
#include "../network/update/client/release_channel.h"
|
||||||
#include "card_counter_settings.h"
|
#include "card_counter_settings.h"
|
||||||
|
#include "version_string.h"
|
||||||
|
|
||||||
#include <QAbstractListModel>
|
#include <QAbstractListModel>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
@ -198,7 +199,13 @@ SettingsCache::SettingsCache()
|
||||||
|
|
||||||
mbDownloadSpoilers = settings->value("personal/downloadspoilers", false).toBool();
|
mbDownloadSpoilers = settings->value("personal/downloadspoilers", false).toBool();
|
||||||
|
|
||||||
checkUpdatesOnStartup = settings->value("personal/startupUpdateCheck", true).toBool();
|
if (settings->contains("personal/startupUpdateCheck")) {
|
||||||
|
checkUpdatesOnStartup = settings->value("personal/startupUpdateCheck", true).toBool();
|
||||||
|
} else if (QString(VERSION_STRING).contains("custom", Qt::CaseInsensitive)) {
|
||||||
|
checkUpdatesOnStartup = false; // do not run auto updater on custom version
|
||||||
|
} else {
|
||||||
|
checkUpdatesOnStartup = true; // default to run auto updater
|
||||||
|
}
|
||||||
startupCardUpdateCheckPromptForUpdate =
|
startupCardUpdateCheckPromptForUpdate =
|
||||||
settings->value("personal/startupCardUpdateCheckPromptForUpdate", true).toBool();
|
settings->value("personal/startupCardUpdateCheckPromptForUpdate", true).toBool();
|
||||||
startupCardUpdateCheckAlwaysUpdate = settings->value("personal/startupCardUpdateCheckAlwaysUpdate", false).toBool();
|
startupCardUpdateCheckAlwaysUpdate = settings->value("personal/startupCardUpdateCheckAlwaysUpdate", false).toBool();
|
||||||
|
|
@ -206,7 +213,15 @@ SettingsCache::SettingsCache()
|
||||||
lastCardUpdateCheck = settings->value("personal/lastCardUpdateCheck", QDateTime::currentDateTime().date()).toDate();
|
lastCardUpdateCheck = settings->value("personal/lastCardUpdateCheck", QDateTime::currentDateTime().date()).toDate();
|
||||||
notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
|
notifyAboutUpdates = settings->value("personal/updatenotification", true).toBool();
|
||||||
notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool();
|
notifyAboutNewVersion = settings->value("personal/newversionnotification", true).toBool();
|
||||||
updateReleaseChannel = settings->value("personal/updatereleasechannel", 0).toInt();
|
|
||||||
|
if (settings->contains("personal/updatereleasechannel")) {
|
||||||
|
updateReleaseChannel = settings->value("personal/updatereleasechannel").toInt();
|
||||||
|
} else if (QString(VERSION_STRING).contains("beta", Qt::CaseInsensitive)) {
|
||||||
|
// default to beta if this is a beta release
|
||||||
|
updateReleaseChannel = 1;
|
||||||
|
} else {
|
||||||
|
updateReleaseChannel = 0; // stable
|
||||||
|
}
|
||||||
|
|
||||||
lang = settings->value("personal/lang").toString();
|
lang = settings->value("personal/lang").toString();
|
||||||
keepalive = settings->value("personal/keepalive", 3).toInt();
|
keepalive = settings->value("personal/keepalive", 3).toInt();
|
||||||
|
|
|
||||||
|
|
@ -150,12 +150,7 @@ void ShortcutTreeView::currentChanged(const QModelIndex ¤t, const QModelIn
|
||||||
*/
|
*/
|
||||||
void ShortcutTreeView::updateSearchString(const QString &searchString)
|
void ShortcutTreeView::updateSearchString(const QString &searchString)
|
||||||
{
|
{
|
||||||
#if QT_VERSION > QT_VERSION_CHECK(5, 14, 0)
|
QStringList searchWords = searchString.split(" ", Qt::SkipEmptyParts);
|
||||||
const auto skipEmptyParts = Qt::SkipEmptyParts;
|
|
||||||
#else
|
|
||||||
const auto skipEmptyParts = QString::SkipEmptyParts;
|
|
||||||
#endif
|
|
||||||
QStringList searchWords = searchString.split(" ", skipEmptyParts);
|
|
||||||
|
|
||||||
auto escapeRegex = [](const QString &s) { return QRegularExpression::escape(s); };
|
auto escapeRegex = [](const QString &s) { return QRegularExpression::escape(s); };
|
||||||
std::transform(searchWords.begin(), searchWords.end(), searchWords.begin(), escapeRegex);
|
std::transform(searchWords.begin(), searchWords.end(), searchWords.begin(), escapeRegex);
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ QueryPartList <- ComplexQueryPart ( ws ("AND" ws)? ComplexQueryPart)* ws*
|
||||||
ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / SomewhatComplexQueryPart
|
ComplexQueryPart <- SomewhatComplexQueryPart ws "OR" ws ComplexQueryPart / SomewhatComplexQueryPart
|
||||||
SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
|
SomewhatComplexQueryPart <- [(] QueryPartList [)] / QueryPart
|
||||||
|
|
||||||
QueryPart <- NotQuery / DeckContentQuery / DeckNameQuery / FileNameQuery / PathQuery / GenericQuery
|
QueryPart <- NotQuery / DeckContentQuery / DeckNameQuery / FileNameQuery / PathQuery / FormatQuery / GenericQuery
|
||||||
|
|
||||||
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
NotQuery <- ('NOT' ws/'-') SomewhatComplexQueryPart
|
||||||
|
|
||||||
|
|
@ -22,8 +22,9 @@ CardSearch <- '[[' CardFilterString ']]'
|
||||||
CardFilterString <- (!']]'.)*
|
CardFilterString <- (!']]'.)*
|
||||||
|
|
||||||
DeckNameQuery <- ([Dd] 'eck')? [Nn] 'ame'? [:] String
|
DeckNameQuery <- ([Dd] 'eck')? [Nn] 'ame'? [:] String
|
||||||
FileNameQuery <- [Ff] ('ile' 'name'?)? [:] String
|
FileNameQuery <- [Ff] ([Nn] / 'ile' ([Nn] 'ame')?) [:] String
|
||||||
PathQuery <- [Pp] 'ath'? [:] String
|
PathQuery <- [Pp] 'ath'? [:] String
|
||||||
|
FormatQuery <- [Ff] 'ormat'? [:] String
|
||||||
|
|
||||||
GenericQuery <- String
|
GenericQuery <- String
|
||||||
|
|
||||||
|
|
@ -118,7 +119,7 @@ static void setupParserRules()
|
||||||
|
|
||||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) -> bool {
|
||||||
int count = 0;
|
int count = 0;
|
||||||
auto cardNodes = deck->deckLoader->getDeckList()->getCardNodes();
|
auto cardNodes = deck->deckLoader->getDeck().deckList.getCardNodes();
|
||||||
for (auto node : cardNodes) {
|
for (auto node : cardNodes) {
|
||||||
auto cardInfoPtr = CardDatabaseManager::query()->getCardInfo(node->getName());
|
auto cardInfoPtr = CardDatabaseManager::query()->getCardInfo(node->getName());
|
||||||
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
|
if (!cardInfoPtr.isNull() && cardFilter.check(cardInfoPtr)) {
|
||||||
|
|
@ -138,7 +139,7 @@ static void setupParserRules()
|
||||||
search["DeckNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
search["DeckNameQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
auto name = std::any_cast<QString>(sv[0]);
|
auto name = std::any_cast<QString>(sv[0]);
|
||||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||||
return deck->deckLoader->getDeckList()->getName().contains(name, Qt::CaseInsensitive);
|
return deck->deckLoader->getDeck().deckList.getName().contains(name, Qt::CaseInsensitive);
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -157,6 +158,14 @@ static void setupParserRules()
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
search["FormatQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
|
auto format = std::any_cast<QString>(sv[0]);
|
||||||
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||||
|
auto gameFormat = deck->deckLoader->getDeck().deckList.getGameFormat();
|
||||||
|
return QString::compare(format, gameFormat, Qt::CaseInsensitive) == 0;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
search["GenericQuery"] = [](const peg::SemanticValues &sv) -> DeckFilter {
|
||||||
auto name = std::any_cast<QString>(sv[0]);
|
auto name = std::any_cast<QString>(sv[0]);
|
||||||
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
return [=](const DeckPreviewWidget *deck, const ExtraDeckSearchInfo &) {
|
||||||
|
|
|
||||||
|
|
@ -269,12 +269,12 @@ void DeckViewContainer::loadDeckFromFile(const QString &filePath)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
loadDeckFromDeckLoader(&deck);
|
loadDeckFromDeckList(deck.getDeck().deckList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::loadDeckFromDeckLoader(DeckLoader *deck)
|
void DeckViewContainer::loadDeckFromDeckList(const DeckList &deck)
|
||||||
{
|
{
|
||||||
QString deckString = deck->getDeckList()->writeToString_Native();
|
QString deckString = deck.writeToString_Native();
|
||||||
|
|
||||||
if (deckString.length() > MAX_FILE_LENGTH) {
|
if (deckString.length() > MAX_FILE_LENGTH) {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Deck is greater than maximum file size."));
|
QMessageBox::critical(this, tr("Error"), tr("Deck is greater than maximum file size."));
|
||||||
|
|
@ -308,8 +308,8 @@ void DeckViewContainer::loadFromClipboard()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeckLoader *deck = dlg.getDeckList();
|
DeckList deck = dlg.getDeckList();
|
||||||
loadDeckFromDeckLoader(deck);
|
loadDeckFromDeckList(deck);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::loadFromWebsite()
|
void DeckViewContainer::loadFromWebsite()
|
||||||
|
|
@ -320,16 +320,15 @@ void DeckViewContainer::loadFromWebsite()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeckLoader *deck = dlg.getDeck();
|
DeckList deck = dlg.getDeck();
|
||||||
loadDeckFromDeckLoader(deck);
|
loadDeckFromDeckList(deck);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::deckSelectFinished(const Response &r)
|
void DeckViewContainer::deckSelectFinished(const Response &r)
|
||||||
{
|
{
|
||||||
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
|
const Response_DeckDownload &resp = r.GetExtension(Response_DeckDownload::ext);
|
||||||
DeckLoader newDeck(this, new DeckList(QString::fromStdString(resp.deck())));
|
DeckList newDeck = DeckList(QString::fromStdString(resp.deck()));
|
||||||
CardPictureLoader::cacheCardPixmaps(
|
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(newDeck.getCardRefList()));
|
||||||
CardDatabaseManager::query()->getCards(newDeck.getDeckList()->getCardRefList()));
|
|
||||||
setDeck(newDeck);
|
setDeck(newDeck);
|
||||||
switchToDeckLoadedView();
|
switchToDeckLoadedView();
|
||||||
}
|
}
|
||||||
|
|
@ -410,8 +409,8 @@ void DeckViewContainer::setSideboardLocked(bool locked)
|
||||||
deckView->resetSideboardPlan();
|
deckView->resetSideboardPlan();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckViewContainer::setDeck(DeckLoader &deck)
|
void DeckViewContainer::setDeck(const DeckList &deck)
|
||||||
{
|
{
|
||||||
deckView->setDeck(*deck.getDeckList());
|
deckView->setDeck(deck);
|
||||||
switchToDeckLoadedView();
|
switchToDeckLoadedView();
|
||||||
}
|
}
|
||||||
|
|
@ -85,12 +85,12 @@ public:
|
||||||
void setReadyStart(bool ready);
|
void setReadyStart(bool ready);
|
||||||
void readyAndUpdate();
|
void readyAndUpdate();
|
||||||
void setSideboardLocked(bool locked);
|
void setSideboardLocked(bool locked);
|
||||||
void setDeck(DeckLoader &deck);
|
void setDeck(const DeckList &deck);
|
||||||
void setVisualDeckStorageExists(bool exists);
|
void setVisualDeckStorageExists(bool exists);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void loadDeckFromFile(const QString &filePath);
|
void loadDeckFromFile(const QString &filePath);
|
||||||
void loadDeckFromDeckLoader(DeckLoader *deck);
|
void loadDeckFromDeckList(const DeckList &deck);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DECK_VIEW_CONTAINER_H
|
#endif // DECK_VIEW_CONTAINER_H
|
||||||
|
|
|
||||||
|
|
@ -117,11 +117,7 @@ DlgCreateToken::DlgCreateToken(const QStringList &_predefinedTokens, QWidget *pa
|
||||||
chooseTokenFromDeckRadioButton->setDisabled(true); // No tokens in deck = no need for option
|
chooseTokenFromDeckRadioButton->setDisabled(true); // No tokens in deck = no need for option
|
||||||
} else {
|
} else {
|
||||||
chooseTokenFromDeckRadioButton->setChecked(true);
|
chooseTokenFromDeckRadioButton->setChecked(true);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
|
||||||
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
|
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
|
||||||
#else
|
|
||||||
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>::fromList(predefinedTokens));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto *tokenChooseLayout = new QVBoxLayout;
|
auto *tokenChooseLayout = new QVBoxLayout;
|
||||||
|
|
@ -223,11 +219,7 @@ void DlgCreateToken::actChooseTokenFromAll(bool checked)
|
||||||
void DlgCreateToken::actChooseTokenFromDeck(bool checked)
|
void DlgCreateToken::actChooseTokenFromDeck(bool checked)
|
||||||
{
|
{
|
||||||
if (checked) {
|
if (checked) {
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
|
||||||
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
|
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>(predefinedTokens.begin(), predefinedTokens.end()));
|
||||||
#else
|
|
||||||
cardDatabaseDisplayModel->setCardNameSet(QSet<QString>::fromList(predefinedTokens));
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -60,13 +60,13 @@ void UtilityMenu::populatePredefinedTokensMenu()
|
||||||
clear();
|
clear();
|
||||||
setEnabled(false);
|
setEnabled(false);
|
||||||
predefinedTokens.clear();
|
predefinedTokens.clear();
|
||||||
DeckLoader *_deck = player->getDeck();
|
const DeckList &deckList = player->getDeck();
|
||||||
|
|
||||||
if (!_deck) {
|
if (deckList.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto tokenCardNodes = _deck->getDeckList()->getCardNodes({DECK_ZONE_TOKENS});
|
auto tokenCardNodes = deckList.getCardNodes({DECK_ZONE_TOKENS});
|
||||||
|
|
||||||
if (!tokenCardNodes.isEmpty()) {
|
if (!tokenCardNodes.isEmpty()) {
|
||||||
setEnabled(true);
|
setEnabled(true);
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,7 @@
|
||||||
Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent)
|
Player::Player(const ServerInfo_User &info, int _id, bool _local, bool _judge, AbstractGame *_parent)
|
||||||
: QObject(_parent), game(_parent), playerInfo(new PlayerInfo(info, _id, _local, _judge)),
|
: QObject(_parent), game(_parent), playerInfo(new PlayerInfo(info, _id, _local, _judge)),
|
||||||
playerEventHandler(new PlayerEventHandler(this)), playerActions(new PlayerActions(this)), active(false),
|
playerEventHandler(new PlayerEventHandler(this)), playerActions(new PlayerActions(this)), active(false),
|
||||||
conceded(false), deck(nullptr), zoneId(0), dialogSemaphore(false)
|
conceded(false), zoneId(0), dialogSemaphore(false)
|
||||||
{
|
{
|
||||||
initializeZones();
|
initializeZones();
|
||||||
|
|
||||||
|
|
@ -263,10 +263,9 @@ void Player::deleteCard(CardItem *card)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Does a player need a DeckLoader?
|
void Player::setDeck(const DeckList &_deck)
|
||||||
void Player::setDeck(DeckLoader &_deck)
|
|
||||||
{
|
{
|
||||||
deck = new DeckLoader(this, _deck.getDeckList());
|
deck = _deck;
|
||||||
|
|
||||||
emit deckChanged();
|
emit deckChanged();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "../../game_graphics/board/abstract_graphics_item.h"
|
#include "../../game_graphics/board/abstract_graphics_item.h"
|
||||||
#include "../../interface/widgets/menus/tearoff_menu.h"
|
#include "../../interface/widgets/menus/tearoff_menu.h"
|
||||||
|
#include "../interface/deck_loader/loaded_deck.h"
|
||||||
#include "../zones/logic/hand_zone_logic.h"
|
#include "../zones/logic/hand_zone_logic.h"
|
||||||
#include "../zones/logic/pile_zone_logic.h"
|
#include "../zones/logic/pile_zone_logic.h"
|
||||||
#include "../zones/logic/stack_zone_logic.h"
|
#include "../zones/logic/stack_zone_logic.h"
|
||||||
|
|
@ -44,7 +45,6 @@ class ArrowTarget;
|
||||||
class CardDatabase;
|
class CardDatabase;
|
||||||
class CardZone;
|
class CardZone;
|
||||||
class CommandContainer;
|
class CommandContainer;
|
||||||
class DeckLoader;
|
|
||||||
class GameCommand;
|
class GameCommand;
|
||||||
class GameEvent;
|
class GameEvent;
|
||||||
class PlayerInfo;
|
class PlayerInfo;
|
||||||
|
|
@ -66,7 +66,7 @@ class Player : public QObject
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void openDeckEditor(DeckLoader *deck);
|
void openDeckEditor(const LoadedDeck &deck);
|
||||||
void deckChanged();
|
void deckChanged();
|
||||||
void newCardAdded(AbstractCardItem *card);
|
void newCardAdded(AbstractCardItem *card);
|
||||||
void rearrangeCounters();
|
void rearrangeCounters();
|
||||||
|
|
@ -130,9 +130,9 @@ public:
|
||||||
return playerMenu;
|
return playerMenu;
|
||||||
}
|
}
|
||||||
|
|
||||||
void setDeck(DeckLoader &_deck);
|
void setDeck(const DeckList &_deck);
|
||||||
|
|
||||||
[[nodiscard]] DeckLoader *getDeck() const
|
[[nodiscard]] const DeckList &getDeck() const
|
||||||
{
|
{
|
||||||
return deck;
|
return deck;
|
||||||
}
|
}
|
||||||
|
|
@ -241,7 +241,7 @@ private:
|
||||||
bool active;
|
bool active;
|
||||||
bool conceded;
|
bool conceded;
|
||||||
|
|
||||||
DeckLoader *deck;
|
DeckList deck;
|
||||||
|
|
||||||
int zoneId;
|
int zoneId;
|
||||||
QMap<QString, CardZoneLogic *> zones;
|
QMap<QString, CardZoneLogic *> zones;
|
||||||
|
|
|
||||||
|
|
@ -218,7 +218,7 @@ void PlayerActions::actAlwaysLookAtTopCard()
|
||||||
|
|
||||||
void PlayerActions::actOpenDeckInDeckEditor()
|
void PlayerActions::actOpenDeckInDeckEditor()
|
||||||
{
|
{
|
||||||
emit player->openDeckEditor(player->getDeck());
|
emit player->openDeckEditor({.deckList = player->getDeck()});
|
||||||
}
|
}
|
||||||
|
|
||||||
void PlayerActions::actViewGraveyard()
|
void PlayerActions::actViewGraveyard()
|
||||||
|
|
|
||||||
|
|
@ -78,14 +78,7 @@ void PlayerEventHandler::eventShuffle(const Event_Shuffle &event)
|
||||||
void PlayerEventHandler::eventRollDie(const Event_RollDie &event)
|
void PlayerEventHandler::eventRollDie(const Event_RollDie &event)
|
||||||
{
|
{
|
||||||
if (!event.values().empty()) {
|
if (!event.values().empty()) {
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
|
||||||
QList<uint> rolls(event.values().begin(), event.values().end());
|
QList<uint> rolls(event.values().begin(), event.values().end());
|
||||||
#else
|
|
||||||
QList<uint> rolls;
|
|
||||||
for (const auto &value : event.values()) {
|
|
||||||
rolls.append(value);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
std::sort(rolls.begin(), rolls.end());
|
std::sort(rolls.begin(), rolls.end());
|
||||||
emit logRollDie(player, static_cast<int>(event.sides()), rolls);
|
emit logRollDie(player, static_cast<int>(event.sides()), rolls);
|
||||||
} else if (event.value()) {
|
} else if (event.value()) {
|
||||||
|
|
|
||||||
|
|
@ -13,12 +13,20 @@
|
||||||
#include <QGraphicsLinearLayout>
|
#include <QGraphicsLinearLayout>
|
||||||
#include <QGraphicsProxyWidget>
|
#include <QGraphicsProxyWidget>
|
||||||
#include <QGraphicsSceneMouseEvent>
|
#include <QGraphicsSceneMouseEvent>
|
||||||
|
#include <QGraphicsView>
|
||||||
#include <QLabel>
|
#include <QLabel>
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QScrollBar>
|
#include <QScrollBar>
|
||||||
|
#include <QStyle>
|
||||||
#include <QStyleOption>
|
#include <QStyleOption>
|
||||||
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
#include <libcockatrice/protocol/pb/command_shuffle.pb.h>
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
constexpr qreal kTitleBarHeight = 24.0;
|
||||||
|
constexpr qreal kMinVisibleWidth = 100.0;
|
||||||
|
} // namespace
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param _player the player the cards were revealed to.
|
* @param _player the player the cards were revealed to.
|
||||||
* @param _origZone the zone the cards were revealed from.
|
* @param _origZone the zone the cards were revealed from.
|
||||||
|
|
@ -241,33 +249,182 @@ void ZoneViewWidget::retranslateUi()
|
||||||
pileViewCheckBox.setText(tr("pile view"));
|
pileViewCheckBox.setText(tr("pile view"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneViewWidget::moveEvent(QGraphicsSceneMoveEvent * /* event */)
|
void ZoneViewWidget::stopWindowDrag()
|
||||||
{
|
{
|
||||||
if (!scene())
|
if (!draggingWindow)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int titleBarHeight = 24;
|
draggingWindow = false;
|
||||||
|
ungrabMouse();
|
||||||
|
}
|
||||||
|
|
||||||
QPointF scenePos = pos();
|
void ZoneViewWidget::startWindowDrag(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
draggingWindow = true;
|
||||||
|
dragStartItemPos = pos();
|
||||||
|
dragStartScreenPos = event->screenPos();
|
||||||
|
dragView = findDragView(event->widget());
|
||||||
|
|
||||||
if (scenePos.x() < 0) {
|
// need to grab mouse to receive events and not miss initial movement
|
||||||
scenePos.setX(0);
|
grabMouse();
|
||||||
} else {
|
}
|
||||||
qreal maxw = scene()->sceneRect().width() - 100;
|
|
||||||
if (scenePos.x() > maxw)
|
QRectF ZoneViewWidget::closeButtonRect(QWidget *styleWidget) const
|
||||||
scenePos.setX(maxw);
|
{
|
||||||
|
const QRectF frameRectF = windowFrameRect();
|
||||||
|
const QRect titleBarRect(frameRectF.toRect().x(), frameRectF.toRect().y(), frameRectF.toRect().width(),
|
||||||
|
static_cast<int>(kTitleBarHeight));
|
||||||
|
|
||||||
|
// query the style for the close button position (handles macOS top-left placement)
|
||||||
|
if (styleWidget) {
|
||||||
|
QStyleOptionTitleBar opt;
|
||||||
|
opt.initFrom(styleWidget);
|
||||||
|
opt.rect = titleBarRect;
|
||||||
|
opt.text = windowTitle();
|
||||||
|
opt.icon = styleWidget->windowIcon();
|
||||||
|
opt.titleBarFlags = Qt::Window | Qt::WindowTitleHint | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
|
||||||
|
opt.subControls = QStyle::SC_TitleBarCloseButton;
|
||||||
|
opt.activeSubControls = QStyle::SC_TitleBarCloseButton;
|
||||||
|
opt.titleBarState = styleWidget->isActiveWindow() ? Qt::WindowActive : Qt::WindowNoState;
|
||||||
|
if (styleWidget->isActiveWindow())
|
||||||
|
opt.state |= QStyle::State_Active;
|
||||||
|
const QRect r = styleWidget->style()->subControlRect(QStyle::CC_TitleBar, &opt, QStyle::SC_TitleBarCloseButton,
|
||||||
|
styleWidget);
|
||||||
|
if (r.isValid() && !r.isEmpty()) {
|
||||||
|
return QRectF(r);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scenePos.y() < titleBarHeight) {
|
// fallback: square at right end of titlebar (Windows/Linux style)
|
||||||
scenePos.setY(titleBarHeight);
|
return QRectF(frameRectF.right() - kTitleBarHeight, frameRectF.top(), kTitleBarHeight, kTitleBarHeight);
|
||||||
} else {
|
}
|
||||||
qreal maxh = scene()->sceneRect().height() - titleBarHeight;
|
|
||||||
if (scenePos.y() > maxh)
|
QGraphicsView *ZoneViewWidget::findDragView(QWidget *eventWidget) const
|
||||||
scenePos.setY(maxh);
|
{
|
||||||
|
QWidget *current = eventWidget;
|
||||||
|
while (current) {
|
||||||
|
if (auto *view = qobject_cast<QGraphicsView *>(current))
|
||||||
|
return view;
|
||||||
|
current = current->parentWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scenePos != pos())
|
if (scene() && !scene()->views().isEmpty())
|
||||||
setPos(scenePos);
|
return scene()->views().constFirst();
|
||||||
|
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
QPointF ZoneViewWidget::calcDraggedWindowPos(const QPoint &screenPos,
|
||||||
|
const QPointF &scenePos,
|
||||||
|
const QPointF &buttonDownScenePos) const
|
||||||
|
{
|
||||||
|
if (dragView && dragView->viewport()) {
|
||||||
|
const QPoint vpStart = dragView->viewport()->mapFromGlobal(dragStartScreenPos);
|
||||||
|
const QPoint vpNow = dragView->viewport()->mapFromGlobal(screenPos);
|
||||||
|
const QPointF sceneStart = dragView->mapToScene(vpStart);
|
||||||
|
const QPointF sceneNow = dragView->mapToScene(vpNow);
|
||||||
|
return dragStartItemPos + (sceneNow - sceneStart);
|
||||||
|
}
|
||||||
|
|
||||||
|
return dragStartItemPos + (scenePos - buttonDownScenePos);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ZoneViewWidget::windowFrameEvent(QEvent *event)
|
||||||
|
{
|
||||||
|
if (event->type() == QEvent::UngrabMouse) {
|
||||||
|
stopWindowDrag();
|
||||||
|
return QGraphicsWidget::windowFrameEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *me = dynamic_cast<QGraphicsSceneMouseEvent *>(event);
|
||||||
|
if (!me)
|
||||||
|
return QGraphicsWidget::windowFrameEvent(event);
|
||||||
|
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::GraphicsSceneMousePress:
|
||||||
|
if (me->button() == Qt::LeftButton && windowFrameSectionAt(me->pos()) == Qt::TitleBarArea) {
|
||||||
|
// avoid drag on close button
|
||||||
|
if (closeButtonRect(me->widget()).contains(me->pos())) {
|
||||||
|
me->accept();
|
||||||
|
close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
startWindowDrag(me);
|
||||||
|
me->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::GraphicsSceneMouseMove:
|
||||||
|
if (draggingWindow) {
|
||||||
|
if (!(me->buttons() & Qt::LeftButton)) {
|
||||||
|
stopWindowDrag();
|
||||||
|
} else {
|
||||||
|
setPos(
|
||||||
|
calcDraggedWindowPos(me->screenPos(), me->scenePos(), me->buttonDownScenePos(Qt::LeftButton)));
|
||||||
|
}
|
||||||
|
me->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case QEvent::GraphicsSceneMouseRelease:
|
||||||
|
if (draggingWindow && me->button() == Qt::LeftButton) {
|
||||||
|
stopWindowDrag();
|
||||||
|
me->accept();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QGraphicsWidget::windowFrameEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneViewWidget::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
// move if the scene routes moves while dragging
|
||||||
|
if (draggingWindow && (event->buttons() & Qt::LeftButton)) {
|
||||||
|
setPos(calcDraggedWindowPos(event->screenPos(), event->scenePos(), event->buttonDownScenePos(Qt::LeftButton)));
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGraphicsWidget::mouseMoveEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZoneViewWidget::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
|
||||||
|
{
|
||||||
|
if (draggingWindow && event->button() == Qt::LeftButton) {
|
||||||
|
stopWindowDrag();
|
||||||
|
event->accept();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QGraphicsWidget::mouseReleaseEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
QVariant ZoneViewWidget::itemChange(GraphicsItemChange change, const QVariant &value)
|
||||||
|
{
|
||||||
|
if (change == QGraphicsItem::ItemPositionChange && scene()) {
|
||||||
|
// Keep grab area in main view
|
||||||
|
const QRectF sceneRect = scene()->sceneRect();
|
||||||
|
const QPointF requestedPos = value.toPointF();
|
||||||
|
QPointF desiredPos = requestedPos;
|
||||||
|
|
||||||
|
const qreal minX = sceneRect.left();
|
||||||
|
const qreal maxX = qMax(minX, sceneRect.right() - kMinVisibleWidth);
|
||||||
|
const qreal minY = sceneRect.top() + kTitleBarHeight;
|
||||||
|
const qreal maxY = qMax(minY, sceneRect.bottom() - kTitleBarHeight);
|
||||||
|
|
||||||
|
desiredPos.setX(qBound(minX, desiredPos.x(), maxX));
|
||||||
|
desiredPos.setY(qBound(minY, desiredPos.y(), maxY));
|
||||||
|
return desiredPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
return QGraphicsWidget::itemChange(change, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZoneViewWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
|
void ZoneViewWidget::resizeEvent(QGraphicsSceneResizeEvent *event)
|
||||||
|
|
@ -350,6 +507,7 @@ void ZoneViewWidget::handleScrollBarChange(int value)
|
||||||
|
|
||||||
void ZoneViewWidget::closeEvent(QCloseEvent *event)
|
void ZoneViewWidget::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
|
stopWindowDrag();
|
||||||
disconnect(zone, &ZoneViewZone::closed, this, 0);
|
disconnect(zone, &ZoneViewZone::closed, this, 0);
|
||||||
// manually call zone->close in order to remove it from the origZones views
|
// manually call zone->close in order to remove it from the origZones views
|
||||||
zone->close();
|
zone->close();
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
* @ingroup GameGraphicsZones
|
* @ingroup GameGraphicsZones
|
||||||
* @brief TODO: Document this.
|
* @brief TODO: Document this.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef ZONEVIEWWIDGET_H
|
#ifndef ZONEVIEWWIDGET_H
|
||||||
#define ZONEVIEWWIDGET_H
|
#define ZONEVIEWWIDGET_H
|
||||||
|
|
||||||
|
|
@ -14,6 +13,7 @@
|
||||||
#include <QGraphicsProxyWidget>
|
#include <QGraphicsProxyWidget>
|
||||||
#include <QGraphicsWidget>
|
#include <QGraphicsWidget>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
|
#include <QPointer>
|
||||||
#include <libcockatrice/utility/macros.h>
|
#include <libcockatrice/utility/macros.h>
|
||||||
|
|
||||||
class QLabel;
|
class QLabel;
|
||||||
|
|
@ -28,6 +28,8 @@ class ServerInfo_Card;
|
||||||
class QGraphicsSceneMouseEvent;
|
class QGraphicsSceneMouseEvent;
|
||||||
class QGraphicsSceneWheelEvent;
|
class QGraphicsSceneWheelEvent;
|
||||||
class QStyleOption;
|
class QStyleOption;
|
||||||
|
class QGraphicsView;
|
||||||
|
class QWidget;
|
||||||
|
|
||||||
class ScrollableGraphicsProxyWidget : public QGraphicsProxyWidget
|
class ScrollableGraphicsProxyWidget : public QGraphicsProxyWidget
|
||||||
{
|
{
|
||||||
|
|
@ -66,6 +68,33 @@ private:
|
||||||
int extraHeight;
|
int extraHeight;
|
||||||
Player *player;
|
Player *player;
|
||||||
|
|
||||||
|
bool draggingWindow = false;
|
||||||
|
QPoint dragStartScreenPos;
|
||||||
|
QPointF dragStartItemPos;
|
||||||
|
QPointer<QGraphicsView> dragView;
|
||||||
|
|
||||||
|
void stopWindowDrag();
|
||||||
|
void startWindowDrag(QGraphicsSceneMouseEvent *event);
|
||||||
|
QRectF closeButtonRect(QWidget *styleWidget) const;
|
||||||
|
/**
|
||||||
|
* @brief Resolves the QGraphicsView to use for drag coordinate mapping
|
||||||
|
*
|
||||||
|
* @param eventWidget QWidget that originated the mouse event
|
||||||
|
* @return The resolved QGraphicsView
|
||||||
|
*/
|
||||||
|
QGraphicsView *findDragView(QWidget *eventWidget) const;
|
||||||
|
/**
|
||||||
|
* @brief Calculates the desired widget position while dragging
|
||||||
|
*
|
||||||
|
* @param screenPos Global screen coordinates of the current mouse position
|
||||||
|
* @param scenePos Scene coordinates of the current mouse position
|
||||||
|
* @param buttonDownScenePos Scene coordinates of the initial mouse press position
|
||||||
|
*
|
||||||
|
* @return The new widget position in scene coordinates
|
||||||
|
*/
|
||||||
|
QPointF
|
||||||
|
calcDraggedWindowPos(const QPoint &screenPos, const QPointF &scenePos, const QPointF &buttonDownScenePos) const;
|
||||||
|
|
||||||
void resizeScrollbar(qreal newZoneHeight);
|
void resizeScrollbar(qreal newZoneHeight);
|
||||||
signals:
|
signals:
|
||||||
void closePressed(ZoneViewWidget *zv);
|
void closePressed(ZoneViewWidget *zv);
|
||||||
|
|
@ -76,7 +105,6 @@ private slots:
|
||||||
void resizeToZoneContents(bool forceInitialHeight = false);
|
void resizeToZoneContents(bool forceInitialHeight = false);
|
||||||
void handleScrollBarChange(int value);
|
void handleScrollBarChange(int value);
|
||||||
void zoneDeleted();
|
void zoneDeleted();
|
||||||
void moveEvent(QGraphicsSceneMoveEvent * /* event */) override;
|
|
||||||
void resizeEvent(QGraphicsSceneResizeEvent * /* event */) override;
|
void resizeEvent(QGraphicsSceneResizeEvent * /* event */) override;
|
||||||
void expandWindow();
|
void expandWindow();
|
||||||
|
|
||||||
|
|
@ -101,6 +129,10 @@ public:
|
||||||
protected:
|
protected:
|
||||||
void closeEvent(QCloseEvent *event) override;
|
void closeEvent(QCloseEvent *event) override;
|
||||||
void initStyleOption(QStyleOption *option) const override;
|
void initStyleOption(QStyleOption *option) const override;
|
||||||
|
bool windowFrameEvent(QEvent *event) override;
|
||||||
|
QVariant itemChange(GraphicsItemChange change, const QVariant &value) override;
|
||||||
|
void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
|
void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,12 +17,7 @@ void AbstractGraphicsItem::paintNumberEllipse(int number,
|
||||||
font.setWeight(QFont::Bold);
|
font.setWeight(QFont::Bold);
|
||||||
|
|
||||||
QFontMetrics fm(font);
|
QFontMetrics fm(font);
|
||||||
double w = 1.3 *
|
double w = 1.3 * fm.horizontalAdvance(numStr);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 11, 0))
|
|
||||||
fm.horizontalAdvance(numStr);
|
|
||||||
#else
|
|
||||||
fm.width(numStr);
|
|
||||||
#endif
|
|
||||||
double h = fm.height() * 1.3;
|
double h = fm.height() * 1.3;
|
||||||
if (w < h)
|
if (w < h)
|
||||||
w = h;
|
w = h;
|
||||||
|
|
|
||||||
|
|
@ -21,9 +21,7 @@ CardPictureLoaderWorker::CardPictureLoaderWorker()
|
||||||
// We need a timeout to ensure requests don't hang indefinitely in case of
|
// We need a timeout to ensure requests don't hang indefinitely in case of
|
||||||
// cache corruption, see related Qt bug: https://bugreports.qt.io/browse/QTBUG-111397
|
// cache corruption, see related Qt bug: https://bugreports.qt.io/browse/QTBUG-111397
|
||||||
// Use Qt's default timeout (30s, as of 2023-02-22)
|
// Use Qt's default timeout (30s, as of 2023-02-22)
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
|
||||||
networkManager->setTransferTimeout();
|
networkManager->setTransferTimeout();
|
||||||
#endif
|
|
||||||
cache = new QNetworkDiskCache(this);
|
cache = new QNetworkDiskCache(this);
|
||||||
cache->setCacheDirectory(SettingsCache::instance().getNetworkCachePath());
|
cache->setCacheDirectory(SettingsCache::instance().getNetworkCachePath());
|
||||||
cache->setMaximumCacheSize(1024L * 1024L *
|
cache->setMaximumCacheSize(1024L * 1024L *
|
||||||
|
|
|
||||||
|
|
@ -25,11 +25,7 @@ const QStringList DeckLoader::ACCEPTED_FILE_EXTENSIONS = {"*.cod", "*.dec", "*.d
|
||||||
const QStringList DeckLoader::FILE_NAME_FILTERS = {
|
const QStringList DeckLoader::FILE_NAME_FILTERS = {
|
||||||
tr("Common deck formats (%1)").arg(ACCEPTED_FILE_EXTENSIONS.join(" ")), tr("All files (*.*)")};
|
tr("Common deck formats (%1)").arg(ACCEPTED_FILE_EXTENSIONS.join(" ")), tr("All files (*.*)")};
|
||||||
|
|
||||||
DeckLoader::DeckLoader(QObject *parent) : QObject(parent), deckList(new DeckList())
|
DeckLoader::DeckLoader(QObject *parent) : QObject(parent)
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckLoader::DeckLoader(QObject *parent, DeckList *_deckList) : QObject(parent), deckList(_deckList)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -41,17 +37,18 @@ bool DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fm
|
||||||
}
|
}
|
||||||
|
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
DeckList deckList = DeckList();
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = deckList->loadFromFile_Plain(&file);
|
result = deckList.loadFromFile_Plain(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice: {
|
case DeckFileFormat::Cockatrice: {
|
||||||
result = deckList->loadFromFile_Native(&file);
|
result = deckList.loadFromFile_Native(&file);
|
||||||
qCInfo(DeckLoaderLog) << "Loaded from" << fileName << "-" << result;
|
qCInfo(DeckLoaderLog) << "Loaded from" << fileName << "-" << result;
|
||||||
if (!result) {
|
if (!result) {
|
||||||
qCInfo(DeckLoaderLog) << "Retrying as plain format";
|
qCInfo(DeckLoaderLog) << "Retrying as plain format";
|
||||||
file.seek(0);
|
file.seek(0);
|
||||||
result = deckList->loadFromFile_Plain(&file);
|
result = deckList.loadFromFile_Plain(&file);
|
||||||
fmt = DeckFileFormat::PlainText;
|
fmt = DeckFileFormat::PlainText;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
@ -62,7 +59,8 @@ bool DeckLoader::loadFromFile(const QString &fileName, DeckFileFormat::Format fm
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
lastLoadInfo = {
|
loadedDeck.deckList = deckList;
|
||||||
|
loadedDeck.lastLoadInfo = {
|
||||||
.fileName = fileName,
|
.fileName = fileName,
|
||||||
.fileFormat = fmt,
|
.fileFormat = fmt,
|
||||||
};
|
};
|
||||||
|
|
@ -86,7 +84,7 @@ bool DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Form
|
||||||
watcher->deleteLater();
|
watcher->deleteLater();
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
lastLoadInfo = {
|
loadedDeck.lastLoadInfo = {
|
||||||
.fileName = fileName,
|
.fileName = fileName,
|
||||||
.fileFormat = fmt,
|
.fileFormat = fmt,
|
||||||
};
|
};
|
||||||
|
|
@ -107,13 +105,13 @@ bool DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Form
|
||||||
|
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
return deckList->loadFromFile_Plain(&file);
|
return loadedDeck.deckList.loadFromFile_Plain(&file);
|
||||||
case DeckFileFormat::Cockatrice: {
|
case DeckFileFormat::Cockatrice: {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
result = deckList->loadFromFile_Native(&file);
|
result = loadedDeck.deckList.loadFromFile_Native(&file);
|
||||||
if (!result) {
|
if (!result) {
|
||||||
file.seek(0);
|
file.seek(0);
|
||||||
return deckList->loadFromFile_Plain(&file);
|
return loadedDeck.deckList.loadFromFile_Plain(&file);
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
@ -129,9 +127,9 @@ bool DeckLoader::loadFromFileAsync(const QString &fileName, DeckFileFormat::Form
|
||||||
|
|
||||||
bool DeckLoader::loadFromRemote(const QString &nativeString, int remoteDeckId)
|
bool DeckLoader::loadFromRemote(const QString &nativeString, int remoteDeckId)
|
||||||
{
|
{
|
||||||
bool result = deckList->loadFromString_Native(nativeString);
|
bool result = loadedDeck.deckList.loadFromString_Native(nativeString);
|
||||||
if (result) {
|
if (result) {
|
||||||
lastLoadInfo = {
|
loadedDeck.lastLoadInfo = {
|
||||||
.remoteDeckId = remoteDeckId,
|
.remoteDeckId = remoteDeckId,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -150,16 +148,16 @@ bool DeckLoader::saveToFile(const QString &fileName, DeckFileFormat::Format fmt)
|
||||||
bool result = false;
|
bool result = false;
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = deckList->saveToFile_Plain(&file);
|
result = loadedDeck.deckList.saveToFile_Plain(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice:
|
case DeckFileFormat::Cockatrice:
|
||||||
result = deckList->saveToFile_Native(&file);
|
result = loadedDeck.deckList.saveToFile_Native(&file);
|
||||||
qCInfo(DeckLoaderLog) << "Saving to " << fileName << "-" << result;
|
qCInfo(DeckLoaderLog) << "Saving to " << fileName << "-" << result;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
lastLoadInfo = {
|
loadedDeck.lastLoadInfo = {
|
||||||
.fileName = fileName,
|
.fileName = fileName,
|
||||||
.fileFormat = fmt,
|
.fileFormat = fmt,
|
||||||
};
|
};
|
||||||
|
|
@ -194,18 +192,18 @@ bool DeckLoader::updateLastLoadedTimestamp(const QString &fileName, DeckFileForm
|
||||||
// Perform file modifications
|
// Perform file modifications
|
||||||
switch (fmt) {
|
switch (fmt) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
result = deckList->saveToFile_Plain(&file);
|
result = loadedDeck.deckList.saveToFile_Plain(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice:
|
case DeckFileFormat::Cockatrice:
|
||||||
deckList->setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
|
loadedDeck.deckList.setLastLoadedTimestamp(QDateTime::currentDateTime().toString());
|
||||||
result = deckList->saveToFile_Native(&file);
|
result = loadedDeck.deckList.saveToFile_Native(&file);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
file.close(); // Close the file to ensure changes are flushed
|
file.close(); // Close the file to ensure changes are flushed
|
||||||
|
|
||||||
if (result) {
|
if (result) {
|
||||||
lastLoadInfo = {
|
loadedDeck.lastLoadInfo = {
|
||||||
.fileName = fileName,
|
.fileName = fileName,
|
||||||
.fileFormat = fmt,
|
.fileFormat = fmt,
|
||||||
};
|
};
|
||||||
|
|
@ -289,14 +287,14 @@ static QString toDecklistExportString(const QList<const DecklistCardNode *> &car
|
||||||
* @param deckList The decklist to export
|
* @param deckList The decklist to export
|
||||||
* @param website The website we're sending the deck to
|
* @param website The website we're sending the deck to
|
||||||
*/
|
*/
|
||||||
QString DeckLoader::exportDeckToDecklist(const DeckList *deckList, DecklistWebsite website)
|
QString DeckLoader::exportDeckToDecklist(const DeckList &deckList, DecklistWebsite website)
|
||||||
{
|
{
|
||||||
// Add the base url
|
// Add the base url
|
||||||
QString deckString = "https://" + getDomainForWebsite(website) + "/?";
|
QString deckString = "https://" + getDomainForWebsite(website) + "/?";
|
||||||
|
|
||||||
// export all cards in zone
|
// export all cards in zone
|
||||||
QString mainBoardCards = toDecklistExportString(deckList->getCardNodes({DECK_ZONE_MAIN}));
|
QString mainBoardCards = toDecklistExportString(deckList.getCardNodes({DECK_ZONE_MAIN}));
|
||||||
QString sideBoardCards = toDecklistExportString(deckList->getCardNodes({DECK_ZONE_SIDE}));
|
QString sideBoardCards = toDecklistExportString(deckList.getCardNodes({DECK_ZONE_SIDE}));
|
||||||
|
|
||||||
// Remove the extra return at the end of the last cards
|
// Remove the extra return at the end of the last cards
|
||||||
mainBoardCards.chop(3);
|
mainBoardCards.chop(3);
|
||||||
|
|
@ -312,7 +310,7 @@ QString DeckLoader::exportDeckToDecklist(const DeckList *deckList, DecklistWebsi
|
||||||
return deckString;
|
return deckString;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckLoader::saveToClipboard(const DeckList *deckList, bool addComments, bool addSetNameAndNumber)
|
void DeckLoader::saveToClipboard(const DeckList &deckList, bool addComments, bool addSetNameAndNumber)
|
||||||
{
|
{
|
||||||
QString buffer;
|
QString buffer;
|
||||||
QTextStream stream(&buffer);
|
QTextStream stream(&buffer);
|
||||||
|
|
@ -322,7 +320,7 @@ void DeckLoader::saveToClipboard(const DeckList *deckList, bool addComments, boo
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckLoader::saveToStream_Plain(QTextStream &out,
|
bool DeckLoader::saveToStream_Plain(QTextStream &out,
|
||||||
const DeckList *deckList,
|
const DeckList &deckList,
|
||||||
bool addComments,
|
bool addComments,
|
||||||
bool addSetNameAndNumber)
|
bool addSetNameAndNumber)
|
||||||
{
|
{
|
||||||
|
|
@ -331,7 +329,7 @@ bool DeckLoader::saveToStream_Plain(QTextStream &out,
|
||||||
}
|
}
|
||||||
|
|
||||||
// loop zones
|
// loop zones
|
||||||
for (auto zoneNode : deckList->getZoneNodes()) {
|
for (auto zoneNode : deckList.getZoneNodes()) {
|
||||||
saveToStream_DeckZone(out, zoneNode, addComments, addSetNameAndNumber);
|
saveToStream_DeckZone(out, zoneNode, addComments, addSetNameAndNumber);
|
||||||
|
|
||||||
// end of zone
|
// end of zone
|
||||||
|
|
@ -341,14 +339,14 @@ bool DeckLoader::saveToStream_Plain(QTextStream &out,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckLoader::saveToStream_DeckHeader(QTextStream &out, const DeckList *deckList)
|
void DeckLoader::saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList)
|
||||||
{
|
{
|
||||||
if (!deckList->getName().isEmpty()) {
|
if (!deckList.getName().isEmpty()) {
|
||||||
out << "// " << deckList->getName() << "\n\n";
|
out << "// " << deckList.getName() << "\n\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deckList->getComments().isEmpty()) {
|
if (!deckList.getComments().isEmpty()) {
|
||||||
QStringList commentRows = deckList->getComments().split(QRegularExpression("\n|\r\n|\r"));
|
QStringList commentRows = deckList.getComments().split(QRegularExpression("\n|\r\n|\r"));
|
||||||
for (const QString &row : commentRows) {
|
for (const QString &row : commentRows) {
|
||||||
out << "// " << row << "\n";
|
out << "// " << row << "\n";
|
||||||
}
|
}
|
||||||
|
|
@ -436,7 +434,7 @@ void DeckLoader::saveToStream_DeckZoneCards(QTextStream &out,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DeckLoader::convertToCockatriceFormat(QString fileName)
|
bool DeckLoader::convertToCockatriceFormat(const QString &fileName)
|
||||||
{
|
{
|
||||||
// Change the file extension to .cod
|
// Change the file extension to .cod
|
||||||
QFileInfo fileInfo(fileName);
|
QFileInfo fileInfo(fileName);
|
||||||
|
|
@ -455,7 +453,7 @@ bool DeckLoader::convertToCockatriceFormat(QString fileName)
|
||||||
switch (DeckFileFormat::getFormatFromName(fileName)) {
|
switch (DeckFileFormat::getFormatFromName(fileName)) {
|
||||||
case DeckFileFormat::PlainText:
|
case DeckFileFormat::PlainText:
|
||||||
// Save in Cockatrice's native format
|
// Save in Cockatrice's native format
|
||||||
result = deckList->saveToFile_Native(&file);
|
result = loadedDeck.deckList.saveToFile_Native(&file);
|
||||||
break;
|
break;
|
||||||
case DeckFileFormat::Cockatrice:
|
case DeckFileFormat::Cockatrice:
|
||||||
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
|
qCInfo(DeckLoaderLog) << "File is already in Cockatrice format. No conversion needed.";
|
||||||
|
|
@ -476,7 +474,7 @@ bool DeckLoader::convertToCockatriceFormat(QString fileName)
|
||||||
} else {
|
} else {
|
||||||
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
|
qCInfo(DeckLoaderLog) << "Original file deleted successfully:" << fileName;
|
||||||
}
|
}
|
||||||
lastLoadInfo = {
|
loadedDeck.lastLoadInfo = {
|
||||||
.fileName = newFileName,
|
.fileName = newFileName,
|
||||||
.fileFormat = DeckFileFormat::Cockatrice,
|
.fileFormat = DeckFileFormat::Cockatrice,
|
||||||
};
|
};
|
||||||
|
|
@ -485,29 +483,6 @@ bool DeckLoader::convertToCockatriceFormat(QString fileName)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
QString DeckLoader::getCardZoneFromName(const QString &cardName, QString currentZoneName)
|
|
||||||
{
|
|
||||||
CardInfoPtr card = CardDatabaseManager::query()->getCardInfo(cardName);
|
|
||||||
|
|
||||||
if (card && card->getIsToken()) {
|
|
||||||
return DECK_ZONE_TOKENS;
|
|
||||||
}
|
|
||||||
|
|
||||||
return currentZoneName;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString DeckLoader::getCompleteCardName(const QString &cardName)
|
|
||||||
{
|
|
||||||
if (CardDatabaseManager::getInstance()) {
|
|
||||||
ExactCard temp = CardDatabaseManager::query()->guessCard({cardName});
|
|
||||||
if (temp) {
|
|
||||||
return temp.getName();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cardName;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node)
|
void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node)
|
||||||
{
|
{
|
||||||
const int totalColumns = 2;
|
const int totalColumns = 2;
|
||||||
|
|
@ -568,7 +543,7 @@ void DeckLoader::printDeckListNode(QTextCursor *cursor, const InnerDecklistNode
|
||||||
cursor->movePosition(QTextCursor::End);
|
cursor->movePosition(QTextCursor::End);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckLoader::printDeckList(QPrinter *printer, const DeckList *deckList)
|
void DeckLoader::printDeckList(QPrinter *printer, const DeckList &deckList)
|
||||||
{
|
{
|
||||||
QTextDocument doc;
|
QTextDocument doc;
|
||||||
|
|
||||||
|
|
@ -584,14 +559,14 @@ void DeckLoader::printDeckList(QPrinter *printer, const DeckList *deckList)
|
||||||
headerCharFormat.setFontWeight(QFont::Bold);
|
headerCharFormat.setFontWeight(QFont::Bold);
|
||||||
|
|
||||||
cursor.insertBlock(headerBlockFormat, headerCharFormat);
|
cursor.insertBlock(headerBlockFormat, headerCharFormat);
|
||||||
cursor.insertText(deckList->getName());
|
cursor.insertText(deckList.getName());
|
||||||
|
|
||||||
headerCharFormat.setFontPointSize(12);
|
headerCharFormat.setFontPointSize(12);
|
||||||
cursor.insertBlock(headerBlockFormat, headerCharFormat);
|
cursor.insertBlock(headerBlockFormat, headerCharFormat);
|
||||||
cursor.insertText(deckList->getComments());
|
cursor.insertText(deckList.getComments());
|
||||||
cursor.insertBlock(headerBlockFormat, headerCharFormat);
|
cursor.insertBlock(headerBlockFormat, headerCharFormat);
|
||||||
|
|
||||||
for (auto zoneNode : deckList->getZoneNodes()) {
|
for (auto zoneNode : deckList.getZoneNodes()) {
|
||||||
cursor.insertHtml("<br><img src=theme:hr.jpg>");
|
cursor.insertHtml("<br><img src=theme:hr.jpg>");
|
||||||
cursor.insertBlock(headerBlockFormat, headerCharFormat);
|
cursor.insertBlock(headerBlockFormat, headerCharFormat);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -41,28 +41,16 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeckList *deckList;
|
LoadedDeck loadedDeck;
|
||||||
LoadedDeck::LoadInfo lastLoadInfo;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DeckLoader(QObject *parent);
|
DeckLoader(QObject *parent);
|
||||||
DeckLoader(QObject *parent, DeckList *_deckList);
|
|
||||||
DeckLoader(const DeckLoader &) = delete;
|
DeckLoader(const DeckLoader &) = delete;
|
||||||
DeckLoader &operator=(const DeckLoader &) = delete;
|
DeckLoader &operator=(const DeckLoader &) = delete;
|
||||||
|
|
||||||
const LoadedDeck::LoadInfo &getLastLoadInfo() const
|
|
||||||
{
|
|
||||||
return lastLoadInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
void setLastLoadInfo(const LoadedDeck::LoadInfo &info)
|
|
||||||
{
|
|
||||||
lastLoadInfo = info;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool hasNotBeenLoaded() const
|
[[nodiscard]] bool hasNotBeenLoaded() const
|
||||||
{
|
{
|
||||||
return lastLoadInfo.isEmpty();
|
return loadedDeck.lastLoadInfo.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest = false);
|
bool loadFromFile(const QString &fileName, DeckFileFormat::Format fmt, bool userRequest = false);
|
||||||
|
|
@ -71,11 +59,11 @@ public:
|
||||||
bool saveToFile(const QString &fileName, DeckFileFormat::Format fmt);
|
bool saveToFile(const QString &fileName, DeckFileFormat::Format fmt);
|
||||||
bool updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt);
|
bool updateLastLoadedTimestamp(const QString &fileName, DeckFileFormat::Format fmt);
|
||||||
|
|
||||||
static QString exportDeckToDecklist(const DeckList *deckList, DecklistWebsite website);
|
static QString exportDeckToDecklist(const DeckList &deckList, DecklistWebsite website);
|
||||||
|
|
||||||
static void saveToClipboard(const DeckList *deckList, bool addComments = true, bool addSetNameAndNumber = true);
|
static void saveToClipboard(const DeckList &deckList, bool addComments = true, bool addSetNameAndNumber = true);
|
||||||
static bool saveToStream_Plain(QTextStream &out,
|
static bool saveToStream_Plain(QTextStream &out,
|
||||||
const DeckList *deckList,
|
const DeckList &deckList,
|
||||||
bool addComments = true,
|
bool addComments = true,
|
||||||
bool addSetNameAndNumber = true);
|
bool addSetNameAndNumber = true);
|
||||||
|
|
||||||
|
|
@ -84,18 +72,26 @@ public:
|
||||||
* @param printer The printer to render the decklist to.
|
* @param printer The printer to render the decklist to.
|
||||||
* @param deckList
|
* @param deckList
|
||||||
*/
|
*/
|
||||||
static void printDeckList(QPrinter *printer, const DeckList *deckList);
|
static void printDeckList(QPrinter *printer, const DeckList &deckList);
|
||||||
|
|
||||||
bool convertToCockatriceFormat(QString fileName);
|
bool convertToCockatriceFormat(const QString &fileName);
|
||||||
|
|
||||||
DeckList *getDeckList()
|
LoadedDeck &getDeck()
|
||||||
{
|
{
|
||||||
return deckList;
|
return loadedDeck;
|
||||||
|
}
|
||||||
|
const LoadedDeck &getDeck() const
|
||||||
|
{
|
||||||
|
return loadedDeck;
|
||||||
|
}
|
||||||
|
void setDeck(const LoadedDeck &deck)
|
||||||
|
{
|
||||||
|
loadedDeck = deck;
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node);
|
static void printDeckListNode(QTextCursor *cursor, const InnerDecklistNode *node);
|
||||||
static void saveToStream_DeckHeader(QTextStream &out, const DeckList *deckList);
|
static void saveToStream_DeckHeader(QTextStream &out, const DeckList &deckList);
|
||||||
|
|
||||||
static void saveToStream_DeckZone(QTextStream &out,
|
static void saveToStream_DeckZone(QTextStream &out,
|
||||||
const InnerDecklistNode *zoneNode,
|
const InnerDecklistNode *zoneNode,
|
||||||
|
|
@ -106,9 +102,6 @@ private:
|
||||||
QList<DecklistCardNode *> cards,
|
QList<DecklistCardNode *> cards,
|
||||||
bool addComments = true,
|
bool addComments = true,
|
||||||
bool addSetNameAndNumber = true);
|
bool addSetNameAndNumber = true);
|
||||||
|
|
||||||
[[nodiscard]] static QString getCardZoneFromName(const QString &cardName, QString currentZoneName);
|
|
||||||
[[nodiscard]] static QString getCompleteCardName(const QString &cardName);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -30,8 +30,8 @@ struct LoadedDeck
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
DeckList deckList; ///< The decklist itself
|
DeckList deckList; ///< The decklist itself
|
||||||
LoadInfo lastLoadInfo; ///< info about where the deck was loaded from
|
LoadInfo lastLoadInfo = {}; ///< info about where the deck was loaded from
|
||||||
|
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -57,17 +57,10 @@ void Logger::openLogfileSession()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
fileStream.setDevice(&fileHandle);
|
fileStream.setDevice(&fileHandle);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
|
||||||
fileStream << "Log session started at " << QDateTime::currentDateTime().toString() << Qt::endl;
|
fileStream << "Log session started at " << QDateTime::currentDateTime().toString() << Qt::endl;
|
||||||
fileStream << getClientVersion() << Qt::endl;
|
fileStream << getClientVersion() << Qt::endl;
|
||||||
fileStream << getSystemArchitecture() << Qt::endl;
|
fileStream << getSystemArchitecture() << Qt::endl;
|
||||||
fileStream << getClientInstallInfo() << Qt::endl;
|
fileStream << getClientInstallInfo() << Qt::endl;
|
||||||
#else
|
|
||||||
fileStream << "Log session started at " << QDateTime::currentDateTime().toString() << endl;
|
|
||||||
fileStream << getClientVersion() << endl;
|
|
||||||
fileStream << getSystemArchitecture() << endl;
|
|
||||||
fileStream << getClientInstallInfo() << endl;
|
|
||||||
#endif
|
|
||||||
logToFileEnabled = true;
|
logToFileEnabled = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -77,11 +70,7 @@ void Logger::closeLogfileSession()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
logToFileEnabled = false;
|
logToFileEnabled = false;
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
|
||||||
fileStream << "Log session closed at " << QDateTime::currentDateTime().toString() << Qt::endl;
|
fileStream << "Log session closed at " << QDateTime::currentDateTime().toString() << Qt::endl;
|
||||||
#else
|
|
||||||
fileStream << "Log session closed at " << QDateTime::currentDateTime().toString() << endl;
|
|
||||||
#endif
|
|
||||||
fileHandle.close();
|
fileHandle.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -103,11 +92,7 @@ void Logger::internalLog(const QString &message)
|
||||||
std::cerr << message.toStdString() << std::endl; // Print to stdout
|
std::cerr << message.toStdString() << std::endl; // Print to stdout
|
||||||
|
|
||||||
if (logToFileEnabled) {
|
if (logToFileEnabled) {
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
|
||||||
fileStream << message << Qt::endl; // Print to fileStream
|
fileStream << message << Qt::endl; // Print to fileStream
|
||||||
#else
|
|
||||||
fileStream << message << endl; // Print to fileStream
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -91,8 +91,9 @@ QWidget *CardGroupDisplayWidget::constructWidgetForIndex(QPersistentModelIndex i
|
||||||
if (indexToWidgetMap.contains(index)) {
|
if (indexToWidgetMap.contains(index)) {
|
||||||
return indexToWidgetMap[index];
|
return indexToWidgetMap[index];
|
||||||
}
|
}
|
||||||
auto cardName = deckListModel->data(index.sibling(index.row(), 1), Qt::EditRole).toString();
|
auto cardName = index.sibling(index.row(), DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
|
||||||
auto cardProviderId = deckListModel->data(index.sibling(index.row(), 4), Qt::EditRole).toString();
|
auto cardProviderId =
|
||||||
|
index.sibling(index.row(), DeckListModelColumns::CARD_PROVIDER_ID).data(Qt::EditRole).toString();
|
||||||
|
|
||||||
auto widget = new CardInfoPictureWithTextOverlayWidget(getLayoutParent(), true);
|
auto widget = new CardInfoPictureWithTextOverlayWidget(getLayoutParent(), true);
|
||||||
widget->setScaleFactor(cardSizeWidget->getSlider()->value());
|
widget->setScaleFactor(cardSizeWidget->getSlider()->value());
|
||||||
|
|
@ -114,7 +115,7 @@ void CardGroupDisplayWidget::updateCardDisplays()
|
||||||
|
|
||||||
// This doesn't really matter since overwrite the whole lessThan function to just compare dynamically anyway.
|
// This doesn't really matter since overwrite the whole lessThan function to just compare dynamically anyway.
|
||||||
proxy.setSortRole(Qt::EditRole);
|
proxy.setSortRole(Qt::EditRole);
|
||||||
proxy.sort(1, Qt::AscendingOrder);
|
proxy.sort(DeckListModelColumns::CARD_NAME, Qt::AscendingOrder);
|
||||||
|
|
||||||
// 1. trackedIndex is a source index → map it to proxy space
|
// 1. trackedIndex is a source index → map it to proxy space
|
||||||
QModelIndex proxyParent = proxy.mapFromSource(trackedIndex);
|
QModelIndex proxyParent = proxy.mapFromSource(trackedIndex);
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,7 @@ CardInfoDisplayWidget::CardInfoDisplayWidget(const CardRef &cardRef, QWidget *pa
|
||||||
layout->addWidget(text, 0, Qt::AlignCenter);
|
layout->addWidget(text, 0, Qt::AlignCenter);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
setFrameStyle(QFrame::Panel | QFrame::Raised);
|
setFrameStyle(static_cast<int>(QFrame::Panel) | QFrame::Raised);
|
||||||
|
|
||||||
int pixmapHeight = QGuiApplication::primaryScreen()->geometry().height() / 3;
|
int pixmapHeight = QGuiApplication::primaryScreen()->geometry().height() / 3;
|
||||||
int pixmapWidth = static_cast<int>(pixmapHeight / aspectRatio);
|
int pixmapWidth = static_cast<int>(pixmapHeight / aspectRatio);
|
||||||
|
|
|
||||||
|
|
@ -39,10 +39,6 @@ CardInfoPictureWidget::CardInfoPictureWidget(QWidget *parent, const bool _hoverT
|
||||||
setMouseTracking(true);
|
setMouseTracking(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
enlargedPixmapWidget = new CardInfoPictureEnlargedWidget(this->window());
|
|
||||||
enlargedPixmapWidget->hide();
|
|
||||||
connect(this, &QObject::destroyed, enlargedPixmapWidget, &CardInfoPictureEnlargedWidget::deleteLater);
|
|
||||||
|
|
||||||
hoverTimer = new QTimer(this);
|
hoverTimer = new QTimer(this);
|
||||||
hoverTimer->setSingleShot(true);
|
hoverTimer->setSingleShot(true);
|
||||||
connect(hoverTimer, &QTimer::timeout, this, &CardInfoPictureWidget::showEnlargedPixmap);
|
connect(hoverTimer, &QTimer::timeout, this, &CardInfoPictureWidget::showEnlargedPixmap);
|
||||||
|
|
@ -277,7 +273,7 @@ void CardInfoPictureWidget::leaveEvent(QEvent *event)
|
||||||
|
|
||||||
if (hoverToZoomEnabled) {
|
if (hoverToZoomEnabled) {
|
||||||
hoverTimer->stop();
|
hoverTimer->stop();
|
||||||
enlargedPixmapWidget->hide();
|
destroyEnlargedPixmapWidget();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (raiseOnEnter) {
|
if (raiseOnEnter) {
|
||||||
|
|
@ -294,7 +290,7 @@ void CardInfoPictureWidget::moveEvent(QMoveEvent *event)
|
||||||
QWidget::moveEvent(event);
|
QWidget::moveEvent(event);
|
||||||
|
|
||||||
hoverTimer->stop();
|
hoverTimer->stop();
|
||||||
enlargedPixmapWidget->hide();
|
destroyEnlargedPixmapWidget();
|
||||||
|
|
||||||
if (animation->state() == QAbstractAnimation::Running) {
|
if (animation->state() == QAbstractAnimation::Running) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -310,7 +306,7 @@ void CardInfoPictureWidget::mouseMoveEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::mouseMoveEvent(event);
|
QWidget::mouseMoveEvent(event);
|
||||||
|
|
||||||
if (hoverToZoomEnabled && enlargedPixmapWidget->isVisible()) {
|
if (hoverToZoomEnabled && enlargedPixmapWidget && enlargedPixmapWidget->isVisible()) {
|
||||||
const QPoint cursorPos = QCursor::pos();
|
const QPoint cursorPos = QCursor::pos();
|
||||||
const QRect screenGeometry = QGuiApplication::screenAt(cursorPos)->geometry();
|
const QRect screenGeometry = QGuiApplication::screenAt(cursorPos)->geometry();
|
||||||
const QSize widgetSize = enlargedPixmapWidget->size();
|
const QSize widgetSize = enlargedPixmapWidget->size();
|
||||||
|
|
@ -344,7 +340,7 @@ void CardInfoPictureWidget::mousePressEvent(QMouseEvent *event)
|
||||||
|
|
||||||
void CardInfoPictureWidget::hideEvent(QHideEvent *event)
|
void CardInfoPictureWidget::hideEvent(QHideEvent *event)
|
||||||
{
|
{
|
||||||
enlargedPixmapWidget->hide();
|
destroyEnlargedPixmapWidget();
|
||||||
QWidget::hideEvent(event);
|
QWidget::hideEvent(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -444,12 +440,19 @@ QMenu *CardInfoPictureWidget::createAddToOpenDeckMenu()
|
||||||
* If card information is available, the enlarged pixmap is loaded, positioned near the cursor,
|
* If card information is available, the enlarged pixmap is loaded, positioned near the cursor,
|
||||||
* and displayed.
|
* and displayed.
|
||||||
*/
|
*/
|
||||||
void CardInfoPictureWidget::showEnlargedPixmap() const
|
void CardInfoPictureWidget::showEnlargedPixmap()
|
||||||
{
|
{
|
||||||
if (!exactCard) {
|
if (!exactCard) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Lazy creation of the enlarged widget
|
||||||
|
if (!enlargedPixmapWidget) {
|
||||||
|
enlargedPixmapWidget = new CardInfoPictureEnlargedWidget(const_cast<CardInfoPictureWidget *>(this)->window());
|
||||||
|
enlargedPixmapWidget->hide();
|
||||||
|
connect(this, &QObject::destroyed, enlargedPixmapWidget, &CardInfoPictureEnlargedWidget::deleteLater);
|
||||||
|
}
|
||||||
|
|
||||||
const QSize enlargedSize(static_cast<int>(size().width() * 2), static_cast<int>(size().width() * aspectRatio * 2));
|
const QSize enlargedSize(static_cast<int>(size().width() * 2), static_cast<int>(size().width() * aspectRatio * 2));
|
||||||
enlargedPixmapWidget->setCardPixmap(exactCard, enlargedSize);
|
enlargedPixmapWidget->setCardPixmap(exactCard, enlargedSize);
|
||||||
|
|
||||||
|
|
@ -460,7 +463,6 @@ void CardInfoPictureWidget::showEnlargedPixmap() const
|
||||||
int newX = cursorPos.x() + enlargedPixmapOffset;
|
int newX = cursorPos.x() + enlargedPixmapOffset;
|
||||||
int newY = cursorPos.y() + enlargedPixmapOffset;
|
int newY = cursorPos.y() + enlargedPixmapOffset;
|
||||||
|
|
||||||
// Adjust if out of bounds
|
|
||||||
if (newX + widgetSize.width() > screenGeometry.right()) {
|
if (newX + widgetSize.width() > screenGeometry.right()) {
|
||||||
newX = cursorPos.x() - widgetSize.width() - enlargedPixmapOffset;
|
newX = cursorPos.x() - widgetSize.width() - enlargedPixmapOffset;
|
||||||
}
|
}
|
||||||
|
|
@ -472,3 +474,11 @@ void CardInfoPictureWidget::showEnlargedPixmap() const
|
||||||
|
|
||||||
enlargedPixmapWidget->show();
|
enlargedPixmapWidget->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CardInfoPictureWidget::destroyEnlargedPixmapWidget()
|
||||||
|
{
|
||||||
|
if (enlargedPixmapWidget) {
|
||||||
|
enlargedPixmapWidget->deleteLater();
|
||||||
|
enlargedPixmapWidget = nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -63,7 +63,8 @@ protected:
|
||||||
{
|
{
|
||||||
return resizedPixmap;
|
return resizedPixmap;
|
||||||
}
|
}
|
||||||
void showEnlargedPixmap() const;
|
void showEnlargedPixmap();
|
||||||
|
void destroyEnlargedPixmapWidget();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
ExactCard exactCard;
|
ExactCard exactCard;
|
||||||
|
|
|
||||||
|
|
@ -82,10 +82,11 @@ void DeckCardZoneDisplayWidget::cleanupInvalidCardGroup(CardGroupDisplayWidget *
|
||||||
|
|
||||||
void DeckCardZoneDisplayWidget::constructAppropriateWidget(QPersistentModelIndex index)
|
void DeckCardZoneDisplayWidget::constructAppropriateWidget(QPersistentModelIndex index)
|
||||||
{
|
{
|
||||||
auto categoryName = deckListModel->data(index.sibling(index.row(), 1), Qt::EditRole).toString();
|
|
||||||
if (indexToWidgetMap.contains(index)) {
|
if (indexToWidgetMap.contains(index)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto categoryName = index.sibling(index.row(), DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
|
||||||
if (displayType == DisplayType::Overlap) {
|
if (displayType == DisplayType::Overlap) {
|
||||||
auto *displayWidget = new OverlappedCardGroupDisplayWidget(
|
auto *displayWidget = new OverlappedCardGroupDisplayWidget(
|
||||||
cardGroupContainer, deckListModel, selectionModel, index, zoneName, categoryName, activeGroupCriteria,
|
cardGroupContainer, deckListModel, selectionModel, index, zoneName, categoryName, activeGroupCriteria,
|
||||||
|
|
@ -120,7 +121,7 @@ void DeckCardZoneDisplayWidget::displayCards()
|
||||||
QSortFilterProxyModel proxy;
|
QSortFilterProxyModel proxy;
|
||||||
proxy.setSourceModel(deckListModel);
|
proxy.setSourceModel(deckListModel);
|
||||||
proxy.setSortRole(Qt::EditRole);
|
proxy.setSortRole(Qt::EditRole);
|
||||||
proxy.sort(1, Qt::AscendingOrder);
|
proxy.sort(DeckListModelColumns::CARD_NAME, Qt::AscendingOrder);
|
||||||
|
|
||||||
// 1. trackedIndex is a source index → map it to proxy space
|
// 1. trackedIndex is a source index → map it to proxy space
|
||||||
QModelIndex proxyParent = proxy.mapFromSource(trackedIndex);
|
QModelIndex proxyParent = proxy.mapFromSource(trackedIndex);
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@
|
||||||
* @param outlineColor The color of the outline around the text.
|
* @param outlineColor The color of the outline around the text.
|
||||||
* @param fontSize The font size of the overlay text.
|
* @param fontSize The font size of the overlay text.
|
||||||
* @param alignment The alignment of the text within the overlay.
|
* @param alignment The alignment of the text within the overlay.
|
||||||
* @param _deckLoader The Deck Loader holding the Deck associated with this preview.
|
|
||||||
*
|
*
|
||||||
* Sets the widget's size policy and default border style.
|
* Sets the widget's size policy and default border style.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -21,32 +21,26 @@ void DeckListStatisticsAnalyzer::update()
|
||||||
manaCurveMap.clear();
|
manaCurveMap.clear();
|
||||||
manaDevotionMap.clear();
|
manaDevotionMap.clear();
|
||||||
|
|
||||||
auto nodes = model->getDeckList()->getCardNodes();
|
QList<ExactCard> cards = model->getCards();
|
||||||
|
|
||||||
for (auto *node : nodes) {
|
for (const ExactCard &card : cards) {
|
||||||
CardInfoPtr info = CardDatabaseManager::query()->getCardInfo(node->getName());
|
// ---- Mana curve ----
|
||||||
if (!info)
|
if (config.computeManaCurve) {
|
||||||
continue;
|
manaCurveMap[card.getInfo().getCmc().toInt()]++;
|
||||||
|
}
|
||||||
|
|
||||||
for (int i = 0; i < node->getNumber(); ++i) {
|
// ---- Mana base ----
|
||||||
// ---- Mana curve ----
|
if (config.computeManaBase) {
|
||||||
if (config.computeManaCurve) {
|
auto mana = determineManaProduction(card.getInfo().getText());
|
||||||
manaCurveMap[info->getCmc().toInt()]++;
|
for (auto it = mana.begin(); it != mana.end(); ++it)
|
||||||
}
|
manaBaseMap[it.key()] += it.value();
|
||||||
|
}
|
||||||
|
|
||||||
// ---- Mana base ----
|
// ---- Devotion ----
|
||||||
if (config.computeManaBase) {
|
if (config.computeDevotion) {
|
||||||
auto mana = determineManaProduction(info->getText());
|
auto devo = countManaSymbols(card.getInfo().getManaCost());
|
||||||
for (auto it = mana.begin(); it != mana.end(); ++it)
|
for (auto &d : devo)
|
||||||
manaBaseMap[it.key()] += it.value();
|
manaDevotionMap[d.first] += d.second;
|
||||||
}
|
|
||||||
|
|
||||||
// ---- Devotion ----
|
|
||||||
if (config.computeDevotion) {
|
|
||||||
auto devo = countManaSymbols(info->getManaCost());
|
|
||||||
for (auto &d : devo)
|
|
||||||
manaDevotionMap[d.first] += d.second;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,13 +134,13 @@ void DeckEditorDatabaseDisplayWidget::clearAllDatabaseFilters()
|
||||||
|
|
||||||
void DeckEditorDatabaseDisplayWidget::updateCard(const QModelIndex ¤t, const QModelIndex & /*previous*/)
|
void DeckEditorDatabaseDisplayWidget::updateCard(const QModelIndex ¤t, const QModelIndex & /*previous*/)
|
||||||
{
|
{
|
||||||
const QString cardName = current.sibling(current.row(), 0).data().toString();
|
|
||||||
|
|
||||||
if (!current.isValid()) {
|
if (!current.isValid()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!current.model()->hasChildren(current.sibling(current.row(), 0))) {
|
const QString cardName = current.siblingAtColumn(CardDatabaseModel::NameColumn).data().toString();
|
||||||
|
|
||||||
|
if (!current.model()->hasChildren(current.siblingAtColumn(CardDatabaseModel::NameColumn))) {
|
||||||
emit cardChanged(CardDatabaseManager::query()->getPreferredCard(cardName));
|
emit cardChanged(CardDatabaseManager::query()->getPreferredCard(cardName));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -172,7 +172,7 @@ ExactCard DeckEditorDatabaseDisplayWidget::currentCard() const
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString cardName = currentIndex.sibling(currentIndex.row(), 0).data().toString();
|
const QString cardName = currentIndex.siblingAtColumn(CardDatabaseModel::NameColumn).data().toString();
|
||||||
|
|
||||||
return CardDatabaseManager::query()->getPreferredCard(cardName);
|
return CardDatabaseManager::query()->getPreferredCard(cardName);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
#include "deck_editor_deck_dock_widget.h"
|
#include "deck_editor_deck_dock_widget.h"
|
||||||
|
|
||||||
#include "../../../client/settings/cache_settings.h"
|
#include "../../../client/settings/cache_settings.h"
|
||||||
#include "../../deck_loader/deck_loader.h"
|
|
||||||
#include "deck_list_style_proxy.h"
|
#include "deck_list_style_proxy.h"
|
||||||
|
#include "deck_state_manager.h"
|
||||||
|
|
||||||
#include <QComboBox>
|
#include <QComboBox>
|
||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
|
|
@ -38,7 +38,7 @@ static int findRestoreIndex(const CardRef &wanted, const QComboBox *combo)
|
||||||
}
|
}
|
||||||
|
|
||||||
DeckEditorDeckDockWidget::DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent)
|
DeckEditorDeckDockWidget::DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent)
|
||||||
: QDockWidget(parent), deckEditor(parent)
|
: QDockWidget(parent), deckEditor(parent), deckStateManager(parent->deckStateManager)
|
||||||
{
|
{
|
||||||
setObjectName("deckDock");
|
setObjectName("deckDock");
|
||||||
|
|
||||||
|
|
@ -52,19 +52,19 @@ DeckEditorDeckDockWidget::DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::createDeckDock()
|
void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
{
|
{
|
||||||
deckModel = new DeckListModel(this);
|
connect(getModel(), &DeckListModel::deckHashChanged, this, &DeckEditorDeckDockWidget::updateHash);
|
||||||
deckModel->setObjectName("deckModel");
|
|
||||||
connect(deckModel, &DeckListModel::deckHashChanged, this, &DeckEditorDeckDockWidget::updateHash);
|
|
||||||
|
|
||||||
deckLoader = new DeckLoader(this, deckModel->getDeckList());
|
|
||||||
|
|
||||||
proxy = new DeckListStyleProxy(this);
|
proxy = new DeckListStyleProxy(this);
|
||||||
proxy->setSourceModel(deckModel);
|
proxy->setSourceModel(getModel());
|
||||||
|
|
||||||
historyManagerWidget = new DeckListHistoryManagerWidget(deckModel, proxy, deckEditor->getHistoryManager(), this);
|
historyManagerWidget = new DeckListHistoryManagerWidget(deckStateManager, proxy, this);
|
||||||
connect(historyManagerWidget, &DeckListHistoryManagerWidget::requestDisplayWidgetSync, this,
|
connect(historyManagerWidget, &DeckListHistoryManagerWidget::requestDisplayWidgetSync, this,
|
||||||
&DeckEditorDeckDockWidget::syncDisplayWidgetsToModel);
|
&DeckEditorDeckDockWidget::syncDisplayWidgetsToModel);
|
||||||
|
|
||||||
|
connect(deckStateManager, &DeckStateManager::focusIndexChanged, this, &DeckEditorDeckDockWidget::setSelectedIndex);
|
||||||
|
connect(deckStateManager, &DeckStateManager::deckReplaced, this,
|
||||||
|
&DeckEditorDeckDockWidget::syncDisplayWidgetsToModel);
|
||||||
|
|
||||||
deckView = new QTreeView();
|
deckView = new QTreeView();
|
||||||
deckView->setObjectName("deckView");
|
deckView->setObjectName("deckView");
|
||||||
deckView->setModel(proxy);
|
deckView->setModel(proxy);
|
||||||
|
|
@ -76,14 +76,14 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
connect(deckView->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
|
connect(deckView->selectionModel(), &QItemSelectionModel::currentRowChanged, this,
|
||||||
&DeckEditorDeckDockWidget::updateCard);
|
&DeckEditorDeckDockWidget::updateCard);
|
||||||
connect(deckView, &QTreeView::doubleClicked, this, &DeckEditorDeckDockWidget::actSwapCard);
|
connect(deckView, &QTreeView::doubleClicked, this, &DeckEditorDeckDockWidget::actSwapSelection);
|
||||||
deckView->setContextMenuPolicy(Qt::CustomContextMenu);
|
deckView->setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
connect(deckView, &QTreeView::customContextMenuRequested, this, &DeckEditorDeckDockWidget::decklistCustomMenu);
|
connect(deckView, &QTreeView::customContextMenuRequested, this, &DeckEditorDeckDockWidget::decklistCustomMenu);
|
||||||
connect(&deckViewKeySignals, &KeySignals::onShiftS, this, &DeckEditorDeckDockWidget::actSwapCard);
|
connect(&deckViewKeySignals, &KeySignals::onShiftS, this, &DeckEditorDeckDockWidget::actSwapSelection);
|
||||||
connect(&deckViewKeySignals, &KeySignals::onEnter, this, &DeckEditorDeckDockWidget::actIncrement);
|
connect(&deckViewKeySignals, &KeySignals::onEnter, this, &DeckEditorDeckDockWidget::actIncrementSelection);
|
||||||
connect(&deckViewKeySignals, &KeySignals::onCtrlAltEqual, this, &DeckEditorDeckDockWidget::actIncrement);
|
connect(&deckViewKeySignals, &KeySignals::onCtrlAltEqual, this, &DeckEditorDeckDockWidget::actIncrementSelection);
|
||||||
connect(&deckViewKeySignals, &KeySignals::onCtrlAltMinus, this, &DeckEditorDeckDockWidget::actDecrementSelection);
|
connect(&deckViewKeySignals, &KeySignals::onCtrlAltMinus, this, &DeckEditorDeckDockWidget::actDecrementSelection);
|
||||||
connect(&deckViewKeySignals, &KeySignals::onShiftRight, this, &DeckEditorDeckDockWidget::actIncrement);
|
connect(&deckViewKeySignals, &KeySignals::onShiftRight, this, &DeckEditorDeckDockWidget::actIncrementSelection);
|
||||||
connect(&deckViewKeySignals, &KeySignals::onShiftLeft, this, &DeckEditorDeckDockWidget::actDecrementSelection);
|
connect(&deckViewKeySignals, &KeySignals::onShiftLeft, this, &DeckEditorDeckDockWidget::actDecrementSelection);
|
||||||
connect(&deckViewKeySignals, &KeySignals::onDelete, this, &DeckEditorDeckDockWidget::actRemoveCard);
|
connect(&deckViewKeySignals, &KeySignals::onDelete, this, &DeckEditorDeckDockWidget::actRemoveCard);
|
||||||
|
|
||||||
|
|
@ -97,7 +97,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
nameDebounceTimer = new QTimer(this);
|
nameDebounceTimer = new QTimer(this);
|
||||||
nameDebounceTimer->setSingleShot(true);
|
nameDebounceTimer->setSingleShot(true);
|
||||||
nameDebounceTimer->setInterval(300); // debounce duration in ms
|
nameDebounceTimer->setInterval(300); // debounce duration in ms
|
||||||
connect(nameDebounceTimer, &QTimer::timeout, this, [this]() { updateName(nameEdit->text()); });
|
connect(nameDebounceTimer, &QTimer::timeout, this, &DeckEditorDeckDockWidget::writeName);
|
||||||
|
|
||||||
connect(nameEdit, &LineEditUnfocusable::textChanged, this, [this]() {
|
connect(nameEdit, &LineEditUnfocusable::textChanged, this, [this]() {
|
||||||
nameDebounceTimer->start(); // restart debounce timer
|
nameDebounceTimer->start(); // restart debounce timer
|
||||||
|
|
@ -141,7 +141,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
commentsDebounceTimer = new QTimer(this);
|
commentsDebounceTimer = new QTimer(this);
|
||||||
commentsDebounceTimer->setSingleShot(true);
|
commentsDebounceTimer->setSingleShot(true);
|
||||||
commentsDebounceTimer->setInterval(400); // longer debounce for multi-line
|
commentsDebounceTimer->setInterval(400); // longer debounce for multi-line
|
||||||
connect(commentsDebounceTimer, &QTimer::timeout, this, [this]() { updateComments(); });
|
connect(commentsDebounceTimer, &QTimer::timeout, this, &DeckEditorDeckDockWidget::writeComments);
|
||||||
|
|
||||||
connect(commentsEdit, &QTextEdit::textChanged, this, [this]() {
|
connect(commentsEdit, &QTextEdit::textChanged, this, [this]() {
|
||||||
commentsDebounceTimer->start(); // restart debounce timer
|
commentsDebounceTimer->start(); // restart debounce timer
|
||||||
|
|
@ -152,18 +152,21 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
bannerCardLabel->setText(tr("Banner Card"));
|
bannerCardLabel->setText(tr("Banner Card"));
|
||||||
bannerCardLabel->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
|
bannerCardLabel->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
|
||||||
bannerCardComboBox = new QComboBox(this);
|
bannerCardComboBox = new QComboBox(this);
|
||||||
connect(deckModel, &DeckListModel::dataChanged, this, [this]() {
|
connect(getModel(), &DeckListModel::dataChanged, this, [this]() {
|
||||||
// Delay the update to avoid race conditions
|
// Delay the update to avoid race conditions
|
||||||
QTimer::singleShot(100, this, &DeckEditorDeckDockWidget::updateBannerCardComboBox);
|
QTimer::singleShot(100, this, &DeckEditorDeckDockWidget::updateBannerCardComboBox);
|
||||||
});
|
});
|
||||||
|
connect(getModel(), &DeckListModel::cardAddedAt, this, &DeckEditorDeckDockWidget::recursiveExpand);
|
||||||
|
connect(getModel(), &DeckListModel::modelReset, this, &DeckEditorDeckDockWidget::expandAll);
|
||||||
|
|
||||||
connect(bannerCardComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
connect(bannerCardComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this,
|
||||||
&DeckEditorDeckDockWidget::setBannerCard);
|
&DeckEditorDeckDockWidget::writeBannerCard);
|
||||||
bannerCardComboBox->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
|
bannerCardComboBox->setHidden(!SettingsCache::instance().getDeckEditorBannerCardComboBoxVisible());
|
||||||
|
|
||||||
deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, deckModel->getDeckList()->getTags());
|
deckTagsDisplayWidget = new DeckPreviewDeckTagsDisplayWidget(this, {});
|
||||||
deckTagsDisplayWidget->setHidden(!SettingsCache::instance().getDeckEditorTagsWidgetVisible());
|
deckTagsDisplayWidget->setHidden(!SettingsCache::instance().getDeckEditorTagsWidgetVisible());
|
||||||
connect(deckTagsDisplayWidget, &DeckPreviewDeckTagsDisplayWidget::tagsChanged, this,
|
connect(deckTagsDisplayWidget, &DeckPreviewDeckTagsDisplayWidget::tagsChanged, deckStateManager,
|
||||||
&DeckEditorDeckDockWidget::setTags);
|
&DeckStateManager::setTags);
|
||||||
|
|
||||||
activeGroupCriteriaLabel = new QLabel(this);
|
activeGroupCriteriaLabel = new QLabel(this);
|
||||||
|
|
||||||
|
|
@ -172,16 +175,14 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
activeGroupCriteriaComboBox->addItem(tr("Mana Cost"), DeckListModelGroupCriteria::MANA_COST);
|
activeGroupCriteriaComboBox->addItem(tr("Mana Cost"), DeckListModelGroupCriteria::MANA_COST);
|
||||||
activeGroupCriteriaComboBox->addItem(tr("Colors"), DeckListModelGroupCriteria::COLOR);
|
activeGroupCriteriaComboBox->addItem(tr("Colors"), DeckListModelGroupCriteria::COLOR);
|
||||||
connect(activeGroupCriteriaComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() {
|
connect(activeGroupCriteriaComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), [this]() {
|
||||||
deckModel->setActiveGroupCriteria(static_cast<DeckListModelGroupCriteria::Type>(
|
getModel()->setActiveGroupCriteria(static_cast<DeckListModelGroupCriteria::Type>(
|
||||||
activeGroupCriteriaComboBox->currentData(Qt::UserRole).toInt()));
|
activeGroupCriteriaComboBox->currentData(Qt::UserRole).toInt()));
|
||||||
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
getModel()->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
||||||
deckView->expandAll();
|
|
||||||
deckView->expandAll();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
aIncrement = new QAction(QString(), this);
|
aIncrement = new QAction(QString(), this);
|
||||||
aIncrement->setIcon(QPixmap("theme:icons/increment"));
|
aIncrement->setIcon(QPixmap("theme:icons/increment"));
|
||||||
connect(aIncrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actIncrement);
|
connect(aIncrement, &QAction::triggered, this, &DeckEditorDeckDockWidget::actIncrementSelection);
|
||||||
auto *tbIncrement = new QToolButton(this);
|
auto *tbIncrement = new QToolButton(this);
|
||||||
tbIncrement->setDefaultAction(aIncrement);
|
tbIncrement->setDefaultAction(aIncrement);
|
||||||
|
|
||||||
|
|
@ -199,7 +200,7 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
|
|
||||||
aSwapCard = new QAction(QString(), this);
|
aSwapCard = new QAction(QString(), this);
|
||||||
aSwapCard->setIcon(QPixmap("theme:icons/swap"));
|
aSwapCard->setIcon(QPixmap("theme:icons/swap"));
|
||||||
connect(aSwapCard, &QAction::triggered, this, &DeckEditorDeckDockWidget::actSwapCard);
|
connect(aSwapCard, &QAction::triggered, this, &DeckEditorDeckDockWidget::actSwapSelection);
|
||||||
auto *tbSwapCard = new QToolButton(this);
|
auto *tbSwapCard = new QToolButton(this);
|
||||||
tbSwapCard->setDefaultAction(aSwapCard);
|
tbSwapCard->setDefaultAction(aSwapCard);
|
||||||
|
|
||||||
|
|
@ -283,21 +284,21 @@ void DeckEditorDeckDockWidget::createDeckDock()
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::initializeFormats()
|
void DeckEditorDeckDockWidget::initializeFormats()
|
||||||
{
|
{
|
||||||
QMap<QString, int> allFormats = CardDatabaseManager::query()->getAllFormatsWithCount();
|
QStringList allFormats = CardDatabaseManager::query()->getAllFormatsWithCount().keys();
|
||||||
|
|
||||||
formatComboBox->clear(); // Remove "Loading Database..."
|
formatComboBox->clear(); // Remove "Loading Database..."
|
||||||
formatComboBox->setEnabled(true);
|
formatComboBox->setEnabled(true);
|
||||||
|
|
||||||
// Populate with formats
|
// Populate with formats
|
||||||
formatComboBox->addItem("", "");
|
formatComboBox->addItem("", "");
|
||||||
for (auto it = allFormats.constBegin(); it != allFormats.constEnd(); ++it) {
|
for (auto formatName : allFormats) {
|
||||||
QString displayText = QString("%1").arg(it.key());
|
formatComboBox->addItem(formatName, formatName); // store the raw key in itemData
|
||||||
formatComboBox->addItem(displayText, it.key()); // store the raw key in itemData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deckModel->getDeckList()->getGameFormat().isEmpty()) {
|
QString format = deckStateManager->getMetadata().gameFormat;
|
||||||
deckModel->setActiveFormat(deckModel->getDeckList()->getGameFormat());
|
if (!format.isEmpty()) {
|
||||||
formatComboBox->setCurrentIndex(formatComboBox->findData(deckModel->getDeckList()->getGameFormat()));
|
getModel()->setActiveFormat(format);
|
||||||
|
formatComboBox->setCurrentIndex(formatComboBox->findData(format));
|
||||||
} else {
|
} else {
|
||||||
// Ensure no selection is visible initially
|
// Ensure no selection is visible initially
|
||||||
formatComboBox->setCurrentIndex(-1);
|
formatComboBox->setCurrentIndex(-1);
|
||||||
|
|
@ -306,11 +307,10 @@ void DeckEditorDeckDockWidget::initializeFormats()
|
||||||
connect(formatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
connect(formatComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this](int index) {
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
QString formatKey = formatComboBox->itemData(index).toString();
|
QString formatKey = formatComboBox->itemData(index).toString();
|
||||||
deckModel->setActiveFormat(formatKey);
|
deckStateManager->setFormat(formatKey);
|
||||||
} else {
|
} else {
|
||||||
deckModel->setActiveFormat(QString()); // clear format if deselected
|
deckStateManager->setFormat(""); // clear format if deselected
|
||||||
}
|
}
|
||||||
emit deckModified();
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -319,17 +319,17 @@ ExactCard DeckEditorDeckDockWidget::getCurrentCard()
|
||||||
QModelIndex current = deckView->selectionModel()->currentIndex();
|
QModelIndex current = deckView->selectionModel()->currentIndex();
|
||||||
if (!current.isValid())
|
if (!current.isValid())
|
||||||
return {};
|
return {};
|
||||||
const QString cardName = current.sibling(current.row(), 1).data().toString();
|
const QString cardName = current.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
|
||||||
const QString cardProviderID = current.sibling(current.row(), 4).data().toString();
|
const QString cardProviderID = current.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data().toString();
|
||||||
const QModelIndex gparent = current.parent().parent();
|
const QModelIndex gparent = current.parent().parent();
|
||||||
|
|
||||||
if (!gparent.isValid()) {
|
if (!gparent.isValid()) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
const QString zoneName = gparent.sibling(gparent.row(), 1).data(Qt::EditRole).toString();
|
const QString zoneName = gparent.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
|
||||||
|
|
||||||
if (!current.model()->hasChildren(current.sibling(current.row(), 0))) {
|
if (!current.model()->hasChildren(current.siblingAtColumn(DeckListModelColumns::CARD_AMOUNT))) {
|
||||||
if (ExactCard selectedCard = CardDatabaseManager::query()->getCard({cardName, cardProviderID})) {
|
if (ExactCard selectedCard = CardDatabaseManager::query()->getCard({cardName, cardProviderID})) {
|
||||||
return selectedCard;
|
return selectedCard;
|
||||||
}
|
}
|
||||||
|
|
@ -340,43 +340,37 @@ ExactCard DeckEditorDeckDockWidget::getCurrentCard()
|
||||||
void DeckEditorDeckDockWidget::updateCard(const QModelIndex /*¤t*/, const QModelIndex & /*previous*/)
|
void DeckEditorDeckDockWidget::updateCard(const QModelIndex /*¤t*/, const QModelIndex & /*previous*/)
|
||||||
{
|
{
|
||||||
if (ExactCard card = getCurrentCard()) {
|
if (ExactCard card = getCurrentCard()) {
|
||||||
emit cardChanged(card);
|
emit selectedCardChanged(card);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::updateName(const QString &name)
|
/**
|
||||||
|
* @brief Writes the contents of the name textBox to the DeckStateManager
|
||||||
|
*/
|
||||||
|
void DeckEditorDeckDockWidget::writeName()
|
||||||
{
|
{
|
||||||
emit requestDeckHistorySave(
|
QString name = nameEdit->text();
|
||||||
QString(tr("Rename deck to \"%1\" from \"%2\"")).arg(name).arg(deckLoader->getDeckList()->getName()));
|
deckStateManager->setName(name);
|
||||||
deckModel->getDeckList()->setName(name);
|
|
||||||
deckEditor->setModified(name.isEmpty());
|
|
||||||
emit nameChanged();
|
|
||||||
emit deckModified();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::updateComments()
|
/**
|
||||||
|
* @brief Writes the contents of the comments textBox to the DeckStateManager
|
||||||
|
*/
|
||||||
|
void DeckEditorDeckDockWidget::writeComments()
|
||||||
{
|
{
|
||||||
emit requestDeckHistorySave(tr("Updated comments (was %1 chars, now %2 chars)")
|
QString comments = commentsEdit->toPlainText();
|
||||||
.arg(deckLoader->getDeckList()->getComments().size())
|
deckStateManager->setComments(comments);
|
||||||
.arg(commentsEdit->toPlainText().size()));
|
|
||||||
|
|
||||||
deckModel->getDeckList()->setComments(commentsEdit->toPlainText());
|
|
||||||
deckEditor->setModified(commentsEdit->toPlainText().isEmpty());
|
|
||||||
emit commentsChanged();
|
|
||||||
emit deckModified();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::updateHash()
|
void DeckEditorDeckDockWidget::updateHash()
|
||||||
{
|
{
|
||||||
hashLabel->setText(deckModel->getDeckList()->getDeckHash());
|
hashLabel->setText(deckStateManager->getDeckHash());
|
||||||
emit hashChanged();
|
|
||||||
emit deckModified();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
{
|
{
|
||||||
// Store current banner card identity
|
// Store current banner card identity
|
||||||
CardRef wanted = deckModel->getDeckList()->getBannerCard();
|
CardRef wanted = deckStateManager->getMetadata().bannerCard;
|
||||||
|
|
||||||
// Block signals temporarily
|
// Block signals temporarily
|
||||||
bool wasBlocked = bannerCardComboBox->blockSignals(true);
|
bool wasBlocked = bannerCardComboBox->blockSignals(true);
|
||||||
|
|
@ -386,15 +380,15 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
|
|
||||||
// Collect unique (name, providerId) pairs
|
// Collect unique (name, providerId) pairs
|
||||||
QSet<QPair<QString, QString>> bannerCardSet;
|
QSet<QPair<QString, QString>> bannerCardSet;
|
||||||
QList<const DecklistCardNode *> cardsInDeck = deckModel->getDeckList()->getCardNodes();
|
QList<CardRef> cardsInDeck = getModel()->getCardRefs();
|
||||||
|
|
||||||
for (auto currentCard : cardsInDeck) {
|
for (auto cardRef : cardsInDeck) {
|
||||||
if (!CardDatabaseManager::query()->getCard(currentCard->toCardRef())) {
|
if (!CardDatabaseManager::query()->getCard(cardRef)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Insert one entry per distinct card, ignore copies
|
// Insert one entry per distinct card, ignore copies
|
||||||
bannerCardSet.insert({currentCard->getName(), currentCard->getCardProviderId()});
|
bannerCardSet.insert({cardRef.name, cardRef.providerId});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Convert to sorted list
|
// Convert to sorted list
|
||||||
|
|
@ -415,7 +409,6 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
// Handle results
|
// Handle results
|
||||||
if (restoreIndex != -1) {
|
if (restoreIndex != -1) {
|
||||||
bannerCardComboBox->setCurrentIndex(restoreIndex);
|
bannerCardComboBox->setCurrentIndex(restoreIndex);
|
||||||
syncDeckListBannerCardWithComboBox();
|
|
||||||
} else {
|
} else {
|
||||||
// Add a placeholder "-" and set it as the current selection
|
// Add a placeholder "-" and set it as the current selection
|
||||||
bannerCardComboBox->insertItem(0, "-");
|
bannerCardComboBox->insertItem(0, "-");
|
||||||
|
|
@ -426,25 +419,14 @@ void DeckEditorDeckDockWidget::updateBannerCardComboBox()
|
||||||
bannerCardComboBox->blockSignals(wasBlocked);
|
bannerCardComboBox->blockSignals(wasBlocked);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::setBannerCard(int /* changedIndex */)
|
/**
|
||||||
|
* @brief Writes the selected bannerCard to the DeckStateManager
|
||||||
|
*/
|
||||||
|
void DeckEditorDeckDockWidget::writeBannerCard(int index)
|
||||||
{
|
{
|
||||||
emit requestDeckHistorySave(tr("Banner card changed"));
|
auto [name, id] = bannerCardComboBox->itemData(index).value<QPair<QString, QString>>();
|
||||||
syncDeckListBannerCardWithComboBox();
|
CardRef bannerCard = {name, id};
|
||||||
deckEditor->setModified(true);
|
deckStateManager->setBannerCard(bannerCard);
|
||||||
emit deckModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::setTags(const QStringList &tags)
|
|
||||||
{
|
|
||||||
deckModel->getDeckList()->setTags(tags);
|
|
||||||
deckEditor->setModified(true);
|
|
||||||
emit deckModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::syncDeckListBannerCardWithComboBox()
|
|
||||||
{
|
|
||||||
auto [name, id] = bannerCardComboBox->currentData().value<QPair<QString, QString>>();
|
|
||||||
deckModel->getDeckList()->setBannerCard({name, id});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::updateShowBannerCardComboBox(const bool visible)
|
void DeckEditorDeckDockWidget::updateShowBannerCardComboBox(const bool visible)
|
||||||
|
|
@ -460,7 +442,7 @@ void DeckEditorDeckDockWidget::updateShowTagsWidget(const bool visible)
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::syncBannerCardComboBoxSelectionWithDeck()
|
void DeckEditorDeckDockWidget::syncBannerCardComboBoxSelectionWithDeck()
|
||||||
{
|
{
|
||||||
if (deckModel->getDeckList()->getBannerCard().name == "") {
|
if (deckStateManager->getMetadata().bannerCard.name == "") {
|
||||||
if (bannerCardComboBox->findText("-") != -1) {
|
if (bannerCardComboBox->findText("-") != -1) {
|
||||||
bannerCardComboBox->setCurrentIndex(bannerCardComboBox->findText("-"));
|
bannerCardComboBox->setCurrentIndex(bannerCardComboBox->findText("-"));
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -468,37 +450,26 @@ void DeckEditorDeckDockWidget::syncBannerCardComboBoxSelectionWithDeck()
|
||||||
bannerCardComboBox->setCurrentIndex(0);
|
bannerCardComboBox->setCurrentIndex(0);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bannerCardComboBox->setCurrentText(deckModel->getDeckList()->getBannerCard().name);
|
bannerCardComboBox->setCurrentText(deckStateManager->getMetadata().bannerCard.name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
void DeckEditorDeckDockWidget::setSelectedIndex(const QModelIndex &newCardIndex)
|
||||||
* Sets the currently active deck for this tab
|
|
||||||
* @param _deck The deck. Takes ownership of the object
|
|
||||||
*/
|
|
||||||
void DeckEditorDeckDockWidget::setDeck(DeckLoader *_deck)
|
|
||||||
{
|
{
|
||||||
deckLoader = _deck;
|
deckView->clearSelection();
|
||||||
deckLoader->setParent(this);
|
deckView->setCurrentIndex(newCardIndex);
|
||||||
deckModel->setDeckList(deckLoader->getDeckList());
|
recursiveExpand(newCardIndex);
|
||||||
connect(deckLoader, &DeckLoader::deckLoaded, deckModel, &DeckListModel::rebuildTree);
|
deckView->setFocus(Qt::FocusReason::MouseFocusReason);
|
||||||
|
|
||||||
emit requestDeckHistoryClear();
|
|
||||||
historyManagerWidget->setDeckListModel(deckModel);
|
|
||||||
|
|
||||||
syncDisplayWidgetsToModel();
|
|
||||||
|
|
||||||
emit deckChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel()
|
void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel()
|
||||||
{
|
{
|
||||||
nameEdit->blockSignals(true);
|
nameEdit->blockSignals(true);
|
||||||
nameEdit->setText(deckModel->getDeckList()->getName());
|
nameEdit->setText(deckStateManager->getMetadata().name);
|
||||||
nameEdit->blockSignals(false);
|
nameEdit->blockSignals(false);
|
||||||
|
|
||||||
commentsEdit->blockSignals(true);
|
commentsEdit->blockSignals(true);
|
||||||
commentsEdit->setText(deckModel->getDeckList()->getComments());
|
commentsEdit->setText(deckStateManager->getMetadata().comments);
|
||||||
commentsEdit->blockSignals(false);
|
commentsEdit->blockSignals(false);
|
||||||
|
|
||||||
bannerCardComboBox->blockSignals(true);
|
bannerCardComboBox->blockSignals(true);
|
||||||
|
|
@ -507,61 +478,100 @@ void DeckEditorDeckDockWidget::syncDisplayWidgetsToModel()
|
||||||
bannerCardComboBox->blockSignals(false);
|
bannerCardComboBox->blockSignals(false);
|
||||||
updateHash();
|
updateHash();
|
||||||
sortDeckModelToDeckView();
|
sortDeckModelToDeckView();
|
||||||
expandAll();
|
|
||||||
|
|
||||||
deckTagsDisplayWidget->setTags(deckModel->getDeckList()->getTags());
|
deckTagsDisplayWidget->setTags(deckStateManager->getMetadata().tags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::sortDeckModelToDeckView()
|
void DeckEditorDeckDockWidget::sortDeckModelToDeckView()
|
||||||
{
|
{
|
||||||
deckModel->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
getModel()->sort(deckView->header()->sortIndicatorSection(), deckView->header()->sortIndicatorOrder());
|
||||||
deckModel->setActiveFormat(deckModel->getDeckList()->getGameFormat());
|
getModel()->setActiveFormat(deckStateManager->getMetadata().gameFormat);
|
||||||
formatComboBox->setCurrentIndex(formatComboBox->findData(deckModel->getDeckList()->getGameFormat()));
|
formatComboBox->setCurrentIndex(formatComboBox->findData(deckStateManager->getMetadata().gameFormat));
|
||||||
deckView->expandAll();
|
|
||||||
deckView->expandAll();
|
|
||||||
|
|
||||||
emit deckChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckLoader *DeckEditorDeckDockWidget::getDeckLoader()
|
|
||||||
{
|
|
||||||
return deckLoader;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckList *DeckEditorDeckDockWidget::getDeckList()
|
|
||||||
{
|
|
||||||
return deckModel->getDeckList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resets the tab to the state for a blank new tab.
|
* @brief Convenience method to get the underlying model instance from the DeckStateManager
|
||||||
*/
|
*/
|
||||||
void DeckEditorDeckDockWidget::cleanDeck()
|
DeckListModel *DeckEditorDeckDockWidget::getModel() const
|
||||||
{
|
{
|
||||||
deckModel->cleanList();
|
return deckStateManager->getModel();
|
||||||
nameEdit->setText(QString());
|
|
||||||
emit nameChanged();
|
|
||||||
commentsEdit->setText(QString());
|
|
||||||
emit commentsChanged();
|
|
||||||
hashLabel->setText(QString());
|
|
||||||
emit hashChanged();
|
|
||||||
emit deckModified();
|
|
||||||
emit deckChanged();
|
|
||||||
updateBannerCardComboBox();
|
|
||||||
deckTagsDisplayWidget->setTags(deckModel->getDeckList()->getTags());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::recursiveExpand(const QModelIndex &index)
|
void DeckEditorDeckDockWidget::selectPrevCard()
|
||||||
{
|
{
|
||||||
if (index.parent().isValid())
|
changeSelectedCard(-1);
|
||||||
recursiveExpand(index.parent());
|
|
||||||
deckView->expand(index);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DeckEditorDeckDockWidget::selectNextCard()
|
||||||
|
{
|
||||||
|
changeSelectedCard(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Selects a card based on the change direction.
|
||||||
|
*
|
||||||
|
* @param changeBy The direction to change, -1 for previous, 1 for next.
|
||||||
|
*/
|
||||||
|
void DeckEditorDeckDockWidget::changeSelectedCard(int changeBy)
|
||||||
|
{
|
||||||
|
if (changeBy == 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the current index of the selected item
|
||||||
|
auto deckViewCurrentIndex = deckView->currentIndex();
|
||||||
|
|
||||||
|
// For some reason, if the deckModel is modified but the view is not manually reselected,
|
||||||
|
// currentIndex will return an index for the underlying deckModel instead of the proxy.
|
||||||
|
// That index will return an invalid index when indexBelow/indexAbove crosses a header node,
|
||||||
|
// causing the selection to fail to move down.
|
||||||
|
/// \todo Figure out why it's happening so we can do a proper fix instead of a hacky workaround
|
||||||
|
if (deckViewCurrentIndex.model() == proxy->sourceModel()) {
|
||||||
|
deckViewCurrentIndex = proxy->mapFromSource(deckViewCurrentIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto nextIndex = deckViewCurrentIndex.siblingAtRow(deckViewCurrentIndex.row() + changeBy);
|
||||||
|
if (!nextIndex.isValid()) {
|
||||||
|
nextIndex = deckViewCurrentIndex;
|
||||||
|
|
||||||
|
// Increment to the next valid index, skipping header rows
|
||||||
|
AbstractDecklistNode *node;
|
||||||
|
do {
|
||||||
|
if (changeBy > 0) {
|
||||||
|
nextIndex = deckView->indexBelow(nextIndex);
|
||||||
|
} else {
|
||||||
|
nextIndex = deckView->indexAbove(nextIndex);
|
||||||
|
}
|
||||||
|
node = static_cast<AbstractDecklistNode *>(nextIndex.internalPointer());
|
||||||
|
} while (node && node->isDeckHeader());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nextIndex.isValid()) {
|
||||||
|
deckView->setCurrentIndex(nextIndex);
|
||||||
|
deckView->setFocus(Qt::FocusReason::MouseFocusReason);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Expands all parents of the given index.
|
||||||
|
* @param sourceIndex The index to expand (model source index)
|
||||||
|
*/
|
||||||
|
void DeckEditorDeckDockWidget::recursiveExpand(const QModelIndex &sourceIndex)
|
||||||
|
{
|
||||||
|
auto index = proxy->mapFromSource(sourceIndex);
|
||||||
|
|
||||||
|
while (index.parent().isValid()) {
|
||||||
|
index = index.parent();
|
||||||
|
deckView->expand(index);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Fully expands all levels of the deck view
|
||||||
|
*/
|
||||||
void DeckEditorDeckDockWidget::expandAll()
|
void DeckEditorDeckDockWidget::expandAll()
|
||||||
{
|
{
|
||||||
deckView->expandAll();
|
deckView->expandRecursively(deckView->rootIndex());
|
||||||
deckView->expandAll();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -575,7 +585,7 @@ QModelIndexList DeckEditorDeckDockWidget::getSelectedCardNodes() const
|
||||||
auto selectedRows = deckView->selectionModel()->selectedRows();
|
auto selectedRows = deckView->selectionModel()->selectedRows();
|
||||||
|
|
||||||
const auto notLeafNode = [this](const QModelIndex &index) {
|
const auto notLeafNode = [this](const QModelIndex &index) {
|
||||||
return deckModel->hasChildren(proxy->mapToSource(index));
|
return getModel()->hasChildren(proxy->mapToSource(index));
|
||||||
};
|
};
|
||||||
selectedRows.erase(std::remove_if(selectedRows.begin(), selectedRows.end(), notLeafNode), selectedRows.end());
|
selectedRows.erase(std::remove_if(selectedRows.begin(), selectedRows.end(), notLeafNode), selectedRows.end());
|
||||||
|
|
||||||
|
|
@ -583,16 +593,39 @@ QModelIndexList DeckEditorDeckDockWidget::getSelectedCardNodes() const
|
||||||
return selectedRows;
|
return selectedRows;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::actIncrement()
|
void DeckEditorDeckDockWidget::actAddCard(const ExactCard &card, const QString &_zoneName)
|
||||||
|
{
|
||||||
|
if (!card) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString zoneName = card.getInfo().getIsToken() ? DECK_ZONE_TOKENS : _zoneName;
|
||||||
|
deckStateManager->addCard(card, zoneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckEditorDeckDockWidget::actIncrementSelection()
|
||||||
{
|
{
|
||||||
auto selectedRows = getSelectedCardNodes();
|
auto selectedRows = getSelectedCardNodes();
|
||||||
|
|
||||||
for (const auto &index : selectedRows) {
|
for (const auto &index : selectedRows) {
|
||||||
offsetCountAtIndex(index, 1);
|
offsetCountAtIndex(index, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::actSwapCard()
|
void DeckEditorDeckDockWidget::actSwapCard(const ExactCard &card, const QString &zoneName)
|
||||||
|
{
|
||||||
|
QString providerId = card.getPrinting().getUuid();
|
||||||
|
QString collectorNumber = card.getPrinting().getProperty("num");
|
||||||
|
|
||||||
|
QModelIndex foundCard = getModel()->findCard(card.getName(), zoneName, providerId, collectorNumber);
|
||||||
|
if (!foundCard.isValid()) {
|
||||||
|
foundCard = getModel()->findCard(card.getName(), zoneName);
|
||||||
|
}
|
||||||
|
|
||||||
|
deckStateManager->swapCardAtIndex(foundCard);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckEditorDeckDockWidget::actSwapSelection()
|
||||||
{
|
{
|
||||||
auto selectedRows = getSelectedCardNodes();
|
auto selectedRows = getSelectedCardNodes();
|
||||||
|
|
||||||
|
|
@ -602,52 +635,15 @@ void DeckEditorDeckDockWidget::actSwapCard()
|
||||||
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
|
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isModified = false;
|
|
||||||
for (const auto ¤tIndex : selectedRows) {
|
for (const auto ¤tIndex : selectedRows) {
|
||||||
if (swapCard(currentIndex)) {
|
deckStateManager->swapCardAtIndex(currentIndex);
|
||||||
isModified = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
|
||||||
if (isModified) {
|
|
||||||
emit deckModified();
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
update();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Swaps the card at the index between the maindeck and sideboard
|
|
||||||
*
|
|
||||||
* @param currentIndex The index to swap.
|
|
||||||
* @return True if the swap was successful
|
|
||||||
*/
|
|
||||||
bool DeckEditorDeckDockWidget::swapCard(const QModelIndex ¤tIndex)
|
|
||||||
{
|
|
||||||
if (!currentIndex.isValid())
|
|
||||||
return false;
|
|
||||||
const QString cardName = currentIndex.sibling(currentIndex.row(), 1).data().toString();
|
|
||||||
const QString cardProviderID = currentIndex.sibling(currentIndex.row(), 4).data().toString();
|
|
||||||
const QModelIndex gparent = currentIndex.parent().parent();
|
|
||||||
|
|
||||||
if (!gparent.isValid())
|
|
||||||
return false;
|
|
||||||
|
|
||||||
const QString zoneName = gparent.sibling(gparent.row(), 1).data(Qt::EditRole).toString();
|
|
||||||
offsetCountAtIndex(currentIndex, -1);
|
|
||||||
const QString otherZoneName = zoneName == DECK_ZONE_MAIN ? DECK_ZONE_SIDE : DECK_ZONE_MAIN;
|
|
||||||
|
|
||||||
ExactCard card = CardDatabaseManager::query()->getCard({cardName, cardProviderID});
|
|
||||||
QModelIndex newCardIndex = card ? deckModel->addCard(card, otherZoneName)
|
|
||||||
// Third argument (true) says create the card no matter what, even if not in DB
|
|
||||||
: deckModel->addPreferredPrintingCard(cardName, otherZoneName, true);
|
|
||||||
recursiveExpand(proxy->mapToSource(newCardIndex));
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::actDecrementCard(const ExactCard &card, QString zoneName)
|
void DeckEditorDeckDockWidget::actDecrementCard(const ExactCard &card, QString zoneName)
|
||||||
{
|
{
|
||||||
if (!card)
|
if (!card)
|
||||||
|
|
@ -655,17 +651,7 @@ void DeckEditorDeckDockWidget::actDecrementCard(const ExactCard &card, QString z
|
||||||
if (card.getInfo().getIsToken())
|
if (card.getInfo().getIsToken())
|
||||||
zoneName = DECK_ZONE_TOKENS;
|
zoneName = DECK_ZONE_TOKENS;
|
||||||
|
|
||||||
QString providerId = card.getPrinting().getUuid();
|
deckStateManager->decrementCard(card, zoneName);
|
||||||
QString collectorNumber = card.getPrinting().getProperty("num");
|
|
||||||
|
|
||||||
QModelIndex idx = deckModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
|
|
||||||
if (!idx.isValid()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
deckView->clearSelection();
|
|
||||||
deckView->setCurrentIndex(proxy->mapToSource(idx));
|
|
||||||
offsetCountAtIndex(idx, -1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::actDecrementSelection()
|
void DeckEditorDeckDockWidget::actDecrementSelection()
|
||||||
|
|
@ -679,7 +665,7 @@ void DeckEditorDeckDockWidget::actDecrementSelection()
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &index : selectedRows) {
|
for (const auto &index : selectedRows) {
|
||||||
offsetCountAtIndex(index, -1);
|
offsetCountAtIndex(index, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
|
@ -695,58 +681,31 @@ void DeckEditorDeckDockWidget::actRemoveCard()
|
||||||
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
|
deckView->setSelectionMode(QAbstractItemView::SingleSelection);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isModified = false;
|
for (const auto &row : selectedRows) {
|
||||||
for (const auto &index : selectedRows) {
|
deckStateManager->removeCardAtIndex(row);
|
||||||
if (!index.isValid() || deckModel->hasChildren(index)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
QModelIndex sourceIndex = proxy->mapToSource(index);
|
|
||||||
QString cardName = sourceIndex.sibling(sourceIndex.row(), 1).data().toString();
|
|
||||||
|
|
||||||
emit requestDeckHistorySave(QString(tr("Removed \"%1\" (all copies)")).arg(cardName));
|
|
||||||
|
|
||||||
deckModel->removeRow(sourceIndex.row(), sourceIndex.parent());
|
|
||||||
isModified = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
deckView->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
|
||||||
if (isModified) {
|
|
||||||
emit deckModified();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::offsetCountAtIndex(const QModelIndex &idx, int offset)
|
/**
|
||||||
|
* @brief Increments or decrements the amount of the card node at the index by 1.
|
||||||
|
* @param idx The proxy index
|
||||||
|
* @param isIncrement If true, increments the count. If false, decrements the count
|
||||||
|
*/
|
||||||
|
void DeckEditorDeckDockWidget::offsetCountAtIndex(const QModelIndex &idx, bool isIncrement)
|
||||||
{
|
{
|
||||||
if (!idx.isValid() || deckModel->hasChildren(idx)) {
|
if (!idx.isValid() || getModel()->hasChildren(idx)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QModelIndex sourceIndex = proxy->mapToSource(idx);
|
QModelIndex sourceIndex = proxy->mapToSource(idx);
|
||||||
|
|
||||||
const QModelIndex numberIndex = sourceIndex.sibling(sourceIndex.row(), 0);
|
if (isIncrement) {
|
||||||
const QModelIndex nameIndex = sourceIndex.sibling(sourceIndex.row(), 1);
|
deckStateManager->incrementCountAtIndex(sourceIndex);
|
||||||
|
|
||||||
const QString cardName = deckModel->data(nameIndex, Qt::EditRole).toString();
|
|
||||||
const int count = deckModel->data(numberIndex, Qt::EditRole).toInt();
|
|
||||||
const int new_count = count + offset;
|
|
||||||
|
|
||||||
const auto reason =
|
|
||||||
QString(tr("%1 %2 × \"%3\" (%4)"))
|
|
||||||
.arg(offset > 0 ? tr("Added") : tr("Removed"))
|
|
||||||
.arg(qAbs(offset))
|
|
||||||
.arg(cardName)
|
|
||||||
.arg(deckModel->data(sourceIndex.sibling(sourceIndex.row(), 4), Qt::DisplayRole).toString());
|
|
||||||
|
|
||||||
emit requestDeckHistorySave(reason);
|
|
||||||
|
|
||||||
if (new_count <= 0) {
|
|
||||||
deckModel->removeRow(sourceIndex.row(), sourceIndex.parent());
|
|
||||||
} else {
|
} else {
|
||||||
deckModel->setData(numberIndex, new_count, Qt::EditRole);
|
deckStateManager->decrementCountAtIndex(sourceIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit deckModified();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorDeckDockWidget::decklistCustomMenu(QPoint point)
|
void DeckEditorDeckDockWidget::decklistCustomMenu(QPoint point)
|
||||||
|
|
|
||||||
|
|
@ -28,22 +28,14 @@ class DeckEditorDeckDockWidget : public QDockWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent);
|
explicit DeckEditorDeckDockWidget(AbstractTabDeckEditor *parent);
|
||||||
DeckLoader *deckLoader;
|
|
||||||
DeckListStyleProxy *proxy;
|
DeckListStyleProxy *proxy;
|
||||||
DeckListModel *deckModel;
|
|
||||||
QTreeView *deckView;
|
QTreeView *deckView;
|
||||||
QComboBox *bannerCardComboBox;
|
QComboBox *bannerCardComboBox;
|
||||||
void createDeckDock();
|
void createDeckDock();
|
||||||
ExactCard getCurrentCard();
|
ExactCard getCurrentCard();
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
QString getDeckName()
|
|
||||||
{
|
|
||||||
return nameEdit->text();
|
|
||||||
}
|
|
||||||
QString getSimpleDeckName()
|
|
||||||
{
|
|
||||||
return nameEdit->text().simplified();
|
|
||||||
}
|
|
||||||
QComboBox *getGroupByComboBox()
|
QComboBox *getGroupByComboBox()
|
||||||
{
|
{
|
||||||
return activeGroupCriteriaComboBox;
|
return activeGroupCriteriaComboBox;
|
||||||
|
|
@ -55,35 +47,27 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void cleanDeck();
|
void selectPrevCard();
|
||||||
|
void selectNextCard();
|
||||||
void updateBannerCardComboBox();
|
void updateBannerCardComboBox();
|
||||||
void setDeck(DeckLoader *_deck);
|
|
||||||
void syncDisplayWidgetsToModel();
|
void syncDisplayWidgetsToModel();
|
||||||
void sortDeckModelToDeckView();
|
void sortDeckModelToDeckView();
|
||||||
DeckLoader *getDeckLoader();
|
void actAddCard(const ExactCard &card, const QString &zoneName);
|
||||||
DeckList *getDeckList();
|
void actIncrementSelection();
|
||||||
void actIncrement();
|
|
||||||
bool swapCard(const QModelIndex &idx);
|
|
||||||
void actDecrementCard(const ExactCard &card, QString zoneName);
|
void actDecrementCard(const ExactCard &card, QString zoneName);
|
||||||
void actDecrementSelection();
|
void actDecrementSelection();
|
||||||
void actSwapCard();
|
void actSwapCard(const ExactCard &card, const QString &zoneName);
|
||||||
|
void actSwapSelection();
|
||||||
void actRemoveCard();
|
void actRemoveCard();
|
||||||
void offsetCountAtIndex(const QModelIndex &idx, int offset);
|
|
||||||
void initializeFormats();
|
void initializeFormats();
|
||||||
void expandAll();
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void nameChanged();
|
void selectedCardChanged(const ExactCard &card);
|
||||||
void commentsChanged();
|
|
||||||
void hashChanged();
|
|
||||||
void deckChanged();
|
|
||||||
void deckModified();
|
|
||||||
void requestDeckHistorySave(const QString &modificationReason);
|
|
||||||
void requestDeckHistoryClear();
|
|
||||||
void cardChanged(const ExactCard &_card);
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AbstractTabDeckEditor *deckEditor;
|
AbstractTabDeckEditor *deckEditor;
|
||||||
|
DeckStateManager *deckStateManager;
|
||||||
|
|
||||||
DeckListHistoryManagerWidget *historyManagerWidget;
|
DeckListHistoryManagerWidget *historyManagerWidget;
|
||||||
KeySignals deckViewKeySignals;
|
KeySignals deckViewKeySignals;
|
||||||
QLabel *nameLabel;
|
QLabel *nameLabel;
|
||||||
|
|
@ -106,22 +90,25 @@ private:
|
||||||
|
|
||||||
QAction *aRemoveCard, *aIncrement, *aDecrement, *aSwapCard;
|
QAction *aRemoveCard, *aIncrement, *aDecrement, *aSwapCard;
|
||||||
|
|
||||||
void recursiveExpand(const QModelIndex &index);
|
DeckListModel *getModel() const;
|
||||||
[[nodiscard]] QModelIndexList getSelectedCardNodes() const;
|
[[nodiscard]] QModelIndexList getSelectedCardNodes() const;
|
||||||
|
void offsetCountAtIndex(const QModelIndex &idx, bool isIncrement);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void decklistCustomMenu(QPoint point);
|
void decklistCustomMenu(QPoint point);
|
||||||
void updateCard(QModelIndex, const QModelIndex ¤t);
|
void updateCard(QModelIndex, const QModelIndex ¤t);
|
||||||
void updateName(const QString &name);
|
void writeName();
|
||||||
void updateComments();
|
void writeComments();
|
||||||
void setBannerCard(int);
|
void writeBannerCard(int);
|
||||||
void setTags(const QStringList &tags);
|
void setSelectedIndex(const QModelIndex &newCardIndex);
|
||||||
void syncDeckListBannerCardWithComboBox();
|
|
||||||
void updateHash();
|
void updateHash();
|
||||||
void refreshShortcuts();
|
void refreshShortcuts();
|
||||||
void updateShowBannerCardComboBox(bool visible);
|
void updateShowBannerCardComboBox(bool visible);
|
||||||
void updateShowTagsWidget(bool visible);
|
void updateShowTagsWidget(bool visible);
|
||||||
void syncBannerCardComboBoxSelectionWithDeck();
|
void syncBannerCardComboBoxSelectionWithDeck();
|
||||||
|
void changeSelectedCard(int changeBy);
|
||||||
|
void recursiveExpand(const QModelIndex &parent);
|
||||||
|
void expandAll();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DECK_EDITOR_DECK_DOCK_WIDGET_H
|
#endif // DECK_EDITOR_DECK_DOCK_WIDGET_H
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,10 @@ void DeckEditorPrintingSelectorDockWidget::createPrintingSelectorDock()
|
||||||
|
|
||||||
installEventFilter(deckEditor);
|
installEventFilter(deckEditor);
|
||||||
connect(this, &QDockWidget::topLevelChanged, deckEditor, &AbstractTabDeckEditor::dockTopLevelChanged);
|
connect(this, &QDockWidget::topLevelChanged, deckEditor, &AbstractTabDeckEditor::dockTopLevelChanged);
|
||||||
|
connect(printingSelector, &PrintingSelector::prevCardRequested, deckEditor->getDeckDockWidget(),
|
||||||
|
&DeckEditorDeckDockWidget::selectPrevCard);
|
||||||
|
connect(printingSelector, &PrintingSelector::nextCardRequested, deckEditor->getDeckDockWidget(),
|
||||||
|
&DeckEditorDeckDockWidget::selectNextCard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckEditorPrintingSelectorDockWidget::retranslateUi()
|
void DeckEditorPrintingSelectorDockWidget::retranslateUi()
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
#include "deck_list_history_manager_widget.h"
|
#include "deck_list_history_manager_widget.h"
|
||||||
|
|
||||||
DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckListModel *_deckListModel,
|
#include "deck_state_manager.h"
|
||||||
|
|
||||||
|
DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckStateManager *_deckStateManager,
|
||||||
DeckListStyleProxy *_styleProxy,
|
DeckListStyleProxy *_styleProxy,
|
||||||
DeckListHistoryManager *manager,
|
|
||||||
QWidget *parent)
|
QWidget *parent)
|
||||||
: QWidget(parent), deckListModel(_deckListModel), styleProxy(_styleProxy), historyManager(manager)
|
: QWidget(parent), deckStateManager(_deckStateManager), styleProxy(_styleProxy)
|
||||||
{
|
{
|
||||||
layout = new QHBoxLayout(this);
|
layout = new QHBoxLayout(this);
|
||||||
|
|
||||||
|
|
@ -43,8 +44,7 @@ DeckListHistoryManagerWidget::DeckListHistoryManagerWidget(DeckListModel *_deckL
|
||||||
|
|
||||||
connect(historyList, &QListWidget::itemClicked, this, &DeckListHistoryManagerWidget::onListClicked);
|
connect(historyList, &QListWidget::itemClicked, this, &DeckListHistoryManagerWidget::onListClicked);
|
||||||
|
|
||||||
connect(historyManager, &DeckListHistoryManager::undoRedoStateChanged, this,
|
connect(deckStateManager, &DeckStateManager::historyChanged, this, &DeckListHistoryManagerWidget::refreshList);
|
||||||
&DeckListHistoryManagerWidget::refreshList);
|
|
||||||
|
|
||||||
refreshList();
|
refreshList();
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
|
|
@ -58,15 +58,12 @@ void DeckListHistoryManagerWidget::retranslateUi()
|
||||||
historyLabel->setText(tr("Click on an entry to revert to that point in the history."));
|
historyLabel->setText(tr("Click on an entry to revert to that point in the history."));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckListHistoryManagerWidget::setDeckListModel(DeckListModel *_deckListModel)
|
|
||||||
{
|
|
||||||
deckListModel = _deckListModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckListHistoryManagerWidget::refreshList()
|
void DeckListHistoryManagerWidget::refreshList()
|
||||||
{
|
{
|
||||||
historyList->clear();
|
historyList->clear();
|
||||||
|
|
||||||
|
DeckListHistoryManager *historyManager = deckStateManager->getHistoryManager();
|
||||||
|
|
||||||
// Fill redo section first (oldest redo at top, newest redo closest to divider)
|
// Fill redo section first (oldest redo at top, newest redo closest to divider)
|
||||||
const auto redoStack = historyManager->getRedoStack();
|
const auto redoStack = historyManager->getRedoStack();
|
||||||
for (int i = 0; i < redoStack.size(); ++i) { // iterate forward
|
for (int i = 0; i < redoStack.size(); ++i) { // iterate forward
|
||||||
|
|
@ -98,36 +95,7 @@ void DeckListHistoryManagerWidget::refreshList()
|
||||||
redoButton->setEnabled(historyManager->canRedo());
|
redoButton->setEnabled(historyManager->canRedo());
|
||||||
}
|
}
|
||||||
|
|
||||||
void DeckListHistoryManagerWidget::doUndo()
|
void DeckListHistoryManagerWidget::onListClicked(const QListWidgetItem *item)
|
||||||
{
|
|
||||||
if (!historyManager->canUndo()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
historyManager->undo(deckListModel->getDeckList());
|
|
||||||
deckListModel->rebuildTree();
|
|
||||||
emit deckListModel->layoutChanged();
|
|
||||||
emit requestDisplayWidgetSync();
|
|
||||||
|
|
||||||
refreshList();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckListHistoryManagerWidget::doRedo()
|
|
||||||
{
|
|
||||||
if (!historyManager->canRedo()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
historyManager->redo(deckListModel->getDeckList());
|
|
||||||
deckListModel->rebuildTree();
|
|
||||||
|
|
||||||
emit deckListModel->layoutChanged();
|
|
||||||
emit requestDisplayWidgetSync();
|
|
||||||
|
|
||||||
refreshList();
|
|
||||||
}
|
|
||||||
|
|
||||||
void DeckListHistoryManagerWidget::onListClicked(QListWidgetItem *item)
|
|
||||||
{
|
{
|
||||||
// Ignore non-selectable items (like divider)
|
// Ignore non-selectable items (like divider)
|
||||||
if (!(item->flags() & Qt::ItemIsSelectable)) {
|
if (!(item->flags() & Qt::ItemIsSelectable)) {
|
||||||
|
|
@ -138,23 +106,24 @@ void DeckListHistoryManagerWidget::onListClicked(QListWidgetItem *item)
|
||||||
int index = item->data(Qt::UserRole + 1).toInt();
|
int index = item->data(Qt::UserRole + 1).toInt();
|
||||||
|
|
||||||
if (mode == "redo") {
|
if (mode == "redo") {
|
||||||
const auto redoStack = historyManager->getRedoStack();
|
const auto redoStack = deckStateManager->getHistoryManager()->getRedoStack();
|
||||||
int steps = redoStack.size() - index;
|
int steps = redoStack.size() - index;
|
||||||
for (int i = 0; i < steps; ++i) {
|
deckStateManager->redo(steps);
|
||||||
historyManager->redo(deckListModel->getDeckList());
|
|
||||||
}
|
|
||||||
} else if (mode == "undo") {
|
} else if (mode == "undo") {
|
||||||
const auto undoStack = historyManager->getUndoStack();
|
const auto undoStack = deckStateManager->getHistoryManager()->getUndoStack();
|
||||||
int steps = undoStack.size() - 1 - index;
|
int steps = undoStack.size() - index;
|
||||||
for (int i = 0; i < steps + 1; ++i) {
|
deckStateManager->undo(steps);
|
||||||
historyManager->undo(deckListModel->getDeckList());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deckListModel->rebuildTree();
|
|
||||||
|
|
||||||
emit deckListModel->layoutChanged();
|
|
||||||
emit requestDisplayWidgetSync();
|
|
||||||
|
|
||||||
refreshList();
|
refreshList();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManagerWidget::doUndo()
|
||||||
|
{
|
||||||
|
deckStateManager->undo();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckListHistoryManagerWidget::doRedo()
|
||||||
|
{
|
||||||
|
deckStateManager->redo();
|
||||||
}
|
}
|
||||||
|
|
@ -14,6 +14,8 @@
|
||||||
#include <libcockatrice/deck_list/deck_list_history_manager.h>
|
#include <libcockatrice/deck_list/deck_list_history_manager.h>
|
||||||
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
||||||
|
|
||||||
|
class DeckStateManager;
|
||||||
|
|
||||||
class DeckListHistoryManagerWidget : public QWidget
|
class DeckListHistoryManagerWidget : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
@ -25,22 +27,19 @@ public slots:
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DeckListHistoryManagerWidget(DeckListModel *deckListModel,
|
explicit DeckListHistoryManagerWidget(DeckStateManager *deckStateManager,
|
||||||
DeckListStyleProxy *styleProxy,
|
DeckListStyleProxy *styleProxy,
|
||||||
DeckListHistoryManager *manager,
|
|
||||||
QWidget *parent = nullptr);
|
QWidget *parent = nullptr);
|
||||||
void setDeckListModel(DeckListModel *_deckListModel);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void refreshList();
|
void refreshList();
|
||||||
void onListClicked(QListWidgetItem *item);
|
void onListClicked(const QListWidgetItem *item);
|
||||||
void doUndo();
|
void doUndo();
|
||||||
void doRedo();
|
void doRedo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeckListModel *deckListModel;
|
DeckStateManager *deckStateManager;
|
||||||
DeckListStyleProxy *styleProxy;
|
DeckListStyleProxy *styleProxy;
|
||||||
DeckListHistoryManager *historyManager;
|
|
||||||
|
|
||||||
QHBoxLayout *layout;
|
QHBoxLayout *layout;
|
||||||
QAction *aUndo;
|
QAction *aUndo;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,361 @@
|
||||||
|
#include "deck_state_manager.h"
|
||||||
|
|
||||||
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
|
#include <libcockatrice/deck_list/deck_list_history_manager.h>
|
||||||
|
|
||||||
|
DeckStateManager::DeckStateManager(QObject *parent)
|
||||||
|
: QObject(parent), deckList(QSharedPointer<DeckList>(new DeckList)),
|
||||||
|
deckListModel(new DeckListModel(this, deckList)), historyManager(new DeckListHistoryManager(this))
|
||||||
|
{
|
||||||
|
connect(historyManager, &DeckListHistoryManager::undoRedoStateChanged, this, [this] {
|
||||||
|
setModified(true);
|
||||||
|
emit historyChanged();
|
||||||
|
});
|
||||||
|
connect(deckListModel, &DeckListModel::rowsInserted, this, &DeckStateManager::uniqueCardsChanged);
|
||||||
|
connect(deckListModel, &DeckListModel::rowsRemoved, this, &DeckStateManager::uniqueCardsChanged);
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeckList &DeckStateManager::getDeckList() const
|
||||||
|
{
|
||||||
|
return *deckList.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
LoadedDeck DeckStateManager::toLoadedDeck() const
|
||||||
|
{
|
||||||
|
return {getDeckList(), lastLoadInfo};
|
||||||
|
}
|
||||||
|
|
||||||
|
DeckList::Metadata const &DeckStateManager::getMetadata() const
|
||||||
|
{
|
||||||
|
return deckList->getMetadata();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DeckStateManager::getSimpleDeckName() const
|
||||||
|
{
|
||||||
|
return deckList->getMetadata().name.simplified();
|
||||||
|
}
|
||||||
|
|
||||||
|
QString DeckStateManager::getDeckHash() const
|
||||||
|
{
|
||||||
|
return deckList->getDeckHash();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckStateManager::isModified() const
|
||||||
|
{
|
||||||
|
return modified;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::setModified(bool state)
|
||||||
|
{
|
||||||
|
if (state == modified) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
modified = state;
|
||||||
|
emit isModifiedChanged(modified);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckStateManager::isBlankNewDeck() const
|
||||||
|
{
|
||||||
|
return !isModified() && deckList->isBlankDeck();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::replaceDeck(const LoadedDeck &deck)
|
||||||
|
{
|
||||||
|
lastLoadInfo = deck.lastLoadInfo;
|
||||||
|
deckList = QSharedPointer<DeckList>(new DeckList(deck.deckList));
|
||||||
|
deckListModel->setDeckList(deckList);
|
||||||
|
|
||||||
|
historyManager->clear();
|
||||||
|
|
||||||
|
setModified(false);
|
||||||
|
emit deckReplaced();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::clearDeck()
|
||||||
|
{
|
||||||
|
replaceDeck(LoadedDeck());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckStateManager::modifyDeck(const QString &reason, const std::function<bool(DeckListModel *)> &operation)
|
||||||
|
{
|
||||||
|
DeckListMemento memento = deckList->createMemento(reason);
|
||||||
|
bool success = operation(deckListModel);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
historyManager->save(memento);
|
||||||
|
doCardModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex DeckStateManager::modifyDeck(const QString &reason,
|
||||||
|
const std::function<QModelIndex(DeckListModel *)> &operation)
|
||||||
|
{
|
||||||
|
DeckListMemento memento = deckList->createMemento(reason);
|
||||||
|
QModelIndex idx = operation(deckListModel);
|
||||||
|
|
||||||
|
if (idx.isValid()) {
|
||||||
|
historyManager->save(memento);
|
||||||
|
doCardModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::setName(const QString &name)
|
||||||
|
{
|
||||||
|
QString previous = deckList->getName();
|
||||||
|
if (previous == name) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestHistorySave(tr("Rename deck to \"%1\" from \"%2\"").arg(name).arg(previous));
|
||||||
|
deckList->setName(name);
|
||||||
|
|
||||||
|
doMetadataModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::setComments(const QString &comments)
|
||||||
|
{
|
||||||
|
QString previous = deckList->getComments();
|
||||||
|
if (previous == comments) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestHistorySave(tr("Updated comments (was %1 chars, now %2 chars)").arg(previous.size()).arg(comments.size()));
|
||||||
|
deckList->setComments(comments);
|
||||||
|
|
||||||
|
doMetadataModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::setBannerCard(const CardRef &bannerCard)
|
||||||
|
{
|
||||||
|
CardRef previous = deckList->getBannerCard();
|
||||||
|
if (previous == bannerCard) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestHistorySave(tr("Set banner card to %1 (%2)").arg(bannerCard.name).arg(bannerCard.providerId));
|
||||||
|
deckList->setBannerCard(bannerCard);
|
||||||
|
|
||||||
|
doMetadataModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::setTags(const QStringList &tags)
|
||||||
|
{
|
||||||
|
QStringList previous = deckList->getTags();
|
||||||
|
if (previous == tags) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestHistorySave(tr("Tags changed"));
|
||||||
|
deckList->setTags(tags);
|
||||||
|
|
||||||
|
doMetadataModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::setFormat(const QString &format)
|
||||||
|
{
|
||||||
|
if (deckList->getMetadata().gameFormat == format) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestHistorySave(tr("Set format to %1").arg(format));
|
||||||
|
deckListModel->setActiveFormat(format);
|
||||||
|
|
||||||
|
doMetadataModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex DeckStateManager::addCard(const ExactCard &card, const QString &zoneName)
|
||||||
|
{
|
||||||
|
if (!card) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
QString reason = tr("Added (%1): %2 (%3) %4")
|
||||||
|
.arg(zoneName, card.getName(), card.getPrinting().getSet()->getCorrectedShortName(),
|
||||||
|
card.getPrinting().getProperty("num"));
|
||||||
|
|
||||||
|
QModelIndex idx = modifyDeck(reason, [&card, &zoneName](auto model) { return model->addCard(card, zoneName); });
|
||||||
|
|
||||||
|
if (idx.isValid()) {
|
||||||
|
emit focusIndexChanged(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
QModelIndex DeckStateManager::decrementCard(const ExactCard &card, const QString &zoneName)
|
||||||
|
{
|
||||||
|
if (!card)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
QString providerId = card.getPrinting().getUuid();
|
||||||
|
QString collectorNumber = card.getPrinting().getProperty("num");
|
||||||
|
|
||||||
|
QModelIndex idx = deckListModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
|
||||||
|
if (!idx.isValid()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
bool success = offsetCountAtIndex(idx, false);
|
||||||
|
|
||||||
|
if (!success) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (idx.isValid()) {
|
||||||
|
emit focusIndexChanged(idx);
|
||||||
|
}
|
||||||
|
|
||||||
|
return idx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool doSwapCard(DeckListModel *model,
|
||||||
|
const QModelIndex &idx,
|
||||||
|
const QString &cardName,
|
||||||
|
const QString &providerId,
|
||||||
|
const QString &otherZone)
|
||||||
|
{
|
||||||
|
bool success = model->offsetCountAtIndex(idx, -1);
|
||||||
|
if (!success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ExactCard card = CardDatabaseManager::query()->getCard({cardName, providerId})) {
|
||||||
|
model->addCard(card, otherZone);
|
||||||
|
} else {
|
||||||
|
// Third argument (true) says create the card no matter what, even if not in DB
|
||||||
|
model->addPreferredPrintingCard(cardName, otherZone, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckStateManager::swapCardAtIndex(const QModelIndex &idx)
|
||||||
|
{
|
||||||
|
if (!idx.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
|
||||||
|
QString providerId = idx.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data().toString();
|
||||||
|
QModelIndex gparent = idx.parent().parent();
|
||||||
|
|
||||||
|
if (!gparent.isValid())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
QString zoneName = gparent.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
|
||||||
|
QString otherZoneName = zoneName == DECK_ZONE_MAIN ? DECK_ZONE_SIDE : DECK_ZONE_MAIN;
|
||||||
|
|
||||||
|
QString reason = tr("Moved to %1 1 × \"%2\" (%3)") //
|
||||||
|
.arg(otherZoneName)
|
||||||
|
.arg(cardName)
|
||||||
|
.arg(providerId);
|
||||||
|
|
||||||
|
return modifyDeck(reason, [&idx, &cardName, &providerId, &otherZoneName](auto model) {
|
||||||
|
return doSwapCard(model, idx, cardName, providerId, otherZoneName);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckStateManager::removeCardAtIndex(const QModelIndex &idx)
|
||||||
|
{
|
||||||
|
if (!idx.isValid() || deckListModel->hasChildren(idx)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data().toString();
|
||||||
|
|
||||||
|
QString reason = tr("Removed \"%1\" (all copies)").arg(cardName);
|
||||||
|
|
||||||
|
return modifyDeck(reason, [&idx](auto model) { return model->removeRow(idx.row(), idx.parent()); });
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckStateManager::incrementCountAtIndex(const QModelIndex &idx)
|
||||||
|
{
|
||||||
|
return offsetCountAtIndex(idx, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckStateManager::decrementCountAtIndex(const QModelIndex &idx)
|
||||||
|
{
|
||||||
|
return offsetCountAtIndex(idx, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool DeckStateManager::offsetCountAtIndex(const QModelIndex &idx, int offset)
|
||||||
|
{
|
||||||
|
if (!idx.isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString cardName = idx.siblingAtColumn(DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
|
||||||
|
QString providerId = idx.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data(Qt::DisplayRole).toString();
|
||||||
|
|
||||||
|
QString reason = tr("%1 1 × \"%2\" (%3)") //
|
||||||
|
.arg(offset > 0 ? tr("Added") : tr("Removed"))
|
||||||
|
.arg(cardName)
|
||||||
|
.arg(providerId);
|
||||||
|
|
||||||
|
return modifyDeck(reason, [&idx, &offset](auto model) { return model->offsetCountAtIndex(idx, offset); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::undo(int steps)
|
||||||
|
{
|
||||||
|
if (!historyManager->canUndo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < steps; i++) {
|
||||||
|
if (!historyManager->canUndo()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
historyManager->undo(deckList.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
deckListModel->rebuildTree();
|
||||||
|
|
||||||
|
emit deckListModel->layoutChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::redo(int steps)
|
||||||
|
{
|
||||||
|
if (!historyManager->canRedo()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < steps; i++) {
|
||||||
|
if (!historyManager->canRedo()) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
historyManager->redo(deckList.get());
|
||||||
|
}
|
||||||
|
|
||||||
|
deckListModel->rebuildTree();
|
||||||
|
|
||||||
|
emit deckListModel->layoutChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeckStateManager::requestHistorySave(const QString &reason)
|
||||||
|
{
|
||||||
|
historyManager->save(deckList->createMemento(reason));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles updating state and emitting signals whenever the cards are modified
|
||||||
|
*/
|
||||||
|
void DeckStateManager::doCardModified()
|
||||||
|
{
|
||||||
|
setModified(true);
|
||||||
|
emit cardModified();
|
||||||
|
emit deckModified();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Handles updating state and emitting signals whenever the metadata is modified
|
||||||
|
*/
|
||||||
|
void DeckStateManager::doMetadataModified()
|
||||||
|
{
|
||||||
|
setModified(true);
|
||||||
|
emit metadataModified();
|
||||||
|
emit deckModified();
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,297 @@
|
||||||
|
#ifndef COCKATRICE_DECK_STATE_MANAGER_H
|
||||||
|
#define COCKATRICE_DECK_STATE_MANAGER_H
|
||||||
|
|
||||||
|
#include "../../deck_loader/loaded_deck.h"
|
||||||
|
#include "deck_list_model.h"
|
||||||
|
|
||||||
|
#include <QSharedPointer>
|
||||||
|
#include <libcockatrice/deck_list/deck_list.h>
|
||||||
|
|
||||||
|
class DeckListHistoryManager;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief This class centralizes the management of the state of the deck in the deck editor tab.
|
||||||
|
* It is responsible for owning and managing the DeckListModel, underlying DeckList, load info, and edit history.
|
||||||
|
*
|
||||||
|
* Although this class provides getters for the underlying DeckListModel, you should generally refrain from directly
|
||||||
|
* modifying the returned model. Outside modifications to the deck state should be done through @link
|
||||||
|
* DeckStateManager::modifyDeck and the metadata setters.
|
||||||
|
* Those methods ensure that the history is recorded and correct signals are emitted.
|
||||||
|
*/
|
||||||
|
class DeckStateManager : public QObject
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
LoadedDeck::LoadInfo lastLoadInfo;
|
||||||
|
QSharedPointer<DeckList> deckList;
|
||||||
|
DeckListModel *deckListModel;
|
||||||
|
DeckListHistoryManager *historyManager;
|
||||||
|
|
||||||
|
bool modified = false;
|
||||||
|
|
||||||
|
public:
|
||||||
|
explicit DeckStateManager(QObject *parent = nullptr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the underlying HistoryManager.
|
||||||
|
* @return The DeckListHistoryManager instance
|
||||||
|
*/
|
||||||
|
DeckListHistoryManager *getHistoryManager() const
|
||||||
|
{
|
||||||
|
return historyManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the underlying DeckListModel.
|
||||||
|
* You should generally refrain modifying the returned model directly.
|
||||||
|
* However, it's fine (and intended) to perform queries on the returned model.
|
||||||
|
* @return The DeckListModel instance
|
||||||
|
*/
|
||||||
|
DeckListModel *getModel() const
|
||||||
|
{
|
||||||
|
return deckListModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a view of the current deck.
|
||||||
|
*/
|
||||||
|
const DeckList &getDeckList() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates a LoadedDeck containing the contents of the current deck and the current LoadInfo.
|
||||||
|
*
|
||||||
|
* @return A new LoadedDeck instance.
|
||||||
|
*/
|
||||||
|
LoadedDeck toLoadedDeck() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets a view of the metadata in the DeckList
|
||||||
|
*/
|
||||||
|
DeckList::Metadata const &getMetadata() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the deck's simplified name.
|
||||||
|
*/
|
||||||
|
QString getSimpleDeckName() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the deck hash.
|
||||||
|
*/
|
||||||
|
QString getDeckHash() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the deck has been modified since it was last saved
|
||||||
|
*/
|
||||||
|
bool isModified() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the new isModified state, emitting a signal if the state changed.
|
||||||
|
* This class will automatically update its isModified state, but you may need to set it manually to handle, for
|
||||||
|
* example, saving.
|
||||||
|
* @param state The state
|
||||||
|
*/
|
||||||
|
void setModified(bool state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Checks if the deck state is as if it was a new deck
|
||||||
|
*/
|
||||||
|
bool isBlankNewDeck() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Overwrites the current deck with a new deck, resetting all history
|
||||||
|
* @param deck The new deck.
|
||||||
|
*/
|
||||||
|
void replaceDeck(const LoadedDeck &deck);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Resets the deck to a blank new deck, resetting all history.
|
||||||
|
*/
|
||||||
|
void clearDeck();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Sets the lastLoadInfo.
|
||||||
|
* @param loadInfo The lastLoadInfo
|
||||||
|
*/
|
||||||
|
void setLastLoadInfo(const LoadedDeck::LoadInfo &loadInfo)
|
||||||
|
{
|
||||||
|
lastLoadInfo = loadInfo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Modifies the cards in the deck, in a wrapped operation that is saved to the history.
|
||||||
|
*
|
||||||
|
* The operation is a function that accepts a DeckListModel that it operates upon, and returns a bool.
|
||||||
|
*
|
||||||
|
* This method will pass the underlying DeckListModel into the operation function. The function can call methods on
|
||||||
|
* the model to modify the deck.
|
||||||
|
* The function should return a bool to indicate success/failure.
|
||||||
|
*
|
||||||
|
* If the operation returns true, the state of the deck before the operation is ran is saved to the history, and the
|
||||||
|
* isModified state is updated.
|
||||||
|
* If the operation returns false, the history and isModified state is not updated.
|
||||||
|
*
|
||||||
|
* Note that even if the operation fails, any modifications to the model will already have been made.
|
||||||
|
* It's recommended for the operation to always return true if any modification has already been made to the model,
|
||||||
|
* as not doing that may cause the state to become desynced.
|
||||||
|
*
|
||||||
|
* @param reason The reason to display in the history
|
||||||
|
* @param operation The modification operation.
|
||||||
|
* @return The bool returned from the operation
|
||||||
|
*/
|
||||||
|
bool modifyDeck(const QString &reason, const std::function<bool(DeckListModel *)> &operation);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Modifies the cards in the deck, in a wrapped operation that is saved to the history.
|
||||||
|
*
|
||||||
|
* The operation is a function that accepts a DeckListModel that it operates upon, and returns a QModelIndex.
|
||||||
|
* If the index is invalid, then the operation is considered to be a failure.
|
||||||
|
*
|
||||||
|
* See the other @link DeckStateManager::modifyDeck for more info about the behavior of this method.
|
||||||
|
*
|
||||||
|
* @param reason The reason to display in the history
|
||||||
|
* @param operation The modification operation.
|
||||||
|
* @return The QModelIndex returned from the operation
|
||||||
|
*/
|
||||||
|
QModelIndex modifyDeck(const QString &reason, const std::function<QModelIndex(DeckListModel *)> &operation);
|
||||||
|
|
||||||
|
/// @name Metadata setters
|
||||||
|
/// @brief These methods set the metadata. Will no-op if the new value is the same as the current value.
|
||||||
|
/// Saves the operation to history if successful.
|
||||||
|
///@{
|
||||||
|
void setName(const QString &name);
|
||||||
|
void setComments(const QString &comments);
|
||||||
|
void setBannerCard(const CardRef &bannerCard);
|
||||||
|
void setTags(const QStringList &tags);
|
||||||
|
void setFormat(const QString &format);
|
||||||
|
///@}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Adds the given card to the given zone.
|
||||||
|
* Saves the operation to history if successful.
|
||||||
|
*
|
||||||
|
* @param card The card to add
|
||||||
|
* @param zoneName The zone to add the card to
|
||||||
|
* @return The index of the added card
|
||||||
|
*/
|
||||||
|
QModelIndex addCard(const ExactCard &card, const QString &zoneName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes 1 copy of the given card from the given zone.
|
||||||
|
* Saves the operation to history if successful.
|
||||||
|
*
|
||||||
|
* @param card The card to remove
|
||||||
|
* @param zoneName The zone to remove the card from
|
||||||
|
* @return The index of the removed card. Will be invalid if the last copy was removed.
|
||||||
|
*/
|
||||||
|
QModelIndex decrementCard(const ExactCard &card, const QString &zoneName);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Swaps one copy of the card at the given index between the maindeck and sideboard.
|
||||||
|
* No-ops if index is invalid or not a card node.
|
||||||
|
* Saves the operation to history if successful.
|
||||||
|
*
|
||||||
|
* @param idx The model index
|
||||||
|
* @return Whether the operation was successfully performed
|
||||||
|
*/
|
||||||
|
bool swapCardAtIndex(const QModelIndex &idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Removes all copies of the card at the given index.
|
||||||
|
* No-ops if index is invalid or not a card node.
|
||||||
|
* Saves the operation to history if successful.
|
||||||
|
*
|
||||||
|
* @param idx The model index
|
||||||
|
* @return Whether the operation was successfully performed
|
||||||
|
*/
|
||||||
|
bool removeCardAtIndex(const QModelIndex &idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Increments the number of copies of the card at the given index by 1.
|
||||||
|
* No-ops if index is invalid or not a card node.
|
||||||
|
* Saves the operation to history if successful.
|
||||||
|
*
|
||||||
|
* @param idx The model index
|
||||||
|
* @return Whether the operation was successfully performed
|
||||||
|
*/
|
||||||
|
bool incrementCountAtIndex(const QModelIndex &idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Decrements the number of copies of the card at the given index by 1.
|
||||||
|
* No-ops if index is invalid or not a card node.
|
||||||
|
* Saves the operation to history if successful.
|
||||||
|
*
|
||||||
|
* @param idx The model index
|
||||||
|
* @return Whether the operation was successfully performed
|
||||||
|
*/
|
||||||
|
bool decrementCountAtIndex(const QModelIndex &idx);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Undoes n steps of the history, setting the decklist state and updating the current step in the historyManager.
|
||||||
|
* @param steps Number of steps to undo.
|
||||||
|
*/
|
||||||
|
void undo(int steps = 1);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redoes n steps of the history, setting the decklist state and updating the current step in the historyManager.
|
||||||
|
* @param steps Number of steps to redo.
|
||||||
|
*/
|
||||||
|
void redo(int steps = 1);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
/**
|
||||||
|
* Saves the current decklist state to history.
|
||||||
|
* @param reason The reason that is shown in the history.
|
||||||
|
*/
|
||||||
|
void requestHistorySave(const QString &reason);
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool offsetCountAtIndex(const QModelIndex &idx, int offset);
|
||||||
|
void doCardModified();
|
||||||
|
void doMetadataModified();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* A modification has been made to the cards in the deck
|
||||||
|
*/
|
||||||
|
void cardModified();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A card that wasn't previously in the deck was added to the deck, or the last copy of a card was removed from the
|
||||||
|
* deck.
|
||||||
|
*/
|
||||||
|
void uniqueCardsChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A modification has been made to the metadata in the deck
|
||||||
|
*/
|
||||||
|
void metadataModified();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A modification has been made to the cards or metadata in the deck
|
||||||
|
*/
|
||||||
|
void deckModified();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The history has been greatly changed and needs to be reloaded.
|
||||||
|
*/
|
||||||
|
void historyChanged();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The deck has been completely changed.
|
||||||
|
*/
|
||||||
|
void deckReplaced();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The isModified state of the deck has changed
|
||||||
|
* @param isModified the new state
|
||||||
|
*/
|
||||||
|
void isModifiedChanged(bool isModified);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The selected card on any views connected to this deck should be changed to this index.
|
||||||
|
* @param index The model index
|
||||||
|
*/
|
||||||
|
void focusIndexChanged(QModelIndex index);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_DECK_STATE_MANAGER_H
|
||||||
|
|
@ -59,7 +59,7 @@ DlgEditPassword::DlgEditPassword(QWidget *parent) : QDialog(parent)
|
||||||
|
|
||||||
void DlgEditPassword::actOk()
|
void DlgEditPassword::actOk()
|
||||||
{
|
{
|
||||||
// TODO this stuff should be using qvalidators
|
//! \todo this stuff should be using qvalidators
|
||||||
if (newPasswordEdit->text().length() < 8) {
|
if (newPasswordEdit->text().length() < 8) {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Your password is too short."));
|
QMessageBox::critical(this, tr("Error"), tr("Your password is too short."));
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -121,7 +121,7 @@ void DlgForgotPasswordReset::actOk()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO this stuff should be using qvalidators
|
//! \todo this stuff should be using qvalidators
|
||||||
if (newpasswordEdit->text().length() < 8) {
|
if (newpasswordEdit->text().length() < 8) {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Your password is too short."));
|
QMessageBox::critical(this, tr("Error"), tr("Your password is too short."));
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -66,26 +66,26 @@ void AbstractDlgDeckTextEdit::setText(const QString &text)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tries to load the current contents of the contentsEdit into the DeckLoader
|
* Tries to load the current contents of the contentsEdit into the deckList
|
||||||
*
|
*
|
||||||
* @param deckLoader The DeckLoader to load the deck into
|
* @param deckList The deckList to load the deck into
|
||||||
* @return Whether the loading was successful
|
* @return Whether the loading was successful
|
||||||
*/
|
*/
|
||||||
bool AbstractDlgDeckTextEdit::loadIntoDeck(DeckLoader *deckLoader) const
|
bool AbstractDlgDeckTextEdit::loadIntoDeck(DeckList &deckList) const
|
||||||
{
|
{
|
||||||
QString buffer = contentsEdit->toPlainText();
|
QString buffer = contentsEdit->toPlainText();
|
||||||
|
|
||||||
if (buffer.contains("<cockatrice_deck version=\"1\">")) {
|
if (buffer.contains("<cockatrice_deck version=\"1\">")) {
|
||||||
return deckLoader->getDeckList()->loadFromString_Native(buffer);
|
return deckList.loadFromString_Native(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
QTextStream stream(&buffer);
|
QTextStream stream(&buffer);
|
||||||
|
|
||||||
if (deckLoader->getDeckList()->loadFromStream_Plain(stream, true)) {
|
if (deckList.loadFromStream_Plain(stream, true)) {
|
||||||
if (loadSetNameAndNumberCheckBox->isChecked()) {
|
if (loadSetNameAndNumberCheckBox->isChecked()) {
|
||||||
deckLoader->getDeckList()->forEachCard(CardNodeFunction::ResolveProviderId());
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
} else {
|
} else {
|
||||||
deckLoader->getDeckList()->forEachCard(CardNodeFunction::ClearPrintingData());
|
deckList.forEachCard(CardNodeFunction::ClearPrintingData());
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -108,7 +108,7 @@ void AbstractDlgDeckTextEdit::keyPressEvent(QKeyEvent *event)
|
||||||
*
|
*
|
||||||
* @param parent The parent widget
|
* @param parent The parent widget
|
||||||
*/
|
*/
|
||||||
DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) : AbstractDlgDeckTextEdit(parent), deckList(nullptr)
|
DlgLoadDeckFromClipboard::DlgLoadDeckFromClipboard(QWidget *parent) : AbstractDlgDeckTextEdit(parent)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Load deck from clipboard"));
|
setWindowTitle(tr("Load deck from clipboard"));
|
||||||
|
|
||||||
|
|
@ -122,8 +122,6 @@ void DlgLoadDeckFromClipboard::actRefresh()
|
||||||
|
|
||||||
void DlgLoadDeckFromClipboard::actOK()
|
void DlgLoadDeckFromClipboard::actOK()
|
||||||
{
|
{
|
||||||
deckList = new DeckLoader(this);
|
|
||||||
|
|
||||||
if (loadIntoDeck(deckList)) {
|
if (loadIntoDeck(deckList)) {
|
||||||
accept();
|
accept();
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -134,18 +132,15 @@ void DlgLoadDeckFromClipboard::actOK()
|
||||||
/**
|
/**
|
||||||
* Creates the dialog window for the "Edit deck in clipboard" action
|
* Creates the dialog window for the "Edit deck in clipboard" action
|
||||||
*
|
*
|
||||||
* @param _deckLoader The existing deck in the deck editor. Copies the instance
|
* @param _deckList The existing deck in the deck editor.
|
||||||
* @param _annotated Whether to add annotations to the text that is loaded from the deck
|
* @param _annotated Whether to add annotations to the text that is loaded from the deck
|
||||||
* @param parent The parent widget
|
* @param parent The parent widget
|
||||||
*/
|
*/
|
||||||
DlgEditDeckInClipboard::DlgEditDeckInClipboard(DeckLoader *_deckLoader, bool _annotated, QWidget *parent)
|
DlgEditDeckInClipboard::DlgEditDeckInClipboard(const DeckList &_deckList, bool _annotated, QWidget *parent)
|
||||||
: AbstractDlgDeckTextEdit(parent), annotated(_annotated)
|
: AbstractDlgDeckTextEdit(parent), deckList(_deckList), annotated(_annotated)
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("Edit deck in clipboard"));
|
setWindowTitle(tr("Edit deck in clipboard"));
|
||||||
|
|
||||||
deckLoader = new DeckLoader(this, _deckLoader->getDeckList());
|
|
||||||
deckLoader->setParent(this);
|
|
||||||
|
|
||||||
DlgEditDeckInClipboard::actRefresh();
|
DlgEditDeckInClipboard::actRefresh();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -155,7 +150,7 @@ DlgEditDeckInClipboard::DlgEditDeckInClipboard(DeckLoader *_deckLoader, bool _an
|
||||||
* @param addComments Whether to add annotations
|
* @param addComments Whether to add annotations
|
||||||
* @return A QString
|
* @return A QString
|
||||||
*/
|
*/
|
||||||
static QString deckListToString(const DeckList *deckList, bool addComments)
|
static QString deckListToString(const DeckList &deckList, bool addComments)
|
||||||
{
|
{
|
||||||
QString buffer;
|
QString buffer;
|
||||||
QTextStream stream(&buffer);
|
QTextStream stream(&buffer);
|
||||||
|
|
@ -165,12 +160,12 @@ static QString deckListToString(const DeckList *deckList, bool addComments)
|
||||||
|
|
||||||
void DlgEditDeckInClipboard::actRefresh()
|
void DlgEditDeckInClipboard::actRefresh()
|
||||||
{
|
{
|
||||||
setText(deckListToString(deckLoader->getDeckList(), annotated));
|
setText(deckListToString(deckList, annotated));
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgEditDeckInClipboard::actOK()
|
void DlgEditDeckInClipboard::actOK()
|
||||||
{
|
{
|
||||||
if (loadIntoDeck(deckLoader)) {
|
if (loadIntoDeck(deckList)) {
|
||||||
accept();
|
accept();
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Invalid deck list."));
|
QMessageBox::critical(this, tr("Error"), tr("Invalid deck list."));
|
||||||
|
|
|
||||||
|
|
@ -8,10 +8,11 @@
|
||||||
#ifndef DLG_LOAD_DECK_FROM_CLIPBOARD_H
|
#ifndef DLG_LOAD_DECK_FROM_CLIPBOARD_H
|
||||||
#define DLG_LOAD_DECK_FROM_CLIPBOARD_H
|
#define DLG_LOAD_DECK_FROM_CLIPBOARD_H
|
||||||
|
|
||||||
|
#include "../../deck_loader/loaded_deck.h"
|
||||||
|
|
||||||
#include <QCheckBox>
|
#include <QCheckBox>
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
|
|
||||||
class DeckLoader;
|
|
||||||
class QPlainTextEdit;
|
class QPlainTextEdit;
|
||||||
class QPushButton;
|
class QPushButton;
|
||||||
|
|
||||||
|
|
@ -35,15 +36,13 @@ public:
|
||||||
/**
|
/**
|
||||||
* Gets the loaded deck. Only call this method after this dialog window has been successfully exec'd.
|
* Gets the loaded deck. Only call this method after this dialog window has been successfully exec'd.
|
||||||
*
|
*
|
||||||
* The returned DeckLoader is parented to this object; make sure to take ownership of the DeckLoader if you intend
|
* @return The loaded decklist
|
||||||
* to use it, since otherwise it will get destroyed once this dlg is destroyed
|
|
||||||
* @return The DeckLoader
|
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] virtual DeckLoader *getDeckList() const = 0;
|
[[nodiscard]] virtual const DeckList &getDeckList() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void setText(const QString &text);
|
void setText(const QString &text);
|
||||||
bool loadIntoDeck(DeckLoader *deckLoader) const;
|
bool loadIntoDeck(DeckList &deckList) const;
|
||||||
void keyPressEvent(QKeyEvent *event) override;
|
void keyPressEvent(QKeyEvent *event) override;
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
|
|
@ -62,12 +61,12 @@ protected slots:
|
||||||
void actRefresh() override;
|
void actRefresh() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeckLoader *deckList;
|
DeckList deckList;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DlgLoadDeckFromClipboard(QWidget *parent = nullptr);
|
explicit DlgLoadDeckFromClipboard(QWidget *parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] DeckLoader *getDeckList() const override
|
[[nodiscard]] const DeckList &getDeckList() override
|
||||||
{
|
{
|
||||||
return deckList;
|
return deckList;
|
||||||
}
|
}
|
||||||
|
|
@ -84,15 +83,15 @@ protected slots:
|
||||||
void actRefresh() override;
|
void actRefresh() override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
DeckLoader *deckLoader;
|
DeckList deckList;
|
||||||
bool annotated;
|
bool annotated;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DlgEditDeckInClipboard(DeckLoader *_deckLoader, bool _annotated, QWidget *parent = nullptr);
|
explicit DlgEditDeckInClipboard(const DeckList &_deckList, bool _annotated, QWidget *parent = nullptr);
|
||||||
|
|
||||||
[[nodiscard]] DeckLoader *getDeckList() const override
|
[[nodiscard]] const DeckList &getDeckList() override
|
||||||
{
|
{
|
||||||
return deckLoader;
|
return deckList;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -97,11 +97,11 @@ void DlgLoadDeckFromWebsite::accept()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Parse the plain text deck here
|
// Parse the plain text deck here
|
||||||
DeckLoader *loader = new DeckLoader(this);
|
DeckList deckList;
|
||||||
QTextStream stream(&deckText);
|
QTextStream stream(&deckText);
|
||||||
loader->getDeckList()->loadFromStream_Plain(stream, false);
|
deckList.loadFromStream_Plain(stream, false);
|
||||||
loader->getDeckList()->forEachCard(CardNodeFunction::ResolveProviderId());
|
deckList.forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
deck = loader;
|
deck = deckList;
|
||||||
|
|
||||||
QDialog::accept();
|
QDialog::accept();
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -26,9 +26,9 @@ public:
|
||||||
explicit DlgLoadDeckFromWebsite(QWidget *parent);
|
explicit DlgLoadDeckFromWebsite(QWidget *parent);
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
bool testValidUrl();
|
bool testValidUrl();
|
||||||
DeckLoader *deck;
|
DeckList deck;
|
||||||
|
|
||||||
DeckLoader *getDeck()
|
const DeckList &getDeck() const
|
||||||
{
|
{
|
||||||
return deck;
|
return deck;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -356,7 +356,7 @@ DlgRegister::DlgRegister(QWidget *parent) : QDialog(parent)
|
||||||
|
|
||||||
void DlgRegister::actOk()
|
void DlgRegister::actOk()
|
||||||
{
|
{
|
||||||
// TODO this stuff should be using qvalidators
|
//! \todo this stuff should be using qvalidators
|
||||||
if (passwordEdit->text().length() < 8) {
|
if (passwordEdit->text().length() < 8) {
|
||||||
QMessageBox::critical(this, tr("Registration Warning"), tr("Your password is too short."));
|
QMessageBox::critical(this, tr("Registration Warning"), tr("Your password is too short."));
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
#include "../../deck_loader/card_node_function.h"
|
#include "../../deck_loader/card_node_function.h"
|
||||||
#include "../../deck_loader/deck_loader.h"
|
#include "../../deck_loader/deck_loader.h"
|
||||||
|
#include "../deck_editor/deck_state_manager.h"
|
||||||
#include "../interface/widgets/cards/card_info_picture_widget.h"
|
#include "../interface/widgets/cards/card_info_picture_widget.h"
|
||||||
#include "../interface/widgets/general/layout_containers/flow_widget.h"
|
#include "../interface/widgets/general/layout_containers/flow_widget.h"
|
||||||
|
|
||||||
|
|
@ -21,7 +22,8 @@
|
||||||
#include <qdrag.h>
|
#include <qdrag.h>
|
||||||
#include <qevent.h>
|
#include <qevent.h>
|
||||||
|
|
||||||
DlgSelectSetForCards::DlgSelectSetForCards(QWidget *parent, DeckListModel *_model) : QDialog(parent), model(_model)
|
DlgSelectSetForCards::DlgSelectSetForCards(QWidget *parent, DeckStateManager *deckStateManger)
|
||||||
|
: QDialog(parent), deckStateManager(deckStateManger)
|
||||||
{
|
{
|
||||||
setMinimumSize(500, 500);
|
setMinimumSize(500, 500);
|
||||||
setAcceptDrops(true);
|
setAcceptDrops(true);
|
||||||
|
|
@ -143,52 +145,61 @@ void DlgSelectSetForCards::retranslateUi()
|
||||||
setAllToPreferredButton->setText(tr("Set all to preferred"));
|
setAllToPreferredButton->setText(tr("Set all to preferred"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool swapPrinting(DeckListModel *model, const QString &modifiedSet, const QString &cardName)
|
||||||
|
{
|
||||||
|
QModelIndex idx = model->findCard(cardName, DECK_ZONE_MAIN);
|
||||||
|
if (!idx.isValid()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
int amount = model->data(idx.siblingAtColumn(DeckListModelColumns::CARD_AMOUNT), Qt::DisplayRole).toInt();
|
||||||
|
model->removeRow(idx.row(), idx.parent());
|
||||||
|
CardInfoPtr cardInfo = CardDatabaseManager::query()->getCardInfo(cardName);
|
||||||
|
PrintingInfo printing = CardDatabaseManager::query()->getSpecificPrinting(cardName, modifiedSet, "");
|
||||||
|
for (int i = 0; i < amount; i++) {
|
||||||
|
model->addCard(ExactCard(cardInfo, printing), DECK_ZONE_MAIN);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void DlgSelectSetForCards::actOK()
|
void DlgSelectSetForCards::actOK()
|
||||||
{
|
{
|
||||||
QMap<QString, QStringList> modifiedSetsAndCardsMap = getModifiedCards();
|
QMap<QString, QStringList> modifiedSetsAndCardsMap = getModifiedCards();
|
||||||
|
|
||||||
if (modifiedSetsAndCardsMap.isEmpty()) {
|
if (modifiedSetsAndCardsMap.isEmpty()) {
|
||||||
accept(); // Nothing to do
|
accept(); // Nothing to do
|
||||||
} else {
|
return;
|
||||||
emit deckAboutToBeModified(tr("Bulk modified printings."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (QString modifiedSet : modifiedSetsAndCardsMap.keys()) {
|
auto bulkModify = [&modifiedSetsAndCardsMap](DeckListModel *model) {
|
||||||
for (QString card : modifiedSetsAndCardsMap.value(modifiedSet)) {
|
for (QString modifiedSet : modifiedSetsAndCardsMap.keys()) {
|
||||||
QModelIndex find_card = model->findCard(card, DECK_ZONE_MAIN);
|
for (QString card : modifiedSetsAndCardsMap.value(modifiedSet)) {
|
||||||
if (!find_card.isValid()) {
|
swapPrinting(model, modifiedSet, card);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
int amount =
|
|
||||||
model->data(find_card.siblingAtColumn(DeckListModelColumns::CARD_AMOUNT), Qt::DisplayRole).toInt();
|
|
||||||
model->removeRow(find_card.row(), find_card.parent());
|
|
||||||
CardInfoPtr cardInfo = CardDatabaseManager::query()->getCardInfo(card);
|
|
||||||
PrintingInfo printing = CardDatabaseManager::query()->getSpecificPrinting(card, modifiedSet, "");
|
|
||||||
for (int i = 0; i < amount; i++) {
|
|
||||||
model->addCard(ExactCard(cardInfo, printing), DECK_ZONE_MAIN);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
return true;
|
||||||
if (!modifiedSetsAndCardsMap.isEmpty()) {
|
};
|
||||||
emit deckModified();
|
|
||||||
}
|
deckStateManager->modifyDeck(tr("Bulk modified printings."), bulkModify);
|
||||||
|
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgSelectSetForCards::actClear()
|
void DlgSelectSetForCards::actClear()
|
||||||
{
|
{
|
||||||
emit deckAboutToBeModified(tr("Cleared all printing information."));
|
deckStateManager->modifyDeck(tr("Cleared all printing information."), [](auto model) {
|
||||||
model->getDeckList()->forEachCard(CardNodeFunction::ClearPrintingData());
|
model->forEachCard(CardNodeFunction::ClearPrintingData());
|
||||||
emit deckModified();
|
return true;
|
||||||
|
});
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
void DlgSelectSetForCards::actSetAllToPreferred()
|
void DlgSelectSetForCards::actSetAllToPreferred()
|
||||||
{
|
{
|
||||||
emit deckAboutToBeModified(tr("Set all printings to preferred."));
|
deckStateManager->modifyDeck(tr("Set all printings to preferred."), [](auto model) {
|
||||||
model->getDeckList()->forEachCard(CardNodeFunction::ClearPrintingData());
|
model->forEachCard(CardNodeFunction::ClearPrintingData());
|
||||||
model->getDeckList()->forEachCard(CardNodeFunction::SetProviderIdToPreferred());
|
model->forEachCard(CardNodeFunction::SetProviderIdToPreferred());
|
||||||
emit deckModified();
|
return true;
|
||||||
|
});
|
||||||
accept();
|
accept();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -221,17 +232,11 @@ void DlgSelectSetForCards::sortSetsByCount()
|
||||||
QMap<QString, int> DlgSelectSetForCards::getSetsForCards()
|
QMap<QString, int> DlgSelectSetForCards::getSetsForCards()
|
||||||
{
|
{
|
||||||
QMap<QString, int> setCounts;
|
QMap<QString, int> setCounts;
|
||||||
if (!model)
|
|
||||||
return setCounts;
|
|
||||||
|
|
||||||
DeckList *decklist = model->getDeckList();
|
QList<QString> cardNames = deckStateManager->getModel()->getCardNames();
|
||||||
if (!decklist)
|
|
||||||
return setCounts;
|
|
||||||
|
|
||||||
QList<const DecklistCardNode *> cardsInDeck = decklist->getCardNodes();
|
for (auto cardName : cardNames) {
|
||||||
|
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(cardName);
|
||||||
for (auto currentCard : cardsInDeck) {
|
|
||||||
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
|
||||||
if (!infoPtr)
|
if (!infoPtr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -267,19 +272,15 @@ void DlgSelectSetForCards::updateCardLists()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DeckList *decklist = model->getDeckList();
|
QList<QString> cardNames = deckStateManager->getModel()->getCardNames();
|
||||||
if (!decklist)
|
|
||||||
return;
|
|
||||||
|
|
||||||
QList<const DecklistCardNode *> cardsInDeck = decklist->getCardNodes();
|
for (auto cardName : cardNames) {
|
||||||
|
|
||||||
for (auto currentCard : cardsInDeck) {
|
|
||||||
bool found = false;
|
bool found = false;
|
||||||
QString foundSetName;
|
QString foundSetName;
|
||||||
|
|
||||||
// Check across all sets if the card is present
|
// Check across all sets if the card is present
|
||||||
for (auto it = selectedCardsBySet.begin(); it != selectedCardsBySet.end(); ++it) {
|
for (auto it = selectedCardsBySet.begin(); it != selectedCardsBySet.end(); ++it) {
|
||||||
if (it.value().contains(currentCard->getName())) {
|
if (it.value().contains(cardName)) {
|
||||||
found = true;
|
found = true;
|
||||||
foundSetName = it.key(); // Store the set name where it was found
|
foundSetName = it.key(); // Store the set name where it was found
|
||||||
break; // Stop at the first match
|
break; // Stop at the first match
|
||||||
|
|
@ -288,16 +289,16 @@ void DlgSelectSetForCards::updateCardLists()
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
// The card was not in any selected set
|
// The card was not in any selected set
|
||||||
ExactCard card = CardDatabaseManager::query()->getCard({currentCard->getName()});
|
ExactCard card = CardDatabaseManager::query()->getCard({cardName});
|
||||||
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(uneditedCardsFlowWidget);
|
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(uneditedCardsFlowWidget);
|
||||||
picture_widget->setCard(card);
|
picture_widget->setCard(card);
|
||||||
uneditedCardsFlowWidget->addWidget(picture_widget);
|
uneditedCardsFlowWidget->addWidget(picture_widget);
|
||||||
} else {
|
} else {
|
||||||
ExactCard card = CardDatabaseManager::query()->getCard(
|
ExactCard card =
|
||||||
{currentCard->getName(), CardDatabaseManager::getInstance()
|
CardDatabaseManager::query()->getCard({cardName, CardDatabaseManager::getInstance()
|
||||||
->query()
|
->query()
|
||||||
->getSpecificPrinting(currentCard->getName(), foundSetName, "")
|
->getSpecificPrinting(cardName, foundSetName, "")
|
||||||
.getUuid()});
|
.getUuid()});
|
||||||
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(modifiedCardsFlowWidget);
|
CardInfoPictureWidget *picture_widget = new CardInfoPictureWidget(modifiedCardsFlowWidget);
|
||||||
picture_widget->setCard(card);
|
picture_widget->setCard(card);
|
||||||
modifiedCardsFlowWidget->addWidget(picture_widget);
|
modifiedCardsFlowWidget->addWidget(picture_widget);
|
||||||
|
|
@ -353,23 +354,17 @@ void DlgSelectSetForCards::dropEvent(QDropEvent *event)
|
||||||
QMap<QString, QStringList> DlgSelectSetForCards::getCardsForSets()
|
QMap<QString, QStringList> DlgSelectSetForCards::getCardsForSets()
|
||||||
{
|
{
|
||||||
QMap<QString, QStringList> setCards;
|
QMap<QString, QStringList> setCards;
|
||||||
if (!model)
|
|
||||||
return setCards;
|
|
||||||
|
|
||||||
DeckList *decklist = model->getDeckList();
|
QList<QString> cardNames = deckStateManager->getModel()->getCardNames();
|
||||||
if (!decklist)
|
|
||||||
return setCards;
|
|
||||||
|
|
||||||
QList<const DecklistCardNode *> cardsInDeck = decklist->getCardNodes();
|
for (auto cardName : cardNames) {
|
||||||
|
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(cardName);
|
||||||
for (auto currentCard : cardsInDeck) {
|
|
||||||
CardInfoPtr infoPtr = CardDatabaseManager::query()->getCardInfo(currentCard->getName());
|
|
||||||
if (!infoPtr)
|
if (!infoPtr)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SetToPrintingsMap setMap = infoPtr->getSets();
|
SetToPrintingsMap setMap = infoPtr->getSets();
|
||||||
for (auto it = setMap.begin(); it != setMap.end(); ++it) {
|
for (auto it = setMap.begin(); it != setMap.end(); ++it) {
|
||||||
setCards[it.key()].append(currentCard->getName());
|
setCards[it.key()].append(cardName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
#include <libcockatrice/models/deck_list/deck_list_model.h>
|
||||||
|
|
||||||
|
class DeckStateManager;
|
||||||
class SetEntryWidget; // Forward declaration
|
class SetEntryWidget; // Forward declaration
|
||||||
|
|
||||||
class DlgSelectSetForCards : public QDialog
|
class DlgSelectSetForCards : public QDialog
|
||||||
|
|
@ -25,7 +26,7 @@ class DlgSelectSetForCards : public QDialog
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit DlgSelectSetForCards(QWidget *parent, DeckListModel *_model);
|
explicit DlgSelectSetForCards(QWidget *parent, DeckStateManager *deckStateManager);
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
void sortSetsByCount();
|
void sortSetsByCount();
|
||||||
QMap<QString, QStringList> getCardsForSets();
|
QMap<QString, QStringList> getCardsForSets();
|
||||||
|
|
@ -37,7 +38,6 @@ public:
|
||||||
signals:
|
signals:
|
||||||
void widgetOrderChanged();
|
void widgetOrderChanged();
|
||||||
void orderChanged();
|
void orderChanged();
|
||||||
void deckAboutToBeModified(const QString &reason);
|
|
||||||
void deckModified();
|
void deckModified();
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
@ -61,7 +61,7 @@ private:
|
||||||
QLabel *modifiedCardsLabel;
|
QLabel *modifiedCardsLabel;
|
||||||
QWidget *listContainer;
|
QWidget *listContainer;
|
||||||
QListWidget *listWidget;
|
QListWidget *listWidget;
|
||||||
DeckListModel *model;
|
DeckStateManager *deckStateManager;
|
||||||
QMap<QString, SetEntryWidget *> setEntries;
|
QMap<QString, SetEntryWidget *> setEntries;
|
||||||
QPushButton *clearButton;
|
QPushButton *clearButton;
|
||||||
QPushButton *setAllToPreferredButton;
|
QPushButton *setAllToPreferredButton;
|
||||||
|
|
|
||||||
|
|
@ -1913,7 +1913,7 @@ void DlgSettings::closeEvent(QCloseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QDir(SettingsCache::instance().getDeckPath()).exists() || SettingsCache::instance().getDeckPath().isEmpty()) {
|
if (!QDir(SettingsCache::instance().getDeckPath()).exists() || SettingsCache::instance().getDeckPath().isEmpty()) {
|
||||||
// TODO: Prompt to create it
|
//! \todo Prompt to create it
|
||||||
if (QMessageBox::critical(
|
if (QMessageBox::critical(
|
||||||
this, tr("Error"),
|
this, tr("Error"),
|
||||||
tr("The path to your deck directory is invalid. Would you like to go back and set the correct path?"),
|
tr("The path to your deck directory is invalid. Would you like to go back and set the correct path?"),
|
||||||
|
|
@ -1924,7 +1924,7 @@ void DlgSettings::closeEvent(QCloseEvent *event)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!QDir(SettingsCache::instance().getPicsPath()).exists() || SettingsCache::instance().getPicsPath().isEmpty()) {
|
if (!QDir(SettingsCache::instance().getPicsPath()).exists() || SettingsCache::instance().getPicsPath().isEmpty()) {
|
||||||
// TODO: Prompt to create it
|
//! \todo Prompt to create it
|
||||||
if (QMessageBox::critical(this, tr("Error"),
|
if (QMessageBox::critical(this, tr("Error"),
|
||||||
tr("The path to your card pictures directory is invalid. Would you like to go back "
|
tr("The path to your card pictures directory is invalid. Would you like to go back "
|
||||||
"and set the correct path?"),
|
"and set the correct path?"),
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,6 @@ HomeWidget::HomeWidget(QWidget *parent, TabSupervisor *_tabSupervisor)
|
||||||
layout = new QGridLayout(this);
|
layout = new QGridLayout(this);
|
||||||
|
|
||||||
backgroundSourceCard = new CardInfoPictureArtCropWidget(this);
|
backgroundSourceCard = new CardInfoPictureArtCropWidget(this);
|
||||||
backgroundSourceDeck = new DeckLoader(this);
|
|
||||||
|
|
||||||
backgroundSourceDeck->loadFromFile(SettingsCache::instance().getDeckPath() + "background.cod",
|
|
||||||
DeckFileFormat::Cockatrice, false);
|
|
||||||
|
|
||||||
gradientColors = extractDominantColors(background);
|
gradientColors = extractDominantColors(background);
|
||||||
|
|
||||||
|
|
@ -72,13 +68,20 @@ void HomeWidget::initializeBackgroundFromSource()
|
||||||
cardChangeTimer->start(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() * 1000);
|
cardChangeTimer->start(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() * 1000);
|
||||||
break;
|
break;
|
||||||
case BackgroundSources::DeckFileArt:
|
case BackgroundSources::DeckFileArt:
|
||||||
backgroundSourceDeck->loadFromFile(SettingsCache::instance().getDeckPath() + "background.cod",
|
loadBackgroundSourceDeck();
|
||||||
DeckFileFormat::Cockatrice, false);
|
|
||||||
cardChangeTimer->start(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() * 1000);
|
cardChangeTimer->start(SettingsCache::instance().getHomeTabBackgroundShuffleFrequency() * 1000);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void HomeWidget::loadBackgroundSourceDeck()
|
||||||
|
{
|
||||||
|
DeckLoader deckLoader = DeckLoader(this);
|
||||||
|
deckLoader.loadFromFile(SettingsCache::instance().getDeckPath() + "background.cod", DeckFileFormat::Cockatrice,
|
||||||
|
false);
|
||||||
|
backgroundSourceDeck = deckLoader.getDeck().deckList;
|
||||||
|
}
|
||||||
|
|
||||||
void HomeWidget::updateRandomCard()
|
void HomeWidget::updateRandomCard()
|
||||||
{
|
{
|
||||||
auto backgroundSourceType = BackgroundSources::fromId(SettingsCache::instance().getHomeTabBackgroundSource());
|
auto backgroundSourceType = BackgroundSources::fromId(SettingsCache::instance().getHomeTabBackgroundSource());
|
||||||
|
|
@ -95,7 +98,7 @@ void HomeWidget::updateRandomCard()
|
||||||
newCard.getCardPtr()->getProperty("layout") != "normal");
|
newCard.getCardPtr()->getProperty("layout") != "normal");
|
||||||
break;
|
break;
|
||||||
case BackgroundSources::DeckFileArt:
|
case BackgroundSources::DeckFileArt:
|
||||||
QList<CardRef> cardRefs = backgroundSourceDeck->getDeckList()->getCardRefList();
|
QList<CardRef> cardRefs = backgroundSourceDeck.getCardRefList();
|
||||||
ExactCard oldCard = backgroundSourceCard->getCard();
|
ExactCard oldCard = backgroundSourceCard->getCard();
|
||||||
|
|
||||||
if (!cardRefs.empty()) {
|
if (!cardRefs.empty()) {
|
||||||
|
|
@ -183,7 +186,7 @@ QGroupBox *HomeWidget::createButtons()
|
||||||
|
|
||||||
auto visualDeckEditorButton = new HomeStyledButton(tr("Create New Deck"), gradientColors);
|
auto visualDeckEditorButton = new HomeStyledButton(tr("Create New Deck"), gradientColors);
|
||||||
connect(visualDeckEditorButton, &QPushButton::clicked, tabSupervisor,
|
connect(visualDeckEditorButton, &QPushButton::clicked, tabSupervisor,
|
||||||
[this] { tabSupervisor->openDeckInNewTab(nullptr); });
|
[this] { tabSupervisor->openDeckInNewTab(LoadedDeck()); });
|
||||||
boxLayout->addWidget(visualDeckEditorButton);
|
boxLayout->addWidget(visualDeckEditorButton);
|
||||||
auto visualDeckStorageButton = new HomeStyledButton(tr("Browse Decks"), gradientColors);
|
auto visualDeckStorageButton = new HomeStyledButton(tr("Browse Decks"), gradientColors);
|
||||||
connect(visualDeckStorageButton, &QPushButton::clicked, tabSupervisor,
|
connect(visualDeckStorageButton, &QPushButton::clicked, tabSupervisor,
|
||||||
|
|
|
||||||
|
|
@ -40,10 +40,12 @@ private:
|
||||||
TabSupervisor *tabSupervisor;
|
TabSupervisor *tabSupervisor;
|
||||||
QPixmap background;
|
QPixmap background;
|
||||||
CardInfoPictureArtCropWidget *backgroundSourceCard = nullptr;
|
CardInfoPictureArtCropWidget *backgroundSourceCard = nullptr;
|
||||||
DeckLoader *backgroundSourceDeck;
|
DeckList backgroundSourceDeck;
|
||||||
QPixmap overlay;
|
QPixmap overlay;
|
||||||
QPair<QColor, QColor> gradientColors;
|
QPair<QColor, QColor> gradientColors;
|
||||||
HomeStyledButton *connectButton;
|
HomeStyledButton *connectButton;
|
||||||
|
|
||||||
|
void loadBackgroundSourceDeck();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // HOME_WIDGET_H
|
#endif // HOME_WIDGET_H
|
||||||
|
|
|
||||||
|
|
@ -11,20 +11,15 @@
|
||||||
* UI elements for managing card counts in both the mainboard and sideboard zones.
|
* UI elements for managing card counts in both the mainboard and sideboard zones.
|
||||||
*
|
*
|
||||||
* @param parent The parent widget.
|
* @param parent The parent widget.
|
||||||
* @param deckEditor Pointer to the TabDeckEditor.
|
* @param deckStateManager Pointer to the DeckStateManager
|
||||||
* @param deckModel Pointer to the DeckListModel.
|
|
||||||
* @param deckView Pointer to the QTreeView for the deck display.
|
|
||||||
* @param cardSizeSlider Pointer to the QSlider used for dynamic font resizing.
|
* @param cardSizeSlider Pointer to the QSlider used for dynamic font resizing.
|
||||||
* @param rootCard The root card for the widget.
|
* @param rootCard The root card for the widget.
|
||||||
*/
|
*/
|
||||||
AllZonesCardAmountWidget::AllZonesCardAmountWidget(QWidget *parent,
|
AllZonesCardAmountWidget::AllZonesCardAmountWidget(QWidget *parent,
|
||||||
AbstractTabDeckEditor *deckEditor,
|
DeckStateManager *deckStateManager,
|
||||||
DeckListModel *deckModel,
|
|
||||||
QTreeView *deckView,
|
|
||||||
QSlider *cardSizeSlider,
|
QSlider *cardSizeSlider,
|
||||||
const ExactCard &rootCard)
|
const ExactCard &rootCard)
|
||||||
: QWidget(parent), deckEditor(deckEditor), deckModel(deckModel), deckView(deckView), cardSizeSlider(cardSizeSlider),
|
: QWidget(parent), cardSizeSlider(cardSizeSlider)
|
||||||
rootCard(rootCard)
|
|
||||||
{
|
{
|
||||||
layout = new QVBoxLayout(this);
|
layout = new QVBoxLayout(this);
|
||||||
layout->setAlignment(Qt::AlignHCenter);
|
layout->setAlignment(Qt::AlignHCenter);
|
||||||
|
|
@ -33,11 +28,9 @@ AllZonesCardAmountWidget::AllZonesCardAmountWidget(QWidget *parent,
|
||||||
setContentsMargins(5, 5, 5, 5); // Padding around the text
|
setContentsMargins(5, 5, 5, 5); // Padding around the text
|
||||||
|
|
||||||
zoneLabelMainboard = new ShadowBackgroundLabel(this, tr("Mainboard"));
|
zoneLabelMainboard = new ShadowBackgroundLabel(this, tr("Mainboard"));
|
||||||
buttonBoxMainboard =
|
buttonBoxMainboard = new CardAmountWidget(this, deckStateManager, cardSizeSlider, rootCard, DECK_ZONE_MAIN);
|
||||||
new CardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, rootCard, DECK_ZONE_MAIN);
|
|
||||||
zoneLabelSideboard = new ShadowBackgroundLabel(this, tr("Sideboard"));
|
zoneLabelSideboard = new ShadowBackgroundLabel(this, tr("Sideboard"));
|
||||||
buttonBoxSideboard =
|
buttonBoxSideboard = new CardAmountWidget(this, deckStateManager, cardSizeSlider, rootCard, DECK_ZONE_SIDE);
|
||||||
new CardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, rootCard, DECK_ZONE_SIDE);
|
|
||||||
|
|
||||||
layout->addWidget(zoneLabelMainboard, 0, Qt::AlignHCenter | Qt::AlignBottom);
|
layout->addWidget(zoneLabelMainboard, 0, Qt::AlignHCenter | Qt::AlignBottom);
|
||||||
layout->addWidget(buttonBoxMainboard, 0, Qt::AlignHCenter | Qt::AlignTop);
|
layout->addWidget(buttonBoxMainboard, 0, Qt::AlignHCenter | Qt::AlignTop);
|
||||||
|
|
|
||||||
|
|
@ -18,9 +18,7 @@ class AllZonesCardAmountWidget : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
explicit AllZonesCardAmountWidget(QWidget *parent,
|
explicit AllZonesCardAmountWidget(QWidget *parent,
|
||||||
AbstractTabDeckEditor *deckEditor,
|
DeckStateManager *deckStateManager,
|
||||||
DeckListModel *deckModel,
|
|
||||||
QTreeView *deckView,
|
|
||||||
QSlider *cardSizeSlider,
|
QSlider *cardSizeSlider,
|
||||||
const ExactCard &rootCard);
|
const ExactCard &rootCard);
|
||||||
int getMainboardAmount();
|
int getMainboardAmount();
|
||||||
|
|
@ -36,11 +34,7 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVBoxLayout *layout;
|
QVBoxLayout *layout;
|
||||||
AbstractTabDeckEditor *deckEditor;
|
|
||||||
DeckListModel *deckModel;
|
|
||||||
QTreeView *deckView;
|
|
||||||
QSlider *cardSizeSlider;
|
QSlider *cardSizeSlider;
|
||||||
ExactCard rootCard;
|
|
||||||
QLabel *zoneLabelMainboard;
|
QLabel *zoneLabelMainboard;
|
||||||
CardAmountWidget *buttonBoxMainboard;
|
CardAmountWidget *buttonBoxMainboard;
|
||||||
QLabel *zoneLabelSideboard;
|
QLabel *zoneLabelSideboard;
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
#include "card_amount_widget.h"
|
#include "card_amount_widget.h"
|
||||||
|
|
||||||
|
#include "../deck_editor/deck_state_manager.h"
|
||||||
|
|
||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
|
|
@ -7,22 +9,17 @@
|
||||||
* @brief Constructs a widget for displaying and controlling the card count in a specific zone.
|
* @brief Constructs a widget for displaying and controlling the card count in a specific zone.
|
||||||
*
|
*
|
||||||
* @param parent The parent widget.
|
* @param parent The parent widget.
|
||||||
* @param deckEditor Pointer to the TabDeckEditor instance.
|
|
||||||
* @param deckModel Pointer to the DeckListModel instance.
|
|
||||||
* @param deckView Pointer to the QTreeView displaying the deck.
|
|
||||||
* @param cardSizeSlider Pointer to the QSlider for adjusting font size.
|
* @param cardSizeSlider Pointer to the QSlider for adjusting font size.
|
||||||
* @param rootCard The root card to manage within the widget.
|
* @param rootCard The root card to manage within the widget.
|
||||||
* @param zoneName The zone name (e.g., DECK_ZONE_MAIN or DECK_ZONE_SIDE).
|
* @param zoneName The zone name (e.g., DECK_ZONE_MAIN or DECK_ZONE_SIDE).
|
||||||
*/
|
*/
|
||||||
CardAmountWidget::CardAmountWidget(QWidget *parent,
|
CardAmountWidget::CardAmountWidget(QWidget *parent,
|
||||||
AbstractTabDeckEditor *deckEditor,
|
DeckStateManager *deckStateManager,
|
||||||
DeckListModel *deckModel,
|
|
||||||
QTreeView *deckView,
|
|
||||||
QSlider *cardSizeSlider,
|
QSlider *cardSizeSlider,
|
||||||
const ExactCard &rootCard,
|
const ExactCard &rootCard,
|
||||||
const QString &zoneName)
|
const QString &zoneName)
|
||||||
: QWidget(parent), deckEditor(deckEditor), deckModel(deckModel), deckView(deckView), cardSizeSlider(cardSizeSlider),
|
: QWidget(parent), deckStateManager(deckStateManager), cardSizeSlider(cardSizeSlider), rootCard(rootCard),
|
||||||
rootCard(rootCard), zoneName(zoneName), hovered(false)
|
zoneName(zoneName), hovered(false)
|
||||||
{
|
{
|
||||||
layout = new QHBoxLayout(this);
|
layout = new QHBoxLayout(this);
|
||||||
layout->setContentsMargins(0, 0, 0, 0);
|
layout->setContentsMargins(0, 0, 0, 0);
|
||||||
|
|
@ -56,15 +53,10 @@ CardAmountWidget::CardAmountWidget(QWidget *parent,
|
||||||
layout->addWidget(incrementButton);
|
layout->addWidget(incrementButton);
|
||||||
|
|
||||||
// React to model changes
|
// React to model changes
|
||||||
connect(deckModel, &DeckListModel::dataChanged, this, &CardAmountWidget::updateCardCount);
|
connect(deckStateManager, &DeckStateManager::cardModified, this, &CardAmountWidget::updateCardCount);
|
||||||
connect(deckModel, &QAbstractItemModel::rowsRemoved, this, &CardAmountWidget::updateCardCount);
|
|
||||||
|
|
||||||
// Connect slider for dynamic font size adjustment
|
// Connect slider for dynamic font size adjustment
|
||||||
connect(cardSizeSlider, &QSlider::valueChanged, this, &CardAmountWidget::adjustFontSize);
|
connect(cardSizeSlider, &QSlider::valueChanged, this, &CardAmountWidget::adjustFontSize);
|
||||||
|
|
||||||
if (deckEditor) {
|
|
||||||
connect(this, &CardAmountWidget::deckModified, deckEditor, &AbstractTabDeckEditor::onDeckHistorySaveRequested);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -137,6 +129,29 @@ void CardAmountWidget::updateCardCount()
|
||||||
layout->activate();
|
layout->activate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static QModelIndex addAndReplacePrintings(DeckListModel *model,
|
||||||
|
const QModelIndex &existing,
|
||||||
|
const ExactCard &rootCard,
|
||||||
|
const QString &zone,
|
||||||
|
int extraCopies,
|
||||||
|
bool replaceProviderless)
|
||||||
|
{
|
||||||
|
auto newCardIndex = model->addCard(rootCard, zone);
|
||||||
|
if (!newCardIndex.isValid()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if a card without a providerId already exists in the deckModel and replace it, if so.
|
||||||
|
if (existing.isValid() && existing != newCardIndex && replaceProviderless) {
|
||||||
|
model->offsetCountAtIndex(newCardIndex, extraCopies);
|
||||||
|
model->removeRow(existing.row(), existing.parent());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set Index and Focus as if the user had just clicked the new card and modify the deckEditor saveState
|
||||||
|
return model->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(),
|
||||||
|
rootCard.getPrinting().getProperty("num"));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Adds a printing of the card to the specified zone (Mainboard or Sideboard).
|
* @brief Adds a printing of the card to the specified zone (Mainboard or Sideboard).
|
||||||
*
|
*
|
||||||
|
|
@ -144,25 +159,24 @@ void CardAmountWidget::updateCardCount()
|
||||||
*/
|
*/
|
||||||
void CardAmountWidget::addPrinting(const QString &zone)
|
void CardAmountWidget::addPrinting(const QString &zone)
|
||||||
{
|
{
|
||||||
int addedCount = 1;
|
|
||||||
// Check if we will need to add extra copies due to replacing copies without providerIds
|
// Check if we will need to add extra copies due to replacing copies without providerIds
|
||||||
QModelIndex existing = deckModel->findCard(rootCard.getName(), zone);
|
QModelIndex existing = deckStateManager->getModel()->findCard(rootCard.getName(), zone);
|
||||||
|
|
||||||
int extraCopies = 0;
|
int extraCopies = 0;
|
||||||
bool replacingProviderless = false;
|
bool replacingProviderless = false;
|
||||||
|
|
||||||
if (existing.isValid()) {
|
if (existing.isValid()) {
|
||||||
QString providerId = deckModel->data(existing.sibling(existing.row(), 4), Qt::DisplayRole).toString();
|
QString foundProviderId =
|
||||||
if (providerId.isEmpty()) {
|
existing.siblingAtColumn(DeckListModelColumns::CARD_PROVIDER_ID).data(Qt::DisplayRole).toString();
|
||||||
int amount = deckModel->data(existing, Qt::DisplayRole).toInt();
|
if (foundProviderId.isEmpty()) {
|
||||||
|
int amount = existing.data(Qt::DisplayRole).toInt();
|
||||||
extraCopies = amount - 1; // One less because we *always* add one
|
extraCopies = amount - 1; // One less because we *always* add one
|
||||||
replacingProviderless = true;
|
replacingProviderless = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
addedCount += extraCopies;
|
|
||||||
|
|
||||||
QString reason = QString("Added %1 copies of '%2 (%3) %4' to %5 [ProviderID: %6]%7")
|
QString reason = QString("Added %1 copies of '%2 (%3) %4' to %5 [ProviderID: %6]%7")
|
||||||
.arg(addedCount)
|
.arg(1 + extraCopies)
|
||||||
.arg(rootCard.getName())
|
.arg(rootCard.getName())
|
||||||
.arg(rootCard.getPrinting().getSet()->getShortName())
|
.arg(rootCard.getPrinting().getSet()->getShortName())
|
||||||
.arg(rootCard.getPrinting().getProperty("num"))
|
.arg(rootCard.getPrinting().getProperty("num"))
|
||||||
|
|
@ -170,29 +184,14 @@ void CardAmountWidget::addPrinting(const QString &zone)
|
||||||
.arg(rootCard.getPrinting().getUuid())
|
.arg(rootCard.getPrinting().getUuid())
|
||||||
.arg(replacingProviderless ? " (replaced providerless printings)" : "");
|
.arg(replacingProviderless ? " (replaced providerless printings)" : "");
|
||||||
|
|
||||||
emit deckModified(reason);
|
|
||||||
|
|
||||||
// Add the card and expand the list UI
|
// Add the card and expand the list UI
|
||||||
auto newCardIndex = deckModel->addCard(rootCard, zone);
|
QModelIndex newCardIndex = deckStateManager->modifyDeck(reason, [&](auto model) {
|
||||||
recursiveExpand(newCardIndex);
|
return addAndReplacePrintings(model, existing, rootCard, zone, extraCopies, replacingProviderless);
|
||||||
|
});
|
||||||
|
|
||||||
// Check if a card without a providerId already exists in the deckModel and replace it, if so.
|
if (newCardIndex.isValid()) {
|
||||||
QString foundProviderId = deckModel->data(existing.sibling(existing.row(), 4), Qt::DisplayRole).toString();
|
emit deckStateManager->focusIndexChanged(newCardIndex);
|
||||||
if (existing.isValid() && existing != newCardIndex && foundProviderId == "") {
|
|
||||||
auto amount = deckModel->data(existing, Qt::DisplayRole);
|
|
||||||
for (int i = 0; i < amount.toInt() - 1; i++) {
|
|
||||||
deckModel->addCard(rootCard, zone);
|
|
||||||
}
|
|
||||||
deckModel->removeRow(existing.row(), existing.parent());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set Index and Focus as if the user had just clicked the new card and modify the deckEditor saveState
|
|
||||||
newCardIndex = deckModel->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(),
|
|
||||||
rootCard.getPrinting().getProperty("num"));
|
|
||||||
|
|
||||||
deckView->setCurrentIndex(newCardIndex);
|
|
||||||
deckView->setFocus(Qt::FocusReason::MouseFocusReason);
|
|
||||||
deckEditor->setModified(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -227,46 +226,6 @@ void CardAmountWidget::removePrintingSideboard()
|
||||||
decrementCardHelper(DECK_ZONE_SIDE);
|
decrementCardHelper(DECK_ZONE_SIDE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Recursively expands the card in the deck view starting from the given index.
|
|
||||||
*
|
|
||||||
* @param index The model index of the card to expand.
|
|
||||||
*/
|
|
||||||
void CardAmountWidget::recursiveExpand(const QModelIndex &index)
|
|
||||||
{
|
|
||||||
if (index.parent().isValid()) {
|
|
||||||
recursiveExpand(index.parent());
|
|
||||||
}
|
|
||||||
deckView->expand(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Offsets the card count at the specified index by the given amount.
|
|
||||||
*
|
|
||||||
* @param idx The model index of the card.
|
|
||||||
* @param offset The amount to add or subtract from the card count.
|
|
||||||
*/
|
|
||||||
void CardAmountWidget::offsetCountAtIndex(const QModelIndex &idx, int offset)
|
|
||||||
{
|
|
||||||
if (!idx.isValid() || offset == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const QModelIndex numberIndex = idx.sibling(idx.row(), 0);
|
|
||||||
const int count = deckModel->data(numberIndex, Qt::EditRole).toInt();
|
|
||||||
const int new_count = count + offset;
|
|
||||||
|
|
||||||
deckView->setCurrentIndex(numberIndex);
|
|
||||||
|
|
||||||
if (new_count <= 0) {
|
|
||||||
deckModel->removeRow(idx.row(), idx.parent());
|
|
||||||
} else {
|
|
||||||
deckModel->setData(numberIndex, new_count, Qt::EditRole);
|
|
||||||
}
|
|
||||||
|
|
||||||
deckEditor->setModified(true);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function to decrement the card count for a given zone.
|
* @brief Helper function to decrement the card count for a given zone.
|
||||||
*
|
*
|
||||||
|
|
@ -281,13 +240,11 @@ void CardAmountWidget::decrementCardHelper(const QString &zone)
|
||||||
.arg(zone == DECK_ZONE_MAIN ? "mainboard" : "sideboard")
|
.arg(zone == DECK_ZONE_MAIN ? "mainboard" : "sideboard")
|
||||||
.arg(rootCard.getPrinting().getUuid());
|
.arg(rootCard.getPrinting().getUuid());
|
||||||
|
|
||||||
emit deckModified(reason);
|
deckStateManager->modifyDeck(reason, [this, &zone](auto model) {
|
||||||
|
QModelIndex idx = model->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(),
|
||||||
QModelIndex idx = deckModel->findCard(rootCard.getName(), zone, rootCard.getPrinting().getUuid(),
|
|
||||||
rootCard.getPrinting().getProperty("num"));
|
rootCard.getPrinting().getProperty("num"));
|
||||||
|
return model->offsetCountAtIndex(idx, -1);
|
||||||
offsetCountAtIndex(idx, -1);
|
});
|
||||||
deckEditor->setModified(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -298,29 +255,14 @@ void CardAmountWidget::decrementCardHelper(const QString &zone)
|
||||||
*/
|
*/
|
||||||
int CardAmountWidget::countCardsInZone(const QString &deckZone)
|
int CardAmountWidget::countCardsInZone(const QString &deckZone)
|
||||||
{
|
{
|
||||||
if (rootCard.getPrinting().getUuid().isEmpty()) {
|
QString uuid = rootCard.getPrinting().getUuid();
|
||||||
|
|
||||||
|
if (uuid.isEmpty()) {
|
||||||
return 0; // Cards without uuids/providerIds CANNOT match another card, they are undefined for us.
|
return 0; // Cards without uuids/providerIds CANNOT match another card, they are undefined for us.
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!deckModel) {
|
QList<ExactCard> cards = deckStateManager->getModel()->getCardsForZone(deckZone);
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckList *decklist = deckModel->getDeckList();
|
return std::count_if(cards.cbegin(), cards.cend(),
|
||||||
if (!decklist) {
|
[&uuid](const ExactCard &card) { return card.getPrinting().getUuid() == uuid; });
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
QList<const DecklistCardNode *> cardsInDeck = decklist->getCardNodes({deckZone});
|
|
||||||
|
|
||||||
int count = 0;
|
|
||||||
for (auto currentCard : cardsInDeck) {
|
|
||||||
for (int k = 0; k < currentCard->getNumber(); ++k) {
|
|
||||||
if (currentCard->getCardProviderId() == rootCard.getPrinting().getProperty("uuid")) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return count;
|
|
||||||
}
|
}
|
||||||
|
|
@ -27,9 +27,7 @@ signals:
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CardAmountWidget(QWidget *parent,
|
explicit CardAmountWidget(QWidget *parent,
|
||||||
AbstractTabDeckEditor *deckEditor,
|
DeckStateManager *deckStateManager,
|
||||||
DeckListModel *deckModel,
|
|
||||||
QTreeView *deckView,
|
|
||||||
QSlider *cardSizeSlider,
|
QSlider *cardSizeSlider,
|
||||||
const ExactCard &rootCard,
|
const ExactCard &rootCard,
|
||||||
const QString &zoneName);
|
const QString &zoneName);
|
||||||
|
|
@ -44,9 +42,7 @@ protected:
|
||||||
void showEvent(QShowEvent *event) override;
|
void showEvent(QShowEvent *event) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AbstractTabDeckEditor *deckEditor;
|
DeckStateManager *deckStateManager;
|
||||||
DeckListModel *deckModel;
|
|
||||||
QTreeView *deckView;
|
|
||||||
QSlider *cardSizeSlider;
|
QSlider *cardSizeSlider;
|
||||||
ExactCard rootCard;
|
ExactCard rootCard;
|
||||||
QString zoneName;
|
QString zoneName;
|
||||||
|
|
@ -57,9 +53,7 @@ private:
|
||||||
|
|
||||||
bool hovered;
|
bool hovered;
|
||||||
|
|
||||||
void offsetCountAtIndex(const QModelIndex &idx, int offset);
|
|
||||||
void decrementCardHelper(const QString &zoneName);
|
void decrementCardHelper(const QString &zoneName);
|
||||||
void recursiveExpand(const QModelIndex &index);
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void addPrintingMainboard();
|
void addPrintingMainboard();
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../../../client/settings/cache_settings.h"
|
#include "../../../client/settings/cache_settings.h"
|
||||||
#include "../../../interface/card_picture_loader/card_picture_loader.h"
|
#include "../../../interface/card_picture_loader/card_picture_loader.h"
|
||||||
#include "../../../interface/widgets/dialogs/dlg_select_set_for_cards.h"
|
#include "../../../interface/widgets/dialogs/dlg_select_set_for_cards.h"
|
||||||
|
#include "../deck_editor/deck_state_manager.h"
|
||||||
#include "printing_selector_card_display_widget.h"
|
#include "printing_selector_card_display_widget.h"
|
||||||
#include "printing_selector_card_search_widget.h"
|
#include "printing_selector_card_search_widget.h"
|
||||||
#include "printing_selector_card_selection_widget.h"
|
#include "printing_selector_card_selection_widget.h"
|
||||||
|
|
@ -21,12 +22,9 @@
|
||||||
*
|
*
|
||||||
* @param parent The parent widget for the PrintingSelector.
|
* @param parent The parent widget for the PrintingSelector.
|
||||||
* @param deckEditor The TabDeckEditor instance used for managing the deck.
|
* @param deckEditor The TabDeckEditor instance used for managing the deck.
|
||||||
* @param deckModel The DeckListModel instance that provides data for the deck's contents.
|
|
||||||
* @param deckView The QTreeView instance used to display the deck and its contents.
|
|
||||||
*/
|
*/
|
||||||
PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deckEditor)
|
PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deckEditor)
|
||||||
: QWidget(parent), deckEditor(_deckEditor), deckModel(deckEditor->deckDockWidget->deckModel),
|
: QWidget(parent), deckEditor(_deckEditor), deckStateManager(_deckEditor->deckStateManager)
|
||||||
deckView(deckEditor->deckDockWidget->deckView)
|
|
||||||
{
|
{
|
||||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
layout = new QVBoxLayout(this);
|
layout = new QVBoxLayout(this);
|
||||||
|
|
@ -74,13 +72,12 @@ PrintingSelector::PrintingSelector(QWidget *parent, AbstractTabDeckEditor *_deck
|
||||||
|
|
||||||
layout->addWidget(flowWidget);
|
layout->addWidget(flowWidget);
|
||||||
|
|
||||||
cardSelectionBar = new PrintingSelectorCardSelectionWidget(this);
|
cardSelectionBar = new PrintingSelectorCardSelectionWidget(this, deckStateManager);
|
||||||
cardSelectionBar->setVisible(SettingsCache::instance().getPrintingSelectorNavigationButtonsVisible());
|
cardSelectionBar->setVisible(SettingsCache::instance().getPrintingSelectorNavigationButtonsVisible());
|
||||||
layout->addWidget(cardSelectionBar);
|
layout->addWidget(cardSelectionBar);
|
||||||
|
|
||||||
// Connect deck model data change signal to update display
|
// Connect deck model data change signal to update display
|
||||||
connect(deckModel, &DeckListModel::rowsInserted, this, &PrintingSelector::printingsInDeckChanged);
|
connect(deckStateManager, &DeckStateManager::uniqueCardsChanged, this, &PrintingSelector::printingsInDeckChanged);
|
||||||
connect(deckModel, &DeckListModel::rowsRemoved, this, &PrintingSelector::printingsInDeckChanged);
|
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
}
|
}
|
||||||
|
|
@ -115,9 +112,8 @@ void PrintingSelector::updateDisplay()
|
||||||
* @brief Sets the current card for the selector and updates the display.
|
* @brief Sets the current card for the selector and updates the display.
|
||||||
*
|
*
|
||||||
* @param newCard The new card to set.
|
* @param newCard The new card to set.
|
||||||
* @param _currentZone The current zone the card is in.
|
|
||||||
*/
|
*/
|
||||||
void PrintingSelector::setCard(const CardInfoPtr &newCard, const QString &_currentZone)
|
void PrintingSelector::setCard(const CardInfoPtr &newCard)
|
||||||
{
|
{
|
||||||
if (newCard.isNull()) {
|
if (newCard.isNull()) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -129,7 +125,6 @@ void PrintingSelector::setCard(const CardInfoPtr &newCard, const QString &_curre
|
||||||
}
|
}
|
||||||
|
|
||||||
selectedCard = newCard;
|
selectedCard = newCard;
|
||||||
currentZone = _currentZone;
|
|
||||||
if (isVisible()) {
|
if (isVisible()) {
|
||||||
updateDisplay();
|
updateDisplay();
|
||||||
}
|
}
|
||||||
|
|
@ -138,58 +133,6 @@ void PrintingSelector::setCard(const CardInfoPtr &newCard, const QString &_curre
|
||||||
flowWidget->repaint();
|
flowWidget->repaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Selects the previous card in the list.
|
|
||||||
*/
|
|
||||||
void PrintingSelector::selectPreviousCard()
|
|
||||||
{
|
|
||||||
selectCard(-1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Selects the next card in the list.
|
|
||||||
*/
|
|
||||||
void PrintingSelector::selectNextCard()
|
|
||||||
{
|
|
||||||
selectCard(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Selects a card based on the change direction.
|
|
||||||
*
|
|
||||||
* @param changeBy The direction to change, -1 for previous, 1 for next.
|
|
||||||
*/
|
|
||||||
void PrintingSelector::selectCard(const int changeBy)
|
|
||||||
{
|
|
||||||
if (changeBy == 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the current index of the selected item
|
|
||||||
auto deckViewCurrentIndex = deckView->currentIndex();
|
|
||||||
|
|
||||||
auto nextIndex = deckViewCurrentIndex.siblingAtRow(deckViewCurrentIndex.row() + changeBy);
|
|
||||||
if (!nextIndex.isValid()) {
|
|
||||||
nextIndex = deckViewCurrentIndex;
|
|
||||||
|
|
||||||
// Increment to the next valid index, skipping header rows
|
|
||||||
AbstractDecklistNode *node;
|
|
||||||
do {
|
|
||||||
if (changeBy > 0) {
|
|
||||||
nextIndex = deckView->indexBelow(nextIndex);
|
|
||||||
} else {
|
|
||||||
nextIndex = deckView->indexAbove(nextIndex);
|
|
||||||
}
|
|
||||||
node = static_cast<AbstractDecklistNode *>(nextIndex.internalPointer());
|
|
||||||
} while (node && node->isDeckHeader());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nextIndex.isValid()) {
|
|
||||||
deckView->setCurrentIndex(nextIndex);
|
|
||||||
deckView->setFocus(Qt::FocusReason::MouseFocusReason);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Loads and displays all sets for the current selected card.
|
* @brief Loads and displays all sets for the current selected card.
|
||||||
*/
|
*/
|
||||||
|
|
@ -206,7 +149,8 @@ void PrintingSelector::getAllSetsForCurrentCard()
|
||||||
QList<PrintingInfo> printingsToUse;
|
QList<PrintingInfo> printingsToUse;
|
||||||
|
|
||||||
if (SettingsCache::instance().getBumpSetsWithCardsInDeckToTop()) {
|
if (SettingsCache::instance().getBumpSetsWithCardsInDeckToTop()) {
|
||||||
printingsToUse = sortToolBar->prependPrintingsInDeck(filteredPrintings, selectedCard, deckModel);
|
printingsToUse =
|
||||||
|
sortToolBar->prependPrintingsInDeck(filteredPrintings, selectedCard, deckStateManager->getModel());
|
||||||
} else {
|
} else {
|
||||||
printingsToUse = filteredPrintings;
|
printingsToUse = filteredPrintings;
|
||||||
}
|
}
|
||||||
|
|
@ -218,8 +162,8 @@ void PrintingSelector::getAllSetsForCurrentCard()
|
||||||
connect(widgetLoadingBufferTimer, &QTimer::timeout, this, [=, this]() mutable {
|
connect(widgetLoadingBufferTimer, &QTimer::timeout, this, [=, this]() mutable {
|
||||||
for (int i = 0; i < BATCH_SIZE && currentIndex < printingsToUse.size(); ++i, ++currentIndex) {
|
for (int i = 0; i < BATCH_SIZE && currentIndex < printingsToUse.size(); ++i, ++currentIndex) {
|
||||||
auto card = ExactCard(selectedCard, printingsToUse[currentIndex]);
|
auto card = ExactCard(selectedCard, printingsToUse[currentIndex]);
|
||||||
auto *cardDisplayWidget = new PrintingSelectorCardDisplayWidget(
|
auto *cardDisplayWidget = new PrintingSelectorCardDisplayWidget(this, deckEditor, deckStateManager,
|
||||||
this, deckEditor, deckModel, deckView, cardSizeWidget->getSlider(), card, currentZone);
|
cardSizeWidget->getSlider(), card);
|
||||||
flowWidget->addWidget(cardDisplayWidget);
|
flowWidget->addWidget(cardDisplayWidget);
|
||||||
cardDisplayWidget->clampSetNameToPicture();
|
cardDisplayWidget->clampSetNameToPicture();
|
||||||
connect(cardDisplayWidget, &PrintingSelectorCardDisplayWidget::cardPreferenceChanged, this,
|
connect(cardDisplayWidget, &PrintingSelectorCardDisplayWidget::cardPreferenceChanged, this,
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
#define BATCH_SIZE 10
|
#define BATCH_SIZE 10
|
||||||
|
|
||||||
|
class DeckStateManager;
|
||||||
class PrintingSelectorCardSearchWidget;
|
class PrintingSelectorCardSearchWidget;
|
||||||
class PrintingSelectorCardSelectionWidget;
|
class PrintingSelectorCardSelectionWidget;
|
||||||
class PrintingSelectorCardSortingWidget;
|
class PrintingSelectorCardSortingWidget;
|
||||||
|
|
@ -33,28 +34,27 @@ class PrintingSelector : public QWidget
|
||||||
public:
|
public:
|
||||||
PrintingSelector(QWidget *parent, AbstractTabDeckEditor *deckEditor);
|
PrintingSelector(QWidget *parent, AbstractTabDeckEditor *deckEditor);
|
||||||
|
|
||||||
void setCard(const CardInfoPtr &newCard, const QString &_currentZone);
|
void setCard(const CardInfoPtr &newCard);
|
||||||
void getAllSetsForCurrentCard();
|
void getAllSetsForCurrentCard();
|
||||||
[[nodiscard]] DeckListModel *getDeckModel() const
|
|
||||||
{
|
|
||||||
return deckModel;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] AbstractTabDeckEditor *getDeckEditor() const
|
|
||||||
{
|
|
||||||
return deckEditor;
|
|
||||||
}
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
void updateDisplay();
|
void updateDisplay();
|
||||||
void selectPreviousCard();
|
|
||||||
void selectNextCard();
|
|
||||||
void toggleVisibilityNavigationButtons(bool _state);
|
void toggleVisibilityNavigationButtons(bool _state);
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void printingsInDeckChanged();
|
void printingsInDeckChanged();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
/**
|
||||||
|
* Requests the previous card in the list
|
||||||
|
*/
|
||||||
|
void prevCardRequested();
|
||||||
|
/**
|
||||||
|
* Requests the next card in the list
|
||||||
|
*/
|
||||||
|
void nextCardRequested();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QVBoxLayout *layout;
|
QVBoxLayout *layout;
|
||||||
SettingsButtonWidget *displayOptionsWidget;
|
SettingsButtonWidget *displayOptionsWidget;
|
||||||
|
|
@ -67,13 +67,10 @@ private:
|
||||||
CardSizeWidget *cardSizeWidget;
|
CardSizeWidget *cardSizeWidget;
|
||||||
PrintingSelectorCardSelectionWidget *cardSelectionBar;
|
PrintingSelectorCardSelectionWidget *cardSelectionBar;
|
||||||
AbstractTabDeckEditor *deckEditor;
|
AbstractTabDeckEditor *deckEditor;
|
||||||
DeckListModel *deckModel;
|
DeckStateManager *deckStateManager;
|
||||||
QTreeView *deckView;
|
|
||||||
CardInfoPtr selectedCard;
|
CardInfoPtr selectedCard;
|
||||||
QString currentZone;
|
|
||||||
QTimer *widgetLoadingBufferTimer;
|
QTimer *widgetLoadingBufferTimer;
|
||||||
int currentIndex = 0;
|
int currentIndex = 0;
|
||||||
void selectCard(int changeBy);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PRINTING_SELECTOR_H
|
#endif // PRINTING_SELECTOR_H
|
||||||
|
|
|
||||||
|
|
@ -17,30 +17,24 @@
|
||||||
* display.
|
* display.
|
||||||
*
|
*
|
||||||
* @param parent The parent widget for this display.
|
* @param parent The parent widget for this display.
|
||||||
* @param _deckEditor The TabDeckEditor instance for deck management.
|
* @param deckEditor The TabDeckEditor instance for deck management.
|
||||||
* @param _deckModel The DeckListModel instance providing deck data.
|
* @param deckStateManager The DeckStateManager instance providing deck data.
|
||||||
* @param _deckView The QTreeView instance displaying the deck.
|
* @param cardSizeSlider The slider controlling the size of the displayed card.
|
||||||
* @param _cardSizeSlider The slider controlling the size of the displayed card.
|
* @param rootCard The root card object, representing the card to be displayed.
|
||||||
* @param _rootCard The root card object, representing the card to be displayed.
|
|
||||||
* @param _currentZone The current zone in which the card is located.
|
|
||||||
*/
|
*/
|
||||||
PrintingSelectorCardDisplayWidget::PrintingSelectorCardDisplayWidget(QWidget *parent,
|
PrintingSelectorCardDisplayWidget::PrintingSelectorCardDisplayWidget(QWidget *parent,
|
||||||
AbstractTabDeckEditor *_deckEditor,
|
AbstractTabDeckEditor *deckEditor,
|
||||||
DeckListModel *_deckModel,
|
DeckStateManager *deckStateManager,
|
||||||
QTreeView *_deckView,
|
QSlider *cardSizeSlider,
|
||||||
QSlider *_cardSizeSlider,
|
const ExactCard &rootCard)
|
||||||
const ExactCard &_rootCard,
|
: QWidget(parent)
|
||||||
QString &_currentZone)
|
|
||||||
: QWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), deckView(_deckView),
|
|
||||||
cardSizeSlider(_cardSizeSlider), rootCard(_rootCard), currentZone(_currentZone)
|
|
||||||
{
|
{
|
||||||
layout = new QVBoxLayout(this);
|
layout = new QVBoxLayout(this);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||||
|
|
||||||
// Create the overlay widget for the card display
|
// Create the overlay widget for the card display
|
||||||
overlayWidget =
|
overlayWidget = new PrintingSelectorCardOverlayWidget(this, deckEditor, deckStateManager, cardSizeSlider, rootCard);
|
||||||
new PrintingSelectorCardOverlayWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, rootCard);
|
|
||||||
connect(overlayWidget, &PrintingSelectorCardOverlayWidget::cardPreferenceChanged, this,
|
connect(overlayWidget, &PrintingSelectorCardOverlayWidget::cardPreferenceChanged, this,
|
||||||
[this]() { emit cardPreferenceChanged(); });
|
[this]() { emit cardPreferenceChanged(); });
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,12 +20,10 @@ class PrintingSelectorCardDisplayWidget : public QWidget
|
||||||
|
|
||||||
public:
|
public:
|
||||||
PrintingSelectorCardDisplayWidget(QWidget *parent,
|
PrintingSelectorCardDisplayWidget(QWidget *parent,
|
||||||
AbstractTabDeckEditor *_deckEditor,
|
AbstractTabDeckEditor *deckEditor,
|
||||||
DeckListModel *_deckModel,
|
DeckStateManager *deckStateManager,
|
||||||
QTreeView *_deckView,
|
QSlider *cardSizeSlider,
|
||||||
QSlider *_cardSizeSlider,
|
const ExactCard &rootCard);
|
||||||
const ExactCard &_rootCard,
|
|
||||||
QString &_currentZone);
|
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void clampSetNameToPicture();
|
void clampSetNameToPicture();
|
||||||
|
|
@ -36,12 +34,6 @@ signals:
|
||||||
private:
|
private:
|
||||||
QVBoxLayout *layout;
|
QVBoxLayout *layout;
|
||||||
SetNameAndCollectorsNumberDisplayWidget *setNameAndCollectorsNumberDisplayWidget;
|
SetNameAndCollectorsNumberDisplayWidget *setNameAndCollectorsNumberDisplayWidget;
|
||||||
AbstractTabDeckEditor *deckEditor;
|
|
||||||
DeckListModel *deckModel;
|
|
||||||
QTreeView *deckView;
|
|
||||||
QSlider *cardSizeSlider;
|
|
||||||
ExactCard rootCard;
|
|
||||||
QString currentZone;
|
|
||||||
PrintingSelectorCardOverlayWidget *overlayWidget;
|
PrintingSelectorCardOverlayWidget *overlayWidget;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -22,19 +22,16 @@
|
||||||
*
|
*
|
||||||
* @param parent The parent widget for this overlay.
|
* @param parent The parent widget for this overlay.
|
||||||
* @param _deckEditor The TabDeckEditor instance for deck management.
|
* @param _deckEditor The TabDeckEditor instance for deck management.
|
||||||
* @param _deckModel The DeckListModel instance providing deck data.
|
* @param deckStateManager The DeckStateManager instance providing deck data.
|
||||||
* @param _deckView The QTreeView instance displaying the deck.
|
* @param cardSizeSlider The slider controlling the size of the card.
|
||||||
* @param _cardSizeSlider The slider controlling the size of the card.
|
|
||||||
* @param _rootCard The root card object that contains information about the card.
|
* @param _rootCard The root card object that contains information about the card.
|
||||||
*/
|
*/
|
||||||
PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *parent,
|
PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *parent,
|
||||||
AbstractTabDeckEditor *_deckEditor,
|
AbstractTabDeckEditor *_deckEditor,
|
||||||
DeckListModel *_deckModel,
|
DeckStateManager *deckStateManager,
|
||||||
QTreeView *_deckView,
|
QSlider *cardSizeSlider,
|
||||||
QSlider *_cardSizeSlider,
|
|
||||||
const ExactCard &_rootCard)
|
const ExactCard &_rootCard)
|
||||||
: QWidget(parent), deckEditor(_deckEditor), deckModel(_deckModel), deckView(_deckView),
|
: QWidget(parent), deckEditor(_deckEditor), rootCard(_rootCard)
|
||||||
cardSizeSlider(_cardSizeSlider), rootCard(_rootCard)
|
|
||||||
{
|
{
|
||||||
// Set up the main layout
|
// Set up the main layout
|
||||||
auto *mainLayout = new QVBoxLayout(this);
|
auto *mainLayout = new QVBoxLayout(this);
|
||||||
|
|
@ -59,8 +56,7 @@ PrintingSelectorCardOverlayWidget::PrintingSelectorCardOverlayWidget(QWidget *pa
|
||||||
updatePinBadgeVisibility();
|
updatePinBadgeVisibility();
|
||||||
|
|
||||||
// Add AllZonesCardAmountWidget
|
// Add AllZonesCardAmountWidget
|
||||||
allZonesCardAmountWidget =
|
allZonesCardAmountWidget = new AllZonesCardAmountWidget(this, deckStateManager, cardSizeSlider, _rootCard);
|
||||||
new AllZonesCardAmountWidget(this, deckEditor, deckModel, deckView, cardSizeSlider, _rootCard);
|
|
||||||
|
|
||||||
allZonesCardAmountWidget->raise(); // Ensure it's on top of the picture
|
allZonesCardAmountWidget->raise(); // Ensure it's on top of the picture
|
||||||
// Set initial visibility based on amounts
|
// Set initial visibility based on amounts
|
||||||
|
|
|
||||||
|
|
@ -20,8 +20,7 @@ class PrintingSelectorCardOverlayWidget : public QWidget
|
||||||
public:
|
public:
|
||||||
explicit PrintingSelectorCardOverlayWidget(QWidget *parent,
|
explicit PrintingSelectorCardOverlayWidget(QWidget *parent,
|
||||||
AbstractTabDeckEditor *_deckEditor,
|
AbstractTabDeckEditor *_deckEditor,
|
||||||
DeckListModel *_deckModel,
|
DeckStateManager *_deckStateManager,
|
||||||
QTreeView *_deckView,
|
|
||||||
QSlider *_cardSizeSlider,
|
QSlider *_cardSizeSlider,
|
||||||
const ExactCard &_rootCard);
|
const ExactCard &_rootCard);
|
||||||
|
|
||||||
|
|
@ -48,9 +47,6 @@ private:
|
||||||
AllZonesCardAmountWidget *allZonesCardAmountWidget;
|
AllZonesCardAmountWidget *allZonesCardAmountWidget;
|
||||||
QLabel *pinBadge = nullptr;
|
QLabel *pinBadge = nullptr;
|
||||||
AbstractTabDeckEditor *deckEditor;
|
AbstractTabDeckEditor *deckEditor;
|
||||||
DeckListModel *deckModel;
|
|
||||||
QTreeView *deckView;
|
|
||||||
QSlider *cardSizeSlider;
|
|
||||||
ExactCard rootCard;
|
ExactCard rootCard;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@
|
||||||
*
|
*
|
||||||
* @param parent The parent PrintingSelector widget responsible for managing card selection.
|
* @param parent The parent PrintingSelector widget responsible for managing card selection.
|
||||||
*/
|
*/
|
||||||
PrintingSelectorCardSelectionWidget::PrintingSelectorCardSelectionWidget(PrintingSelector *parent) : parent(parent)
|
PrintingSelectorCardSelectionWidget::PrintingSelectorCardSelectionWidget(PrintingSelector *parent,
|
||||||
|
DeckStateManager *deckStateManager)
|
||||||
|
: parent(parent), deckStateManager(deckStateManager)
|
||||||
{
|
{
|
||||||
cardSelectionBarLayout = new QHBoxLayout(this);
|
cardSelectionBarLayout = new QHBoxLayout(this);
|
||||||
cardSelectionBarLayout->setContentsMargins(9, 0, 9, 0);
|
cardSelectionBarLayout->setContentsMargins(9, 0, 9, 0);
|
||||||
|
|
@ -42,18 +44,12 @@ PrintingSelectorCardSelectionWidget::PrintingSelectorCardSelectionWidget(Printin
|
||||||
*/
|
*/
|
||||||
void PrintingSelectorCardSelectionWidget::connectSignals()
|
void PrintingSelectorCardSelectionWidget::connectSignals()
|
||||||
{
|
{
|
||||||
connect(previousCardButton, &QPushButton::clicked, parent, &PrintingSelector::selectPreviousCard);
|
connect(previousCardButton, &QPushButton::clicked, parent, &PrintingSelector::prevCardRequested);
|
||||||
connect(nextCardButton, &QPushButton::clicked, parent, &PrintingSelector::selectNextCard);
|
connect(nextCardButton, &QPushButton::clicked, parent, &PrintingSelector::nextCardRequested);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PrintingSelectorCardSelectionWidget::selectSetForCards()
|
void PrintingSelectorCardSelectionWidget::selectSetForCards()
|
||||||
{
|
{
|
||||||
auto *setSelectionDialog = new DlgSelectSetForCards(nullptr, parent->getDeckModel());
|
auto *setSelectionDialog = new DlgSelectSetForCards(nullptr, deckStateManager);
|
||||||
connect(setSelectionDialog, &DlgSelectSetForCards::deckAboutToBeModified, parent->getDeckEditor(),
|
setSelectionDialog->exec();
|
||||||
&AbstractTabDeckEditor::onDeckHistorySaveRequested);
|
|
||||||
connect(setSelectionDialog, &DlgSelectSetForCards::deckModified, parent->getDeckEditor(),
|
|
||||||
&AbstractTabDeckEditor::onDeckModified);
|
|
||||||
if (!setSelectionDialog->exec()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ class PrintingSelectorCardSelectionWidget : public QWidget
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit PrintingSelectorCardSelectionWidget(PrintingSelector *parent);
|
explicit PrintingSelectorCardSelectionWidget(PrintingSelector *parent, DeckStateManager *deckStateManager);
|
||||||
|
|
||||||
void connectSignals();
|
void connectSignals();
|
||||||
|
|
||||||
|
|
@ -27,6 +27,7 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
PrintingSelector *parent;
|
PrintingSelector *parent;
|
||||||
|
DeckStateManager *deckStateManager;
|
||||||
QHBoxLayout *cardSelectionBarLayout;
|
QHBoxLayout *cardSelectionBarLayout;
|
||||||
QPushButton *previousCardButton;
|
QPushButton *previousCardButton;
|
||||||
QPushButton *selectSetForCardsButton;
|
QPushButton *selectSetForCardsButton;
|
||||||
|
|
|
||||||
|
|
@ -183,7 +183,7 @@ QList<PrintingInfo> PrintingSelectorCardSortingWidget::prependPinnedPrintings(co
|
||||||
*/
|
*/
|
||||||
QList<PrintingInfo> PrintingSelectorCardSortingWidget::prependPrintingsInDeck(const QList<PrintingInfo> &printings,
|
QList<PrintingInfo> PrintingSelectorCardSortingWidget::prependPrintingsInDeck(const QList<PrintingInfo> &printings,
|
||||||
const CardInfoPtr &selectedCard,
|
const CardInfoPtr &selectedCard,
|
||||||
DeckListModel *deckModel)
|
const DeckListModel *deckModel)
|
||||||
{
|
{
|
||||||
if (!selectedCard) {
|
if (!selectedCard) {
|
||||||
return {};
|
return {};
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,7 @@ public:
|
||||||
QList<PrintingInfo> prependPinnedPrintings(const QList<PrintingInfo> &printings, const QString &cardName);
|
QList<PrintingInfo> prependPinnedPrintings(const QList<PrintingInfo> &printings, const QString &cardName);
|
||||||
QList<PrintingInfo> prependPrintingsInDeck(const QList<PrintingInfo> &printings,
|
QList<PrintingInfo> prependPrintingsInDeck(const QList<PrintingInfo> &printings,
|
||||||
const CardInfoPtr &selectedCard,
|
const CardInfoPtr &selectedCard,
|
||||||
DeckListModel *deckModel);
|
const DeckListModel *deckModel);
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
void updateSortOrder();
|
void updateSortOrder();
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ SetNameAndCollectorsNumberDisplayWidget::SetNameAndCollectorsNumberDisplayWidget
|
||||||
const QString &_setName,
|
const QString &_setName,
|
||||||
const QString &_collectorsNumber,
|
const QString &_collectorsNumber,
|
||||||
QSlider *_cardSizeSlider)
|
QSlider *_cardSizeSlider)
|
||||||
: QWidget(parent)
|
: QWidget(parent), cardSizeSlider(_cardSizeSlider)
|
||||||
{
|
{
|
||||||
// Set up the layout for the widget
|
// Set up the layout for the widget
|
||||||
layout = new QVBoxLayout(this);
|
layout = new QVBoxLayout(this);
|
||||||
|
|
@ -35,7 +35,6 @@ SetNameAndCollectorsNumberDisplayWidget::SetNameAndCollectorsNumberDisplayWidget
|
||||||
collectorsNumber->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
collectorsNumber->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
|
||||||
|
|
||||||
// Store the card size slider and connect its signal to the font size adjustment slot
|
// Store the card size slider and connect its signal to the font size adjustment slot
|
||||||
cardSizeSlider = _cardSizeSlider;
|
|
||||||
connect(cardSizeSlider, &QSlider::valueChanged, this, &SetNameAndCollectorsNumberDisplayWidget::adjustFontSize);
|
connect(cardSizeSlider, &QSlider::valueChanged, this, &SetNameAndCollectorsNumberDisplayWidget::adjustFontSize);
|
||||||
|
|
||||||
// Add labels to the layout
|
// Add labels to the layout
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ void ChatView::appendMessage(QString message,
|
||||||
defaultFormat = QTextCharFormat();
|
defaultFormat = QTextCharFormat();
|
||||||
if (!isUserMessage) {
|
if (!isUserMessage) {
|
||||||
if (messageType == Event_RoomSay::ChatHistory) {
|
if (messageType == Event_RoomSay::ChatHistory) {
|
||||||
defaultFormat.setForeground(Qt::gray); // FIXME : hardcoded color
|
defaultFormat.setForeground(Qt::gray); //! \todo hardcoded color
|
||||||
defaultFormat.setFontWeight(QFont::Light);
|
defaultFormat.setFontWeight(QFont::Light);
|
||||||
defaultFormat.setFontItalic(true);
|
defaultFormat.setFontItalic(true);
|
||||||
static const QRegularExpression userNameRegex("^(\\[[^\\]]*\\]\\s)(\\S+):\\s");
|
static const QRegularExpression userNameRegex("^(\\[[^\\]]*\\]\\s)(\\S+):\\s");
|
||||||
|
|
@ -229,18 +229,14 @@ void ChatView::appendMessage(QString message,
|
||||||
message.remove(0, pos.relativePosition - 2); // do not remove semicolon
|
message.remove(0, pos.relativePosition - 2); // do not remove semicolon
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
defaultFormat.setForeground(Qt::darkGreen); // FIXME : hardcoded color
|
defaultFormat.setForeground(Qt::darkGreen); //! \todo hardcoded color
|
||||||
defaultFormat.setFontWeight(QFont::Bold);
|
defaultFormat.setFontWeight(QFont::Bold);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cursor.setCharFormat(defaultFormat);
|
cursor.setCharFormat(defaultFormat);
|
||||||
|
|
||||||
bool mentionEnabled = SettingsCache::instance().getChatMention();
|
bool mentionEnabled = SettingsCache::instance().getChatMention();
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0))
|
|
||||||
highlightedWords = SettingsCache::instance().getHighlightWords().split(' ', Qt::SkipEmptyParts);
|
highlightedWords = SettingsCache::instance().getHighlightWords().split(' ', Qt::SkipEmptyParts);
|
||||||
#else
|
|
||||||
highlightedWords = SettingsCache::instance().getHighlightWords().split(' ', QString::SkipEmptyParts);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// parse the message
|
// parse the message
|
||||||
while (message.size()) {
|
while (message.size()) {
|
||||||
|
|
|
||||||
|
|
@ -28,9 +28,6 @@ class UserListProxy;
|
||||||
class UserMessagePosition
|
class UserMessagePosition
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
#if (QT_VERSION < QT_VERSION_CHECK(5, 13, 0))
|
|
||||||
UserMessagePosition() = default; // older qt versions require a default constructor to use in containers
|
|
||||||
#endif
|
|
||||||
UserMessagePosition(QTextCursor &cursor);
|
UserMessagePosition(QTextCursor &cursor);
|
||||||
int relativePosition;
|
int relativePosition;
|
||||||
QTextBlock block;
|
QTextBlock block;
|
||||||
|
|
|
||||||
|
|
@ -421,10 +421,8 @@ bool GamesProxyModel::filterAcceptsRow(int sourceRow) const
|
||||||
{
|
{
|
||||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 0)
|
||||||
static const QDate epochDate = QDateTime::fromSecsSinceEpoch(0, QTimeZone::UTC).date();
|
static const QDate epochDate = QDateTime::fromSecsSinceEpoch(0, QTimeZone::UTC).date();
|
||||||
#elif (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0))
|
|
||||||
static const QDate epochDate = QDateTime::fromSecsSinceEpoch(0, Qt::UTC).date();
|
|
||||||
#else
|
#else
|
||||||
static const QDate epochDate = QDateTime::fromTime_t(0, Qt::UTC).date();
|
static const QDate epochDate = QDateTime::fromSecsSinceEpoch(0, Qt::UTC).date();
|
||||||
#endif
|
#endif
|
||||||
auto *model = qobject_cast<GamesModel *>(sourceModel());
|
auto *model = qobject_cast<GamesModel *>(sourceModel());
|
||||||
if (!model)
|
if (!model)
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@
|
||||||
#include "../../../client/settings/cache_settings.h"
|
#include "../../../client/settings/cache_settings.h"
|
||||||
#include "../client/network/interfaces/deck_stats_interface.h"
|
#include "../client/network/interfaces/deck_stats_interface.h"
|
||||||
#include "../client/network/interfaces/tapped_out_interface.h"
|
#include "../client/network/interfaces/tapped_out_interface.h"
|
||||||
|
#include "../deck_editor/deck_state_manager.h"
|
||||||
#include "../interface/card_picture_loader/card_picture_loader.h"
|
#include "../interface/card_picture_loader/card_picture_loader.h"
|
||||||
#include "../interface/pixel_map_generator.h"
|
#include "../interface/pixel_map_generator.h"
|
||||||
#include "../interface/widgets/dialogs/dlg_load_deck.h"
|
#include "../interface/widgets/dialogs/dlg_load_deck.h"
|
||||||
|
|
@ -52,7 +53,7 @@ AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Ta
|
||||||
{
|
{
|
||||||
setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
|
setDockOptions(QMainWindow::AnimatedDocks | QMainWindow::AllowNestedDocks | QMainWindow::AllowTabbedDocks);
|
||||||
|
|
||||||
historyManager = new DeckListHistoryManager(this);
|
deckStateManager = new DeckStateManager(this);
|
||||||
|
|
||||||
databaseDisplayDockWidget = new DeckEditorDatabaseDisplayWidget(this);
|
databaseDisplayDockWidget = new DeckEditorDatabaseDisplayWidget(this);
|
||||||
deckDockWidget = new DeckEditorDeckDockWidget(this);
|
deckDockWidget = new DeckEditorDeckDockWidget(this);
|
||||||
|
|
@ -64,14 +65,8 @@ AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Ta
|
||||||
});
|
});
|
||||||
|
|
||||||
// Connect deck signals to this tab
|
// Connect deck signals to this tab
|
||||||
connect(deckDockWidget, &DeckEditorDeckDockWidget::deckChanged, this, &AbstractTabDeckEditor::onDeckChanged);
|
connect(deckStateManager, &DeckStateManager::isModifiedChanged, this, &AbstractTabDeckEditor::onDeckModified);
|
||||||
connect(deckDockWidget, &DeckEditorDeckDockWidget::deckModified, this, &AbstractTabDeckEditor::onDeckModified);
|
connect(deckDockWidget, &DeckEditorDeckDockWidget::selectedCardChanged, this, &AbstractTabDeckEditor::updateCard);
|
||||||
connect(deckDockWidget, &DeckEditorDeckDockWidget::requestDeckHistorySave, this,
|
|
||||||
&AbstractTabDeckEditor::onDeckHistorySaveRequested);
|
|
||||||
connect(deckDockWidget, &DeckEditorDeckDockWidget::requestDeckHistoryClear, this,
|
|
||||||
&AbstractTabDeckEditor::onDeckHistoryClearRequested);
|
|
||||||
connect(deckDockWidget, &DeckEditorDeckDockWidget::cardChanged, this, &AbstractTabDeckEditor::updateCard);
|
|
||||||
connect(this, &AbstractTabDeckEditor::decrementCard, deckDockWidget, &DeckEditorDeckDockWidget::actDecrementCard);
|
|
||||||
|
|
||||||
// Connect database display signals to this tab
|
// Connect database display signals to this tab
|
||||||
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::cardChanged, this,
|
connect(databaseDisplayDockWidget, &DeckEditorDatabaseDisplayWidget::cardChanged, this,
|
||||||
|
|
@ -101,13 +96,12 @@ AbstractTabDeckEditor::AbstractTabDeckEditor(TabSupervisor *_tabSupervisor) : Ta
|
||||||
void AbstractTabDeckEditor::updateCard(const ExactCard &card)
|
void AbstractTabDeckEditor::updateCard(const ExactCard &card)
|
||||||
{
|
{
|
||||||
cardInfoDockWidget->updateCard(card);
|
cardInfoDockWidget->updateCard(card);
|
||||||
printingSelectorDockWidget->printingSelector->setCard(card.getCardPtr(), DECK_ZONE_MAIN);
|
printingSelectorDockWidget->printingSelector->setCard(card.getCardPtr());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Placeholder: called when the deck changes. */
|
/** @brief Placeholder: called when the deck changes. */
|
||||||
void AbstractTabDeckEditor::onDeckChanged()
|
void AbstractTabDeckEditor::onDeckChanged()
|
||||||
{
|
{
|
||||||
historyManager->clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -115,24 +109,8 @@ void AbstractTabDeckEditor::onDeckChanged()
|
||||||
*/
|
*/
|
||||||
void AbstractTabDeckEditor::onDeckModified()
|
void AbstractTabDeckEditor::onDeckModified()
|
||||||
{
|
{
|
||||||
setModified(!isBlankNewDeck());
|
deckMenu->setSaveStatus(!deckStateManager->isBlankNewDeck());
|
||||||
deckMenu->setSaveStatus(!isBlankNewDeck());
|
emit tabTextChanged(this, getTabText());
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Marks the tab as modified and updates the save menu status.
|
|
||||||
*/
|
|
||||||
void AbstractTabDeckEditor::onDeckHistorySaveRequested(const QString &modificationReason)
|
|
||||||
{
|
|
||||||
historyManager->save(deckDockWidget->getDeckList()->createMemento(modificationReason));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Marks the tab as modified and updates the save menu status.
|
|
||||||
*/
|
|
||||||
void AbstractTabDeckEditor::onDeckHistoryClearRequested()
|
|
||||||
{
|
|
||||||
historyManager->clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -140,23 +118,9 @@ void AbstractTabDeckEditor::onDeckHistoryClearRequested()
|
||||||
* @param card Card to add.
|
* @param card Card to add.
|
||||||
* @param zoneName Zone to add the card to.
|
* @param zoneName Zone to add the card to.
|
||||||
*/
|
*/
|
||||||
void AbstractTabDeckEditor::addCardHelper(const ExactCard &card, QString zoneName)
|
void AbstractTabDeckEditor::addCardHelper(const ExactCard &card, const QString &zoneName)
|
||||||
{
|
{
|
||||||
if (!card)
|
deckStateManager->addCard(card, zoneName);
|
||||||
return;
|
|
||||||
|
|
||||||
if (card.getInfo().getIsToken())
|
|
||||||
zoneName = DECK_ZONE_TOKENS;
|
|
||||||
|
|
||||||
onDeckHistorySaveRequested(QString(tr("Added (%1): %2 (%3) %4"))
|
|
||||||
.arg(zoneName, card.getName(), card.getPrinting().getSet()->getCorrectedShortName(),
|
|
||||||
card.getPrinting().getProperty("num")));
|
|
||||||
|
|
||||||
QModelIndex newCardIndex = deckDockWidget->deckModel->addCard(card, zoneName);
|
|
||||||
deckDockWidget->expandAll();
|
|
||||||
deckDockWidget->deckView->clearSelection();
|
|
||||||
deckDockWidget->deckView->setCurrentIndex(newCardIndex);
|
|
||||||
setModified(true);
|
|
||||||
|
|
||||||
databaseDisplayDockWidget->searchEdit->setSelection(0, databaseDisplayDockWidget->searchEdit->text().length());
|
databaseDisplayDockWidget->searchEdit->setSelection(0, databaseDisplayDockWidget->searchEdit->text().length());
|
||||||
}
|
}
|
||||||
|
|
@ -184,91 +148,41 @@ void AbstractTabDeckEditor::actAddCardToSideboard(const ExactCard &card)
|
||||||
/** @brief Decrements a card from the main deck. */
|
/** @brief Decrements a card from the main deck. */
|
||||||
void AbstractTabDeckEditor::actDecrementCard(const ExactCard &card)
|
void AbstractTabDeckEditor::actDecrementCard(const ExactCard &card)
|
||||||
{
|
{
|
||||||
emit decrementCard(card, DECK_ZONE_MAIN);
|
deckStateManager->decrementCard(card, DECK_ZONE_MAIN);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Decrements a card from the sideboard. */
|
/** @brief Decrements a card from the sideboard. */
|
||||||
void AbstractTabDeckEditor::actDecrementCardFromSideboard(const ExactCard &card)
|
void AbstractTabDeckEditor::actDecrementCardFromSideboard(const ExactCard &card)
|
||||||
{
|
{
|
||||||
emit decrementCard(card, DECK_ZONE_SIDE);
|
deckStateManager->decrementCard(card, DECK_ZONE_SIDE);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Swaps a card in a deck zone.
|
|
||||||
* @param card Card to swap.
|
|
||||||
* @param zoneName Zone to swap in.
|
|
||||||
*/
|
|
||||||
void AbstractTabDeckEditor::actSwapCard(const ExactCard &card, const QString &zoneName)
|
|
||||||
{
|
|
||||||
QString providerId = card.getPrinting().getUuid();
|
|
||||||
QString collectorNumber = card.getPrinting().getProperty("num");
|
|
||||||
|
|
||||||
QModelIndex foundCard = deckDockWidget->deckModel->findCard(card.getName(), zoneName, providerId, collectorNumber);
|
|
||||||
if (!foundCard.isValid()) {
|
|
||||||
foundCard = deckDockWidget->deckModel->findCard(card.getName(), zoneName);
|
|
||||||
}
|
|
||||||
|
|
||||||
deckDockWidget->swapCard(foundCard);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Opens a deck in this tab.
|
* @brief Opens a deck in this tab.
|
||||||
* @param deck DeckLoader object (takes ownership).
|
* @param deck The deck
|
||||||
*/
|
*/
|
||||||
void AbstractTabDeckEditor::openDeck(DeckLoader *deck)
|
void AbstractTabDeckEditor::openDeck(const LoadedDeck &deck)
|
||||||
{
|
{
|
||||||
setDeck(deck);
|
setDeck(deck);
|
||||||
|
|
||||||
if (!deck->getLastLoadInfo().fileName.isEmpty()) {
|
if (!deck.lastLoadInfo.fileName.isEmpty()) {
|
||||||
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(deck->getLastLoadInfo().fileName);
|
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(deck.lastLoadInfo.fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sets the currently active deck.
|
* @brief Sets the currently active deck.
|
||||||
* @param _deck DeckLoader object.
|
* @param _deck The deck
|
||||||
*/
|
*/
|
||||||
void AbstractTabDeckEditor::setDeck(DeckLoader *_deck)
|
void AbstractTabDeckEditor::setDeck(const LoadedDeck &_deck)
|
||||||
{
|
{
|
||||||
deckDockWidget->setDeck(_deck);
|
deckStateManager->replaceDeck(_deck);
|
||||||
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(getDeckList()->getCardRefList()));
|
CardPictureLoader::cacheCardPixmaps(CardDatabaseManager::query()->getCards(_deck.deckList.getCardRefList()));
|
||||||
setModified(false);
|
|
||||||
|
|
||||||
aDeckDockVisible->setChecked(true);
|
aDeckDockVisible->setChecked(true);
|
||||||
deckDockWidget->setVisible(aDeckDockVisible->isChecked());
|
deckDockWidget->setVisible(aDeckDockVisible->isChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Returns the currently loaded deck. */
|
|
||||||
DeckLoader *AbstractTabDeckEditor::getDeckLoader() const
|
|
||||||
{
|
|
||||||
return deckDockWidget->getDeckLoader();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Returns the currently loaded deck list. */
|
|
||||||
DeckList *AbstractTabDeckEditor::getDeckList() const
|
|
||||||
{
|
|
||||||
return deckDockWidget->getDeckList();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Sets the modified state of the tab.
|
|
||||||
* @param _modified True if tab is modified, false otherwise.
|
|
||||||
*/
|
|
||||||
void AbstractTabDeckEditor::setModified(bool _modified)
|
|
||||||
{
|
|
||||||
modified = _modified;
|
|
||||||
emit tabTextChanged(this, getTabText());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Returns true if the tab is a blank newly created deck.
|
|
||||||
*/
|
|
||||||
bool AbstractTabDeckEditor::isBlankNewDeck() const
|
|
||||||
{
|
|
||||||
DeckLoader *deck = deckDockWidget->getDeckLoader();
|
|
||||||
return !modified && deck->getDeckList()->isBlankDeck() && deck->hasNotBeenLoaded();
|
|
||||||
}
|
|
||||||
|
|
||||||
/** @brief Creates a new deck. Handles opening in new tab if needed. */
|
/** @brief Creates a new deck. Handles opening in new tab if needed. */
|
||||||
void AbstractTabDeckEditor::actNewDeck()
|
void AbstractTabDeckEditor::actNewDeck()
|
||||||
{
|
{
|
||||||
|
|
@ -277,7 +191,7 @@ void AbstractTabDeckEditor::actNewDeck()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (deckOpenLocation == NEW_TAB) {
|
if (deckOpenLocation == NEW_TAB) {
|
||||||
emit openDeckEditor(nullptr);
|
emit openDeckEditor(LoadedDeck());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -287,9 +201,8 @@ void AbstractTabDeckEditor::actNewDeck()
|
||||||
/** @brief Clears the current deck and resets modified flag. */
|
/** @brief Clears the current deck and resets modified flag. */
|
||||||
void AbstractTabDeckEditor::cleanDeckAndResetModified()
|
void AbstractTabDeckEditor::cleanDeckAndResetModified()
|
||||||
{
|
{
|
||||||
|
deckStateManager->clearDeck();
|
||||||
deckMenu->setSaveStatus(false);
|
deckMenu->setSaveStatus(false);
|
||||||
deckDockWidget->cleanDeck();
|
|
||||||
setModified(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -300,13 +213,13 @@ void AbstractTabDeckEditor::cleanDeckAndResetModified()
|
||||||
AbstractTabDeckEditor::DeckOpenLocation AbstractTabDeckEditor::confirmOpen(const bool openInSameTabIfBlank)
|
AbstractTabDeckEditor::DeckOpenLocation AbstractTabDeckEditor::confirmOpen(const bool openInSameTabIfBlank)
|
||||||
{
|
{
|
||||||
if (SettingsCache::instance().getOpenDeckInNewTab()) {
|
if (SettingsCache::instance().getOpenDeckInNewTab()) {
|
||||||
if (openInSameTabIfBlank && isBlankNewDeck())
|
if (openInSameTabIfBlank && deckStateManager->isBlankNewDeck())
|
||||||
return SAME_TAB;
|
return SAME_TAB;
|
||||||
else
|
else
|
||||||
return NEW_TAB;
|
return NEW_TAB;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!modified)
|
if (!deckStateManager->isModified())
|
||||||
return SAME_TAB;
|
return SAME_TAB;
|
||||||
|
|
||||||
tabSupervisor->setCurrentWidget(this);
|
tabSupervisor->setCurrentWidget(this);
|
||||||
|
|
@ -357,7 +270,6 @@ void AbstractTabDeckEditor::actLoadDeck()
|
||||||
|
|
||||||
QString fileName = dialog.selectedFiles().at(0);
|
QString fileName = dialog.selectedFiles().at(0);
|
||||||
openDeckFromFile(fileName, deckOpenLocation);
|
openDeckFromFile(fileName, deckOpenLocation);
|
||||||
deckDockWidget->updateBannerCardComboBox();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -382,17 +294,15 @@ void AbstractTabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLo
|
||||||
{
|
{
|
||||||
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName);
|
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName);
|
||||||
|
|
||||||
auto *l = new DeckLoader(this);
|
auto l = DeckLoader(this);
|
||||||
if (l->loadFromFile(fileName, fmt, true)) {
|
if (l.loadFromFile(fileName, fmt, true)) {
|
||||||
if (deckOpenLocation == NEW_TAB) {
|
if (deckOpenLocation == NEW_TAB) {
|
||||||
emit openDeckEditor(l);
|
emit openDeckEditor(l.getDeck());
|
||||||
l->deleteLater();
|
|
||||||
} else {
|
} else {
|
||||||
deckMenu->setSaveStatus(false);
|
deckMenu->setSaveStatus(false);
|
||||||
openDeck(l);
|
openDeck(l.getDeck());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
l->deleteLater();
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(fileName));
|
QMessageBox::critical(this, tr("Error"), tr("Could not open deck at %1").arg(fileName));
|
||||||
}
|
}
|
||||||
deckMenu->setSaveStatus(true);
|
deckMenu->setSaveStatus(true);
|
||||||
|
|
@ -405,16 +315,16 @@ void AbstractTabDeckEditor::openDeckFromFile(const QString &fileName, DeckOpenLo
|
||||||
*/
|
*/
|
||||||
bool AbstractTabDeckEditor::actSaveDeck()
|
bool AbstractTabDeckEditor::actSaveDeck()
|
||||||
{
|
{
|
||||||
DeckLoader *const deck = getDeckLoader();
|
const auto loadedDeck = deckStateManager->toLoadedDeck();
|
||||||
if (deck->getLastLoadInfo().remoteDeckId != LoadedDeck::LoadInfo::NON_REMOTE_ID) {
|
if (loadedDeck.lastLoadInfo.remoteDeckId != LoadedDeck::LoadInfo::NON_REMOTE_ID) {
|
||||||
QString deckString = deck->getDeckList()->writeToString_Native();
|
QString deckString = loadedDeck.deckList.writeToString_Native();
|
||||||
if (deckString.length() > MAX_FILE_LENGTH) {
|
if (deckString.length() > MAX_FILE_LENGTH) {
|
||||||
QMessageBox::critical(this, tr("Error"), tr("Could not save remote deck"));
|
QMessageBox::critical(this, tr("Error"), tr("Could not save remote deck"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Command_DeckUpload cmd;
|
Command_DeckUpload cmd;
|
||||||
cmd.set_deck_id(static_cast<google::protobuf::uint32>(deck->getLastLoadInfo().remoteDeckId));
|
cmd.set_deck_id(static_cast<google::protobuf::uint32>(loadedDeck.lastLoadInfo.remoteDeckId));
|
||||||
cmd.set_deck_list(deckString.toStdString());
|
cmd.set_deck_list(deckString.toStdString());
|
||||||
|
|
||||||
PendingCommand *pend = AbstractClient::prepareSessionCommand(cmd);
|
PendingCommand *pend = AbstractClient::prepareSessionCommand(cmd);
|
||||||
|
|
@ -422,10 +332,14 @@ bool AbstractTabDeckEditor::actSaveDeck()
|
||||||
tabSupervisor->getClient()->sendCommand(pend);
|
tabSupervisor->getClient()->sendCommand(pend);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
} else if (deck->getLastLoadInfo().fileName.isEmpty())
|
}
|
||||||
|
if (loadedDeck.lastLoadInfo.fileName.isEmpty())
|
||||||
return actSaveDeckAs();
|
return actSaveDeckAs();
|
||||||
else if (deck->saveToFile(deck->getLastLoadInfo().fileName, deck->getLastLoadInfo().fileFormat)) {
|
|
||||||
setModified(false);
|
auto deckLoader = DeckLoader(this);
|
||||||
|
deckLoader.setDeck(loadedDeck);
|
||||||
|
if (deckLoader.saveToFile(loadedDeck.lastLoadInfo.fileName, loadedDeck.lastLoadInfo.fileFormat)) {
|
||||||
|
deckStateManager->setModified(false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -441,12 +355,14 @@ bool AbstractTabDeckEditor::actSaveDeck()
|
||||||
*/
|
*/
|
||||||
bool AbstractTabDeckEditor::actSaveDeckAs()
|
bool AbstractTabDeckEditor::actSaveDeckAs()
|
||||||
{
|
{
|
||||||
|
LoadedDeck loadedDeck = deckStateManager->toLoadedDeck();
|
||||||
|
|
||||||
QFileDialog dialog(this, tr("Save deck"));
|
QFileDialog dialog(this, tr("Save deck"));
|
||||||
dialog.setDirectory(SettingsCache::instance().getDeckPath());
|
dialog.setDirectory(SettingsCache::instance().getDeckPath());
|
||||||
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
dialog.setAcceptMode(QFileDialog::AcceptSave);
|
||||||
dialog.setDefaultSuffix("cod");
|
dialog.setDefaultSuffix("cod");
|
||||||
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
|
dialog.setNameFilters(DeckLoader::FILE_NAME_FILTERS);
|
||||||
dialog.selectFile(getDeckList()->getName().trimmed());
|
dialog.selectFile(loadedDeck.deckList.getName().trimmed());
|
||||||
|
|
||||||
if (!dialog.exec())
|
if (!dialog.exec())
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -454,14 +370,18 @@ bool AbstractTabDeckEditor::actSaveDeckAs()
|
||||||
QString fileName = dialog.selectedFiles().at(0);
|
QString fileName = dialog.selectedFiles().at(0);
|
||||||
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName);
|
DeckFileFormat::Format fmt = DeckFileFormat::getFormatFromName(fileName);
|
||||||
|
|
||||||
if (!getDeckLoader()->saveToFile(fileName, fmt)) {
|
DeckLoader deckLoader = DeckLoader(this);
|
||||||
|
deckLoader.setDeck(loadedDeck);
|
||||||
|
if (!deckLoader.saveToFile(fileName, fmt)) {
|
||||||
QMessageBox::critical(
|
QMessageBox::critical(
|
||||||
this, tr("Error"),
|
this, tr("Error"),
|
||||||
tr("The deck could not be saved.\nPlease check that the directory is writable and try again."));
|
tr("The deck could not be saved.\nPlease check that the directory is writable and try again."));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
setModified(false);
|
deckStateManager->setLastLoadInfo({.fileName = fileName, .fileFormat = fmt});
|
||||||
|
|
||||||
|
deckStateManager->setModified(false);
|
||||||
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
|
SettingsCache::instance().recents().updateRecentlyOpenedDeckPaths(fileName);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
@ -475,7 +395,7 @@ void AbstractTabDeckEditor::saveDeckRemoteFinished(const Response &response)
|
||||||
if (response.response_code() != Response::RespOk)
|
if (response.response_code() != Response::RespOk)
|
||||||
QMessageBox::critical(this, tr("Error"), tr("The deck could not be saved."));
|
QMessageBox::critical(this, tr("Error"), tr("The deck could not be saved."));
|
||||||
else
|
else
|
||||||
setModified(false);
|
deckStateManager->setModified(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -493,10 +413,10 @@ void AbstractTabDeckEditor::actLoadDeckFromClipboard()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (deckOpenLocation == NEW_TAB) {
|
if (deckOpenLocation == NEW_TAB) {
|
||||||
emit openDeckEditor(dlg.getDeckList());
|
emit openDeckEditor({.deckList = dlg.getDeckList()});
|
||||||
} else {
|
} else {
|
||||||
setDeck(dlg.getDeckList());
|
setDeck({.deckList = dlg.getDeckList()});
|
||||||
setModified(true);
|
deckStateManager->setModified(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
deckMenu->setSaveStatus(true);
|
deckMenu->setSaveStatus(true);
|
||||||
|
|
@ -508,12 +428,13 @@ void AbstractTabDeckEditor::actLoadDeckFromClipboard()
|
||||||
*/
|
*/
|
||||||
void AbstractTabDeckEditor::editDeckInClipboard(bool annotated)
|
void AbstractTabDeckEditor::editDeckInClipboard(bool annotated)
|
||||||
{
|
{
|
||||||
DlgEditDeckInClipboard dlg(getDeckLoader(), annotated, this);
|
LoadedDeck loadedDeck = deckStateManager->toLoadedDeck();
|
||||||
|
DlgEditDeckInClipboard dlg(loadedDeck.deckList, annotated, this);
|
||||||
if (!dlg.exec())
|
if (!dlg.exec())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
setDeck(dlg.getDeckList());
|
setDeck({dlg.getDeckList(), loadedDeck.lastLoadInfo});
|
||||||
setModified(true);
|
deckStateManager->setModified(true);
|
||||||
deckMenu->setSaveStatus(true);
|
deckMenu->setSaveStatus(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -532,25 +453,25 @@ void AbstractTabDeckEditor::actEditDeckInClipboardRaw()
|
||||||
/** @brief Saves deck to clipboard with set info and annotation. */
|
/** @brief Saves deck to clipboard with set info and annotation. */
|
||||||
void AbstractTabDeckEditor::actSaveDeckToClipboard()
|
void AbstractTabDeckEditor::actSaveDeckToClipboard()
|
||||||
{
|
{
|
||||||
DeckLoader::saveToClipboard(getDeckList(), true, true);
|
DeckLoader::saveToClipboard(deckStateManager->getDeckList(), true, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Saves deck to clipboard with annotation, without set info. */
|
/** @brief Saves deck to clipboard with annotation, without set info. */
|
||||||
void AbstractTabDeckEditor::actSaveDeckToClipboardNoSetInfo()
|
void AbstractTabDeckEditor::actSaveDeckToClipboardNoSetInfo()
|
||||||
{
|
{
|
||||||
DeckLoader::saveToClipboard(getDeckList(), true, false);
|
DeckLoader::saveToClipboard(deckStateManager->getDeckList(), true, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Saves deck to clipboard without annotations, with set info. */
|
/** @brief Saves deck to clipboard without annotations, with set info. */
|
||||||
void AbstractTabDeckEditor::actSaveDeckToClipboardRaw()
|
void AbstractTabDeckEditor::actSaveDeckToClipboardRaw()
|
||||||
{
|
{
|
||||||
DeckLoader::saveToClipboard(getDeckList(), false, true);
|
DeckLoader::saveToClipboard(deckStateManager->getDeckList(), false, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Saves deck to clipboard without annotations or set info. */
|
/** @brief Saves deck to clipboard without annotations or set info. */
|
||||||
void AbstractTabDeckEditor::actSaveDeckToClipboardRawNoSetInfo()
|
void AbstractTabDeckEditor::actSaveDeckToClipboardRawNoSetInfo()
|
||||||
{
|
{
|
||||||
DeckLoader::saveToClipboard(getDeckList(), false, false);
|
DeckLoader::saveToClipboard(deckStateManager->getDeckList(), false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Prints the deck using a QPrintPreviewDialog. */
|
/** @brief Prints the deck using a QPrintPreviewDialog. */
|
||||||
|
|
@ -558,7 +479,7 @@ void AbstractTabDeckEditor::actPrintDeck()
|
||||||
{
|
{
|
||||||
auto *dlg = new QPrintPreviewDialog(this);
|
auto *dlg = new QPrintPreviewDialog(this);
|
||||||
connect(dlg, &QPrintPreviewDialog::paintRequested, this,
|
connect(dlg, &QPrintPreviewDialog::paintRequested, this,
|
||||||
[this](QPrinter *printer) { DeckLoader::printDeckList(printer, getDeckList()); });
|
[this](QPrinter *printer) { DeckLoader::printDeckList(printer, deckStateManager->getDeckList()); });
|
||||||
dlg->exec();
|
dlg->exec();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -576,10 +497,10 @@ void AbstractTabDeckEditor::actLoadDeckFromWebsite()
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (deckOpenLocation == NEW_TAB) {
|
if (deckOpenLocation == NEW_TAB) {
|
||||||
emit openDeckEditor(dlg.getDeck());
|
emit openDeckEditor({.deckList = dlg.getDeck()});
|
||||||
} else {
|
} else {
|
||||||
setDeck(dlg.getDeck());
|
setDeck({.deckList = dlg.getDeck()});
|
||||||
setModified(true);
|
deckStateManager->setModified(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
deckMenu->setSaveStatus(true);
|
deckMenu->setSaveStatus(true);
|
||||||
|
|
@ -591,26 +512,21 @@ void AbstractTabDeckEditor::actLoadDeckFromWebsite()
|
||||||
*/
|
*/
|
||||||
void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website)
|
void AbstractTabDeckEditor::exportToDecklistWebsite(DeckLoader::DecklistWebsite website)
|
||||||
{
|
{
|
||||||
if (DeckLoader *const deck = getDeckLoader()) {
|
QString decklistUrlString = DeckLoader::exportDeckToDecklist(deckStateManager->getDeckList(), website);
|
||||||
QString decklistUrlString = deck->exportDeckToDecklist(getDeckList(), website);
|
// Check to make sure the string isn't empty.
|
||||||
// Check to make sure the string isn't empty.
|
if (decklistUrlString.isEmpty()) {
|
||||||
if (decklistUrlString.isEmpty()) {
|
// Show an error if the deck is empty, and return.
|
||||||
// Show an error if the deck is empty, and return.
|
QMessageBox::critical(this, tr("Error"), tr("There are no cards in your deck to be exported"));
|
||||||
QMessageBox::critical(this, tr("Error"), tr("There are no cards in your deck to be exported"));
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Encode the string recieved from the model to make sure all characters are encoded.
|
|
||||||
// first we put it into a qurl object
|
|
||||||
QUrl decklistUrl = QUrl(decklistUrlString);
|
|
||||||
// we get the correctly encoded url.
|
|
||||||
decklistUrlString = decklistUrl.toEncoded();
|
|
||||||
// We open the url in the user's default browser
|
|
||||||
QDesktopServices::openUrl(decklistUrlString);
|
|
||||||
} else {
|
|
||||||
// if there's no deck loader object, return an error
|
|
||||||
QMessageBox::critical(this, tr("Error"), tr("No deck was selected to be exported."));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Encode the string recieved from the model to make sure all characters are encoded.
|
||||||
|
// first we put it into a qurl object
|
||||||
|
QUrl decklistUrl = QUrl(decklistUrlString);
|
||||||
|
// we get the correctly encoded url.
|
||||||
|
decklistUrlString = decklistUrl.toEncoded();
|
||||||
|
// We open the url in the user's default browser
|
||||||
|
QDesktopServices::openUrl(decklistUrlString);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Exports deck to www.decklist.org. */
|
/** @brief Exports deck to www.decklist.org. */
|
||||||
|
|
@ -629,14 +545,14 @@ void AbstractTabDeckEditor::actExportDeckDecklistXyz()
|
||||||
void AbstractTabDeckEditor::actAnalyzeDeckDeckstats()
|
void AbstractTabDeckEditor::actAnalyzeDeckDeckstats()
|
||||||
{
|
{
|
||||||
auto *interface = new DeckStatsInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(), this);
|
auto *interface = new DeckStatsInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(), this);
|
||||||
interface->analyzeDeck(getDeckList());
|
interface->analyzeDeck(deckStateManager->getDeckList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Analyzes the deck using TappedOut. */
|
/** @brief Analyzes the deck using TappedOut. */
|
||||||
void AbstractTabDeckEditor::actAnalyzeDeckTappedout()
|
void AbstractTabDeckEditor::actAnalyzeDeckTappedout()
|
||||||
{
|
{
|
||||||
auto *interface = new TappedOutInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(), this);
|
auto *interface = new TappedOutInterface(*databaseDisplayDockWidget->databaseModel->getDatabase(), this);
|
||||||
interface->analyzeDeck(getDeckList());
|
interface->analyzeDeck(deckStateManager->getDeckList());
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @brief Applies a new filter tree to the database display. */
|
/** @brief Applies a new filter tree to the database display. */
|
||||||
|
|
@ -695,7 +611,7 @@ bool AbstractTabDeckEditor::eventFilter(QObject *o, QEvent *e)
|
||||||
/** @brief Shows a confirmation dialog before closing. */
|
/** @brief Shows a confirmation dialog before closing. */
|
||||||
bool AbstractTabDeckEditor::confirmClose()
|
bool AbstractTabDeckEditor::confirmClose()
|
||||||
{
|
{
|
||||||
if (modified) {
|
if (deckStateManager->isModified()) {
|
||||||
tabSupervisor->setCurrentWidget(this);
|
tabSupervisor->setCurrentWidget(this);
|
||||||
int ret = createSaveConfirmationWindow()->exec();
|
int ret = createSaveConfirmationWindow()->exec();
|
||||||
if (ret == QMessageBox::Save)
|
if (ret == QMessageBox::Save)
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <libcockatrice/deck_list/deck_list_history_manager.h>
|
#include <libcockatrice/deck_list/deck_list_history_manager.h>
|
||||||
|
|
||||||
|
class DeckStateManager;
|
||||||
class CardDatabaseModel;
|
class CardDatabaseModel;
|
||||||
class CardDatabaseDisplayModel;
|
class CardDatabaseDisplayModel;
|
||||||
|
|
||||||
|
|
@ -77,7 +78,6 @@ class QAction;
|
||||||
*
|
*
|
||||||
* - actAddCard(const ExactCard &card) — Adds a card to the deck.
|
* - actAddCard(const ExactCard &card) — Adds a card to the deck.
|
||||||
* - actDecrementCard(const ExactCard &card) — Removes a single instance of a card from the deck.
|
* - actDecrementCard(const ExactCard &card) — Removes a single instance of a card from the deck.
|
||||||
* - actSwapCard(const ExactCard &card, const QString &zone) — Swaps a card between zones.
|
|
||||||
* - actRemoveCard() — Removes the currently selected card from the deck.
|
* - actRemoveCard() — Removes the currently selected card from the deck.
|
||||||
* - actSaveDeckAs() — Performs a "Save As" action for the deck.
|
* - actSaveDeckAs() — Performs a "Save As" action for the deck.
|
||||||
* - updateCard(const ExactCard &card) — Updates the currently displayed card info in the dock.
|
* - updateCard(const ExactCard &card) — Updates the currently displayed card info in the dock.
|
||||||
|
|
@ -114,34 +114,17 @@ public:
|
||||||
virtual void retranslateUi() override = 0;
|
virtual void retranslateUi() override = 0;
|
||||||
|
|
||||||
/** @brief Opens a deck in this tab.
|
/** @brief Opens a deck in this tab.
|
||||||
* @param deck Pointer to a DeckLoader object.
|
* @param deck The deck to open
|
||||||
*/
|
*/
|
||||||
void openDeck(DeckLoader *deck);
|
void openDeck(const LoadedDeck &deck);
|
||||||
|
|
||||||
/** @brief Returns the currently active deck loader. */
|
|
||||||
DeckLoader *getDeckLoader() const;
|
|
||||||
|
|
||||||
/** @brief Returns the currently active deck list. */
|
|
||||||
DeckList *getDeckList() const;
|
|
||||||
|
|
||||||
/** @brief Sets the modified state of the tab.
|
|
||||||
* @param _windowModified Whether the tab is modified.
|
|
||||||
*/
|
|
||||||
void setModified(bool _windowModified);
|
|
||||||
|
|
||||||
DeckEditorDeckDockWidget *getDeckDockWidget() const
|
DeckEditorDeckDockWidget *getDeckDockWidget() const
|
||||||
{
|
{
|
||||||
return deckDockWidget;
|
return deckDockWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
DeckListHistoryManager *getHistoryManager() const
|
|
||||||
{
|
|
||||||
return historyManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
DeckListHistoryManager *historyManager;
|
|
||||||
|
|
||||||
// UI Elements
|
// UI Elements
|
||||||
|
DeckStateManager *deckStateManager;
|
||||||
DeckEditorMenu *deckMenu; ///< Menu for deck operations
|
DeckEditorMenu *deckMenu; ///< Menu for deck operations
|
||||||
DeckEditorDatabaseDisplayWidget *databaseDisplayDockWidget; ///< Database dock
|
DeckEditorDatabaseDisplayWidget *databaseDisplayDockWidget; ///< Database dock
|
||||||
DeckEditorCardInfoDockWidget *cardInfoDockWidget; ///< Card info dock
|
DeckEditorCardInfoDockWidget *cardInfoDockWidget; ///< Card info dock
|
||||||
|
|
@ -156,14 +139,6 @@ public slots:
|
||||||
/** @brief Called when the deck is modified. */
|
/** @brief Called when the deck is modified. */
|
||||||
virtual void onDeckModified();
|
virtual void onDeckModified();
|
||||||
|
|
||||||
/** @brief Called when a widget is about to modify the state of the DeckList.
|
|
||||||
* @param modificationReason The reason for the state modification
|
|
||||||
*/
|
|
||||||
virtual void onDeckHistorySaveRequested(const QString &modificationReason);
|
|
||||||
|
|
||||||
/** @brief Called when a widget would like to clear the history. */
|
|
||||||
virtual void onDeckHistoryClearRequested();
|
|
||||||
|
|
||||||
/** @brief Updates the card info panel.
|
/** @brief Updates the card info panel.
|
||||||
* @param card The card to display.
|
* @param card The card to display.
|
||||||
*/
|
*/
|
||||||
|
|
@ -198,14 +173,11 @@ public slots:
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
/** @brief Emitted when a deck should be opened in a new editor tab. */
|
/** @brief Emitted when a deck should be opened in a new editor tab. */
|
||||||
void openDeckEditor(DeckLoader *deckLoader);
|
void openDeckEditor(const LoadedDeck &deck);
|
||||||
|
|
||||||
/** @brief Emitted before the tab is closed. */
|
/** @brief Emitted before the tab is closed. */
|
||||||
void deckEditorClosing(AbstractTabDeckEditor *tab);
|
void deckEditorClosing(AbstractTabDeckEditor *tab);
|
||||||
|
|
||||||
/** @brief Emitted when a card should be decremented. */
|
|
||||||
void decrementCard(const ExactCard &card, QString zoneName);
|
|
||||||
|
|
||||||
protected slots:
|
protected slots:
|
||||||
/** @brief Starts a new deck in this tab. */
|
/** @brief Starts a new deck in this tab. */
|
||||||
virtual void actNewDeck();
|
virtual void actNewDeck();
|
||||||
|
|
@ -286,7 +258,7 @@ private:
|
||||||
/** @brief Sets the deck for this tab.
|
/** @brief Sets the deck for this tab.
|
||||||
* @param _deck The deck object.
|
* @param _deck The deck object.
|
||||||
*/
|
*/
|
||||||
virtual void setDeck(DeckLoader *_deck);
|
virtual void setDeck(const LoadedDeck &_deck);
|
||||||
|
|
||||||
/** @brief Helper for editing decks from the clipboard. */
|
/** @brief Helper for editing decks from the clipboard. */
|
||||||
void editDeckInClipboard(bool annotated);
|
void editDeckInClipboard(bool annotated);
|
||||||
|
|
@ -316,14 +288,8 @@ protected:
|
||||||
*/
|
*/
|
||||||
QMessageBox *createSaveConfirmationWindow();
|
QMessageBox *createSaveConfirmationWindow();
|
||||||
|
|
||||||
/** @brief Returns true if the tab is a blank newly created deck. */
|
|
||||||
bool isBlankNewDeck() const;
|
|
||||||
|
|
||||||
/** @brief Helper function to add a card to a specific deck zone. */
|
/** @brief Helper function to add a card to a specific deck zone. */
|
||||||
void addCardHelper(const ExactCard &card, QString zoneName);
|
void addCardHelper(const ExactCard &card, const QString &zoneName);
|
||||||
|
|
||||||
/** @brief Swaps a card in the deck view. */
|
|
||||||
void actSwapCard(const ExactCard &card, const QString &zoneName);
|
|
||||||
|
|
||||||
/** @brief Opens a deck from a file. */
|
/** @brief Opens a deck from a file. */
|
||||||
virtual void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);
|
virtual void openDeckFromFile(const QString &fileName, DeckOpenLocation deckOpenLocation);
|
||||||
|
|
@ -334,8 +300,6 @@ protected:
|
||||||
QAction *aResetLayout;
|
QAction *aResetLayout;
|
||||||
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
|
QAction *aCardInfoDockVisible, *aCardInfoDockFloating, *aDeckDockVisible, *aDeckDockFloating;
|
||||||
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
|
QAction *aFilterDockVisible, *aFilterDockFloating, *aPrintingSelectorDockVisible, *aPrintingSelectorDockFloating;
|
||||||
|
|
||||||
bool modified = false; ///< Whether the deck/tab has unsaved changes
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // TAB_GENERIC_DECK_EDITOR_H
|
#endif // TAB_GENERIC_DECK_EDITOR_H
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,227 @@
|
||||||
|
#ifndef COCKATRICE_ARCHIDEKT_FORMATS_H
|
||||||
|
#define COCKATRICE_ARCHIDEKT_FORMATS_H
|
||||||
|
#include <QHash>
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace ArchidektFormats
|
||||||
|
{
|
||||||
|
enum class DeckFormat
|
||||||
|
{
|
||||||
|
Standard = 0,
|
||||||
|
Modern = 1,
|
||||||
|
Commander = 2,
|
||||||
|
Legacy = 3,
|
||||||
|
Vintage = 4,
|
||||||
|
Pauper = 5,
|
||||||
|
Custom = 6,
|
||||||
|
Frontier = 7,
|
||||||
|
FutureStandard = 8,
|
||||||
|
PennyDreadful = 9,
|
||||||
|
Commander1v1 = 10,
|
||||||
|
DualCommander = 11,
|
||||||
|
Brawl = 12,
|
||||||
|
|
||||||
|
// Values outside Archidekt range
|
||||||
|
Alchemy = 1000,
|
||||||
|
Historic = 1001,
|
||||||
|
Gladiator = 1002,
|
||||||
|
Oathbreaker = 1003,
|
||||||
|
OldSchool = 1004,
|
||||||
|
PauperCommander = 1005,
|
||||||
|
Pioneer = 1006,
|
||||||
|
PreDH = 1007,
|
||||||
|
Premodern = 1008,
|
||||||
|
StandardBrawl = 1009,
|
||||||
|
Timeless = 1010,
|
||||||
|
Unknown = 1011
|
||||||
|
};
|
||||||
|
|
||||||
|
inline static QString formatToApiName(DeckFormat format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case DeckFormat::Standard:
|
||||||
|
return "Standard";
|
||||||
|
case DeckFormat::Modern:
|
||||||
|
return "Modern";
|
||||||
|
case DeckFormat::Commander:
|
||||||
|
return "Commander";
|
||||||
|
case DeckFormat::Legacy:
|
||||||
|
return "Legacy";
|
||||||
|
case DeckFormat::Vintage:
|
||||||
|
return "Vintage";
|
||||||
|
case DeckFormat::Pauper:
|
||||||
|
return "Pauper";
|
||||||
|
case DeckFormat::Custom:
|
||||||
|
return "Custom";
|
||||||
|
case DeckFormat::Frontier:
|
||||||
|
return "Frontier";
|
||||||
|
case DeckFormat::FutureStandard:
|
||||||
|
return "Future Std";
|
||||||
|
case DeckFormat::PennyDreadful:
|
||||||
|
return "Penny Dreadful";
|
||||||
|
case DeckFormat::Commander1v1:
|
||||||
|
return "1v1 Commander";
|
||||||
|
case DeckFormat::DualCommander:
|
||||||
|
return "Dual Commander";
|
||||||
|
case DeckFormat::Brawl:
|
||||||
|
return "Brawl";
|
||||||
|
|
||||||
|
case DeckFormat::Alchemy:
|
||||||
|
return "Alchemy";
|
||||||
|
case DeckFormat::Historic:
|
||||||
|
return "Historic";
|
||||||
|
case DeckFormat::Gladiator:
|
||||||
|
return "Gladiator";
|
||||||
|
case DeckFormat::Oathbreaker:
|
||||||
|
return "Oathbreaker";
|
||||||
|
case DeckFormat::OldSchool:
|
||||||
|
return "Old School";
|
||||||
|
case DeckFormat::PauperCommander:
|
||||||
|
return "Pauper Commander";
|
||||||
|
case DeckFormat::Pioneer:
|
||||||
|
return "Pioneer";
|
||||||
|
case DeckFormat::PreDH:
|
||||||
|
return "PreDH";
|
||||||
|
case DeckFormat::Premodern:
|
||||||
|
return "Premodern";
|
||||||
|
case DeckFormat::StandardBrawl:
|
||||||
|
return "Standard Brawl";
|
||||||
|
case DeckFormat::Timeless:
|
||||||
|
return "Timeless";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static DeckFormat apiNameToFormat(const QString &name)
|
||||||
|
{
|
||||||
|
const QString n = name.trimmed();
|
||||||
|
|
||||||
|
if (n.compare("Standard", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Standard;
|
||||||
|
if (n.compare("Modern", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Modern;
|
||||||
|
if (n.compare("Commander", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Commander;
|
||||||
|
if (n.compare("Legacy", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Legacy;
|
||||||
|
if (n.compare("Vintage", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Vintage;
|
||||||
|
if (n.compare("Pauper", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Pauper;
|
||||||
|
if (n.compare("Custom", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Custom;
|
||||||
|
if (n.compare("Frontier", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Frontier;
|
||||||
|
if (n.compare("Future Std", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::FutureStandard;
|
||||||
|
if (n.compare("Penny Dreadful", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::PennyDreadful;
|
||||||
|
if (n.compare("1v1 Commander", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Commander1v1;
|
||||||
|
if (n.compare("Dual Commander", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::DualCommander;
|
||||||
|
if (n.compare("Brawl", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Brawl;
|
||||||
|
|
||||||
|
if (n.compare("Alchemy", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Alchemy;
|
||||||
|
if (n.compare("Historic", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Historic;
|
||||||
|
if (n.compare("Gladiator", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Gladiator;
|
||||||
|
if (n.compare("Oathbreaker", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Oathbreaker;
|
||||||
|
if (n.compare("Old School", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::OldSchool;
|
||||||
|
if (n.compare("Pauper Commander", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::PauperCommander;
|
||||||
|
if (n.compare("Pioneer", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Pioneer;
|
||||||
|
if (n.compare("PreDH", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::PreDH;
|
||||||
|
if (n.compare("Premodern", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Premodern;
|
||||||
|
if (n.compare("Standard Brawl", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::StandardBrawl;
|
||||||
|
if (n.compare("Timeless", Qt::CaseInsensitive) == 0)
|
||||||
|
return DeckFormat::Timeless;
|
||||||
|
|
||||||
|
return DeckFormat::Unknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static QString formatToCockatriceName(DeckFormat format)
|
||||||
|
{
|
||||||
|
switch (format) {
|
||||||
|
case DeckFormat::Standard:
|
||||||
|
return "standard";
|
||||||
|
case DeckFormat::Modern:
|
||||||
|
return "modern";
|
||||||
|
case DeckFormat::Commander:
|
||||||
|
return "commander";
|
||||||
|
case DeckFormat::Legacy:
|
||||||
|
return "legacy";
|
||||||
|
case DeckFormat::Vintage:
|
||||||
|
return "vintage";
|
||||||
|
case DeckFormat::Pauper:
|
||||||
|
return "pauper";
|
||||||
|
case DeckFormat::Brawl:
|
||||||
|
return "brawl";
|
||||||
|
case DeckFormat::PennyDreadful:
|
||||||
|
return "penny";
|
||||||
|
case DeckFormat::FutureStandard:
|
||||||
|
return "future";
|
||||||
|
case DeckFormat::Commander1v1:
|
||||||
|
return "duel";
|
||||||
|
case DeckFormat::DualCommander:
|
||||||
|
return "duel";
|
||||||
|
case DeckFormat::Alchemy:
|
||||||
|
return "alchemy";
|
||||||
|
case DeckFormat::Historic:
|
||||||
|
return "historic";
|
||||||
|
case DeckFormat::Gladiator:
|
||||||
|
return "gladiator";
|
||||||
|
case DeckFormat::Oathbreaker:
|
||||||
|
return "oathbreaker";
|
||||||
|
case DeckFormat::OldSchool:
|
||||||
|
return "oldschool";
|
||||||
|
case DeckFormat::PauperCommander:
|
||||||
|
return "paupercommander";
|
||||||
|
case DeckFormat::Pioneer:
|
||||||
|
return "pioneer";
|
||||||
|
case DeckFormat::PreDH:
|
||||||
|
return "predh";
|
||||||
|
case DeckFormat::Premodern:
|
||||||
|
return "premodern";
|
||||||
|
case DeckFormat::StandardBrawl:
|
||||||
|
return "standardbrawl";
|
||||||
|
case DeckFormat::Timeless:
|
||||||
|
return "timeless";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inline static DeckFormat cockatriceNameToFormat(const QString &apiName)
|
||||||
|
{
|
||||||
|
static const QHash<QString, DeckFormat> map = {
|
||||||
|
{"standard", DeckFormat::Standard}, {"modern", DeckFormat::Modern},
|
||||||
|
{"commander", DeckFormat::Commander}, {"legacy", DeckFormat::Legacy},
|
||||||
|
{"vintage", DeckFormat::Vintage}, {"pauper", DeckFormat::Pauper},
|
||||||
|
{"brawl", DeckFormat::Brawl}, {"penny", DeckFormat::PennyDreadful},
|
||||||
|
{"future", DeckFormat::FutureStandard}, {"duel", DeckFormat::Commander1v1},
|
||||||
|
{"alchemy", DeckFormat::Alchemy}, {"historic", DeckFormat::Historic},
|
||||||
|
{"gladiator", DeckFormat::Gladiator}, {"oathbreaker", DeckFormat::Oathbreaker},
|
||||||
|
{"oldschool", DeckFormat::OldSchool}, {"paupercommander", DeckFormat::PauperCommander},
|
||||||
|
{"pioneer", DeckFormat::Pioneer}, {"predh", DeckFormat::PreDH},
|
||||||
|
{"premodern", DeckFormat::Premodern}, {"standardbrawl", DeckFormat::StandardBrawl},
|
||||||
|
{"timeless", DeckFormat::Timeless}};
|
||||||
|
|
||||||
|
return map.value(apiName.toLower(), DeckFormat::Unknown);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ArchidektFormats
|
||||||
|
|
||||||
|
#endif // COCKATRICE_ARCHIDEKT_FORMATS_H
|
||||||
|
|
@ -21,16 +21,16 @@ void ArchidektApiResponseCard::fromJson(const QJsonObject &json)
|
||||||
edition.fromJson(json.value("edition").toObject());
|
edition.fromJson(json.value("edition").toObject());
|
||||||
|
|
||||||
flavor = json.value("flavor").toString();
|
flavor = json.value("flavor").toString();
|
||||||
// TODO but not really important
|
//! \todo but not really important
|
||||||
// games = {""};
|
//! \todo games = {""};
|
||||||
// options = {""};
|
//! \todo options = {""};
|
||||||
scryfallImageHash = json.value("scryfallImageHash").toString();
|
scryfallImageHash = json.value("scryfallImageHash").toString();
|
||||||
oracleCard = json.value("oracleCard").toObject();
|
oracleCard = json.value("oracleCard").toObject();
|
||||||
owned = json.value("owned").toInt();
|
owned = json.value("owned").toInt();
|
||||||
pinnedStatus = json.value("pinnedStatus").toInt();
|
pinnedStatus = json.value("pinnedStatus").toInt();
|
||||||
rarity = json.value("rarity").toString();
|
rarity = json.value("rarity").toString();
|
||||||
// TODO but not really important
|
//! \todo but not really important
|
||||||
// globalCategories = {""};
|
//! \todo globalCategories = {""};
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArchidektApiResponseCard::debugPrint() const
|
void ArchidektApiResponseCard::debugPrint() const
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,11 @@ public:
|
||||||
return name;
|
return name;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
int getDeckFormat() const
|
||||||
|
{
|
||||||
|
return deckFormat;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
int id;
|
int id;
|
||||||
QString name;
|
QString name;
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
#include "../../../../cards/card_size_widget.h"
|
#include "../../../../cards/card_size_widget.h"
|
||||||
#include "../../../../cards/deck_card_zone_display_widget.h"
|
#include "../../../../cards/deck_card_zone_display_widget.h"
|
||||||
#include "../../../../visual_deck_editor/visual_deck_display_options_widget.h"
|
#include "../../../../visual_deck_editor/visual_deck_display_options_widget.h"
|
||||||
|
#include "../api_response/archidekt_formats.h"
|
||||||
#include "../api_response/deck/archidekt_api_response_deck.h"
|
#include "../api_response/deck/archidekt_api_response_deck.h"
|
||||||
|
|
||||||
#include <QSortFilterProxyModel>
|
#include <QSortFilterProxyModel>
|
||||||
|
|
@ -67,11 +68,12 @@ ArchidektApiResponseDeckDisplayWidget::ArchidektApiResponseDeckDisplayWidget(QWi
|
||||||
|
|
||||||
model = new DeckListModel(this);
|
model = new DeckListModel(this);
|
||||||
connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset);
|
connect(model, &DeckListModel::modelReset, this, &ArchidektApiResponseDeckDisplayWidget::decklistModelReset);
|
||||||
model->getDeckList()->loadFromStream_Plain(deckStream, false);
|
|
||||||
|
|
||||||
model->getDeckList()->forEachCard(CardNodeFunction::ResolveProviderId());
|
auto decklist = QSharedPointer<DeckList>(new DeckList);
|
||||||
|
decklist->loadFromStream_Plain(deckStream, false);
|
||||||
|
model->setDeckList(decklist);
|
||||||
|
|
||||||
model->rebuildTree();
|
model->forEachCard(CardNodeFunction::ResolveProviderId());
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
}
|
}
|
||||||
|
|
@ -84,17 +86,19 @@ void ArchidektApiResponseDeckDisplayWidget::retranslateUi()
|
||||||
void ArchidektApiResponseDeckDisplayWidget::onGroupCriteriaChange(const QString &activeGroupCriteria)
|
void ArchidektApiResponseDeckDisplayWidget::onGroupCriteriaChange(const QString &activeGroupCriteria)
|
||||||
{
|
{
|
||||||
model->setActiveGroupCriteria(DeckListModelGroupCriteria::fromString(activeGroupCriteria));
|
model->setActiveGroupCriteria(DeckListModelGroupCriteria::fromString(activeGroupCriteria));
|
||||||
model->sort(1, Qt::AscendingOrder);
|
model->sort(DeckListModelColumns::CARD_NAME, Qt::AscendingOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArchidektApiResponseDeckDisplayWidget::actOpenInDeckEditor()
|
void ArchidektApiResponseDeckDisplayWidget::actOpenInDeckEditor()
|
||||||
{
|
{
|
||||||
auto loader = new DeckLoader(this);
|
DeckList deckList(*model->getDeckList());
|
||||||
loader->getDeckList()->loadFromString_Native(model->getDeckList()->writeToString_Native());
|
deckList.setName(response.getDeckName());
|
||||||
|
deckList.setGameFormat(
|
||||||
|
ArchidektFormats::formatToCockatriceName(ArchidektFormats::DeckFormat(response.getDeckFormat() - 1)));
|
||||||
|
|
||||||
loader->getDeckList()->setName(response.getDeckName());
|
LoadedDeck loadedDeck = {deckList, {}};
|
||||||
|
|
||||||
emit openInDeckEditor(loader);
|
emit openInDeckEditor(loadedDeck);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ArchidektApiResponseDeckDisplayWidget::clearAllDisplayWidgets()
|
void ArchidektApiResponseDeckDisplayWidget::clearAllDisplayWidgets()
|
||||||
|
|
@ -119,7 +123,7 @@ void ArchidektApiResponseDeckDisplayWidget::constructZoneWidgetsFromDeckListMode
|
||||||
QSortFilterProxyModel proxy;
|
QSortFilterProxyModel proxy;
|
||||||
proxy.setSourceModel(model);
|
proxy.setSourceModel(model);
|
||||||
proxy.setSortRole(Qt::EditRole);
|
proxy.setSortRole(Qt::EditRole);
|
||||||
proxy.sort(1, Qt::AscendingOrder);
|
proxy.sort(DeckListModelColumns::CARD_NAME, Qt::AscendingOrder);
|
||||||
|
|
||||||
for (int i = 0; i < proxy.rowCount(); ++i) {
|
for (int i = 0; i < proxy.rowCount(); ++i) {
|
||||||
QModelIndex proxyIndex = proxy.index(i, 0);
|
QModelIndex proxyIndex = proxy.index(i, 0);
|
||||||
|
|
@ -132,10 +136,12 @@ void ArchidektApiResponseDeckDisplayWidget::constructZoneWidgetsFromDeckListMode
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString zoneName =
|
||||||
|
persistent.sibling(persistent.row(), DeckListModelColumns::CARD_NAME).data(Qt::EditRole).toString();
|
||||||
|
|
||||||
DeckCardZoneDisplayWidget *zoneDisplayWidget =
|
DeckCardZoneDisplayWidget *zoneDisplayWidget =
|
||||||
new DeckCardZoneDisplayWidget(zoneContainer, model, nullptr, persistent,
|
new DeckCardZoneDisplayWidget(zoneContainer, model, nullptr, persistent, zoneName, "maintype", {"name"},
|
||||||
model->data(persistent.sibling(persistent.row(), 1), Qt::EditRole).toString(),
|
DisplayType::Overlap, 20, 10, cardSizeSlider);
|
||||||
"maintype", {"name"}, DisplayType::Overlap, 20, 10, cardSizeSlider);
|
|
||||||
|
|
||||||
connect(displayOptionsWidget, &VisualDeckDisplayOptionsWidget::sortCriteriaChanged, zoneDisplayWidget,
|
connect(displayOptionsWidget, &VisualDeckDisplayOptionsWidget::sortCriteriaChanged, zoneDisplayWidget,
|
||||||
&DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged);
|
&DeckCardZoneDisplayWidget::onActiveSortCriteriaChanged);
|
||||||
|
|
|
||||||
|
|
@ -31,7 +31,7 @@
|
||||||
*
|
*
|
||||||
* ### Signals
|
* ### Signals
|
||||||
* - `requestNavigation(QString url)` — triggered when navigation to a deck URL is requested.
|
* - `requestNavigation(QString url)` — triggered when navigation to a deck URL is requested.
|
||||||
* - `openInDeckEditor(DeckLoader *loader)` — emitted when the user chooses to open the deck
|
* - `openInDeckEditor(const LoadedDeck &deck)` — emitted when the user chooses to open the deck
|
||||||
* in the deck editor.
|
* in the deck editor.
|
||||||
*
|
*
|
||||||
* ### Features
|
* ### Features
|
||||||
|
|
@ -52,9 +52,9 @@ signals:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Emitted when the deck should be opened in the deck editor.
|
* @brief Emitted when the deck should be opened in the deck editor.
|
||||||
* @param loader Initialized DeckLoader containing the deck data.
|
* @param deck LoadedDeck containing the deck data.
|
||||||
*/
|
*/
|
||||||
void openInDeckEditor(DeckLoader *loader);
|
void openInDeckEditor(const LoadedDeck &deck);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
|
|
@ -75,7 +75,7 @@ public:
|
||||||
void retranslateUi();
|
void retranslateUi();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Opens the deck in the deck editor via DeckLoader.
|
* @brief Opens the deck in the deck editor.
|
||||||
*/
|
*/
|
||||||
void actOpenInDeckEditor();
|
void actOpenInDeckEditor();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
#define ARCHIDEKT_DEFAULT_IMAGE "https://storage.googleapis.com/topdekt-user/images/archidekt_deck_card_shadow.jpg"
|
#define ARCHIDEKT_DEFAULT_IMAGE "https://storage.googleapis.com/topdekt-user/images/archidekt_deck_card_shadow.jpg"
|
||||||
|
|
||||||
QString timeAgo(const QString ×tamp)
|
static QString timeAgo(const QString ×tamp)
|
||||||
{
|
{
|
||||||
QDateTime dt = QDateTime::fromString(timestamp, Qt::ISODate);
|
QDateTime dt = QDateTime::fromString(timestamp, Qt::ISODate);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -16,10 +16,7 @@ ArchidektApiResponseDeckListingsDisplayWidget::ArchidektApiResponseDeckListingsD
|
||||||
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
flowWidget = new FlowWidget(this, Qt::Horizontal, Qt::ScrollBarAlwaysOff, Qt::ScrollBarAsNeeded);
|
||||||
|
|
||||||
imageNetworkManager = new QNetworkAccessManager(this);
|
imageNetworkManager = new QNetworkAccessManager(this);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
|
||||||
imageNetworkManager->setTransferTimeout(); // Use Qt's default timeout
|
imageNetworkManager->setTransferTimeout(); // Use Qt's default timeout
|
||||||
#endif
|
|
||||||
|
|
||||||
imageNetworkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
|
imageNetworkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
|
||||||
|
|
||||||
// Add widgets for deck listings
|
// Add widgets for deck listings
|
||||||
|
|
|
||||||
|
|
@ -27,10 +27,7 @@
|
||||||
TabArchidekt::TabArchidekt(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
|
TabArchidekt::TabArchidekt(TabSupervisor *_tabSupervisor) : Tab(_tabSupervisor)
|
||||||
{
|
{
|
||||||
networkManager = new QNetworkAccessManager(this);
|
networkManager = new QNetworkAccessManager(this);
|
||||||
#if (QT_VERSION >= QT_VERSION_CHECK(5, 15, 0))
|
|
||||||
networkManager->setTransferTimeout(); // Use Qt's default timeout
|
networkManager->setTransferTimeout(); // Use Qt's default timeout
|
||||||
#endif
|
|
||||||
|
|
||||||
networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
|
networkManager->setRedirectPolicy(QNetworkRequest::ManualRedirectPolicy);
|
||||||
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(processApiJson(QNetworkReply *)));
|
connect(networkManager, SIGNAL(finished(QNetworkReply *)), this, SLOT(processApiJson(QNetworkReply *)));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,8 @@ void EdhrecDeckApiResponse::fromJson(const QJsonArray &json)
|
||||||
deckList += cardlistValue.toString() + "\n";
|
deckList += cardlistValue.toString() + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
deckLoader = new DeckLoader(nullptr);
|
|
||||||
|
|
||||||
QTextStream stream(&deckList);
|
QTextStream stream(&deckList);
|
||||||
deckLoader->getDeckList()->loadFromStream_Plain(stream, true);
|
deck.loadFromStream_Plain(stream, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void EdhrecDeckApiResponse::debugPrint() const
|
void EdhrecDeckApiResponse::debugPrint() const
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ public:
|
||||||
// Debug method for logging
|
// Debug method for logging
|
||||||
void debugPrint() const;
|
void debugPrint() const;
|
||||||
|
|
||||||
DeckLoader *deckLoader;
|
DeckList deck;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // EDHREC_DECK_API_RESPONSE_H
|
#endif // EDHREC_DECK_API_RESPONSE_H
|
||||||
|
|
|
||||||
|
|
@ -19,17 +19,17 @@ EdhrecApiResponseCardDetailsDisplayWidget::EdhrecApiResponseCardDetailsDisplayWi
|
||||||
nameLabel = new QLabel(this);
|
nameLabel = new QLabel(this);
|
||||||
nameLabel->setText(toDisplay.name);
|
nameLabel->setText(toDisplay.name);
|
||||||
nameLabel->setAlignment(Qt::AlignHCenter);
|
nameLabel->setAlignment(Qt::AlignHCenter);
|
||||||
|
nameLabel->setStyleSheet("font-size: 20px; font-weight: bold");
|
||||||
|
|
||||||
inclusionDisplayWidget = new EdhrecApiResponseCardInclusionDisplayWidget(this, toDisplay);
|
inclusionDisplayWidget = new EdhrecApiResponseCardInclusionDisplayWidget(this, toDisplay);
|
||||||
|
|
||||||
synergyDisplayWidget = new EdhrecApiResponseCardSynergyDisplayWidget(this, toDisplay);
|
synergyDisplayWidget = new EdhrecApiResponseCardSynergyDisplayWidget(this, toDisplay);
|
||||||
|
|
||||||
layout->addWidget(nameLabel);
|
|
||||||
layout->addWidget(cardPictureWidget);
|
|
||||||
|
|
||||||
backgroundPlateWidget = new BackgroundPlateWidget(this);
|
backgroundPlateWidget = new BackgroundPlateWidget(this);
|
||||||
auto plateLayout = new QVBoxLayout(backgroundPlateWidget);
|
auto plateLayout = new QVBoxLayout(backgroundPlateWidget);
|
||||||
|
|
||||||
|
plateLayout->addWidget(nameLabel);
|
||||||
|
plateLayout->addWidget(cardPictureWidget);
|
||||||
plateLayout->addWidget(inclusionDisplayWidget);
|
plateLayout->addWidget(inclusionDisplayWidget);
|
||||||
plateLayout->addWidget(synergyDisplayWidget);
|
plateLayout->addWidget(synergyDisplayWidget);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@
|
||||||
#include "../../../../../cards/card_info_picture_widget.h"
|
#include "../../../../../cards/card_info_picture_widget.h"
|
||||||
#include "../../tab_edhrec_main.h"
|
#include "../../tab_edhrec_main.h"
|
||||||
#include "../card_prices/edhrec_api_response_card_prices_display_widget.h"
|
#include "../card_prices/edhrec_api_response_card_prices_display_widget.h"
|
||||||
|
#include "edhrec_commander_api_response_bracket_navigation_widget.h"
|
||||||
|
|
||||||
#include <libcockatrice/card/database/card_database_manager.h>
|
#include <libcockatrice/card/database/card_database_manager.h>
|
||||||
|
|
||||||
|
|
@ -12,9 +13,14 @@ EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCom
|
||||||
QString baseUrl)
|
QString baseUrl)
|
||||||
: QWidget(parent), commanderDetails(_commanderDetails)
|
: QWidget(parent), commanderDetails(_commanderDetails)
|
||||||
{
|
{
|
||||||
layout = new QVBoxLayout(this);
|
layout = new QHBoxLayout(this);
|
||||||
setLayout(layout);
|
setLayout(layout);
|
||||||
|
|
||||||
|
commanderLayout = new QHBoxLayout();
|
||||||
|
commanderDetailsLayout = new QVBoxLayout();
|
||||||
|
commanderDetailsLayout->setAlignment(Qt::AlignCenter);
|
||||||
|
navigationAndPricesLayout = new QVBoxLayout();
|
||||||
|
|
||||||
commanderPicture = new CardInfoPictureWidget(this);
|
commanderPicture = new CardInfoPictureWidget(this);
|
||||||
commanderPicture->setCard(CardDatabaseManager::query()->getCard({commanderDetails.getName()}));
|
commanderPicture->setCard(CardDatabaseManager::query()->getCard({commanderDetails.getName()}));
|
||||||
|
|
||||||
|
|
@ -36,20 +42,35 @@ EdhrecCommanderResponseCommanderDetailsDisplayWidget::EdhrecCommanderResponseCom
|
||||||
|
|
||||||
commanderDetails.debugPrint();
|
commanderDetails.debugPrint();
|
||||||
|
|
||||||
|
commanderName = new QLabel(this);
|
||||||
|
commanderName->setText(commanderDetails.getName());
|
||||||
|
commanderName->setAlignment(Qt::AlignCenter);
|
||||||
|
commanderName->setStyleSheet("font-size: 28px; font-weight: bold");
|
||||||
|
|
||||||
label = new QLabel(this);
|
label = new QLabel(this);
|
||||||
label->setAlignment(Qt::AlignCenter);
|
label->setAlignment(Qt::AlignCenter);
|
||||||
|
label->setStyleSheet("font-size: 16px");
|
||||||
|
|
||||||
salt = new QLabel(this);
|
salt = new QLabel(this);
|
||||||
salt->setAlignment(Qt::AlignCenter);
|
salt->setAlignment(Qt::AlignCenter);
|
||||||
|
salt->setStyleSheet("font-size: 16px");
|
||||||
|
|
||||||
cardPricesDisplayWidget = new EdhrecApiResponseCardPricesDisplayWidget(this, commanderDetails.getPrices());
|
cardPricesDisplayWidget = new EdhrecApiResponseCardPricesDisplayWidget(this, commanderDetails.getPrices());
|
||||||
|
|
||||||
navigationWidget = new EdhrecCommanderApiResponseNavigationWidget(this, commanderDetails, baseUrl);
|
navigationWidget = new EdhrecCommanderApiResponseNavigationWidget(this, commanderDetails, baseUrl);
|
||||||
|
|
||||||
layout->addWidget(commanderPicture);
|
commanderLayout->addWidget(commanderPicture);
|
||||||
layout->addWidget(label);
|
commanderDetailsLayout->addWidget(commanderName);
|
||||||
layout->addWidget(salt);
|
commanderDetailsLayout->addSpacing(1);
|
||||||
layout->addWidget(cardPricesDisplayWidget);
|
commanderDetailsLayout->addWidget(label);
|
||||||
layout->addWidget(navigationWidget);
|
commanderDetailsLayout->addWidget(salt);
|
||||||
|
commanderDetailsLayout->addWidget(cardPricesDisplayWidget);
|
||||||
|
commanderLayout->addLayout(commanderDetailsLayout);
|
||||||
|
navigationAndPricesLayout->addWidget(navigationWidget);
|
||||||
|
// navigationAndPricesLayout->addWidget(cardPricesDisplayWidget);
|
||||||
|
|
||||||
|
layout->addLayout(commanderLayout);
|
||||||
|
layout->addLayout(navigationAndPricesLayout);
|
||||||
|
|
||||||
retranslateUi();
|
retranslateUi();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,8 +29,12 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
EdhrecCommanderApiResponseCommanderDetails commanderDetails;
|
EdhrecCommanderApiResponseCommanderDetails commanderDetails;
|
||||||
QVBoxLayout *layout;
|
QHBoxLayout *layout;
|
||||||
|
QHBoxLayout *commanderLayout;
|
||||||
|
QVBoxLayout *commanderDetailsLayout;
|
||||||
|
QVBoxLayout *navigationAndPricesLayout;
|
||||||
CardInfoPictureWidget *commanderPicture;
|
CardInfoPictureWidget *commanderPicture;
|
||||||
|
QLabel *commanderName;
|
||||||
QLabel *label;
|
QLabel *label;
|
||||||
QLabel *salt;
|
QLabel *salt;
|
||||||
EdhrecApiResponseCardPricesDisplayWidget *cardPricesDisplayWidget;
|
EdhrecApiResponseCardPricesDisplayWidget *cardPricesDisplayWidget;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,95 @@
|
||||||
|
#include "edhrec_commander_api_response_bracket_navigation_widget.h"
|
||||||
|
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
|
EdhrecCommanderApiResponseBracketNavigationWidget::EdhrecCommanderApiResponseBracketNavigationWidget(
|
||||||
|
QWidget *parent,
|
||||||
|
const QString &baseUrl)
|
||||||
|
: QWidget(parent)
|
||||||
|
{
|
||||||
|
layout = new QGridLayout(this);
|
||||||
|
setLayout(layout);
|
||||||
|
|
||||||
|
gameChangerLabel = new QLabel(this);
|
||||||
|
|
||||||
|
layout->addWidget(gameChangerLabel, 1, 0, 1, 2);
|
||||||
|
|
||||||
|
for (int i = 0; i < gameChangerOptions.length(); i++) {
|
||||||
|
QString option = gameChangerOptions.at(i);
|
||||||
|
QString label = option.isEmpty() ? "All" : option.at(0).toUpper() + option.mid(1);
|
||||||
|
QPushButton *optionButton = new QPushButton(label, this);
|
||||||
|
optionButton->setMinimumHeight(84);
|
||||||
|
optionButton->setStyleSheet("font-size: 24px");
|
||||||
|
gameChangerButtons[option] = optionButton;
|
||||||
|
layout->addWidget(optionButton, 2, i);
|
||||||
|
connect(optionButton, &QPushButton::clicked, this, [=, this]() {
|
||||||
|
selectedGameChanger = option;
|
||||||
|
updateOptionButtonSelection(gameChangerButtons, option);
|
||||||
|
emit requestNavigation();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
updateOptionButtonSelection(gameChangerButtons, "");
|
||||||
|
|
||||||
|
retranslateUi();
|
||||||
|
applyOptionsFromUrl(baseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdhrecCommanderApiResponseBracketNavigationWidget::retranslateUi()
|
||||||
|
{
|
||||||
|
gameChangerLabel->setText(tr("Game Changers"));
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdhrecCommanderApiResponseBracketNavigationWidget::applyOptionsFromUrl(const QString &url)
|
||||||
|
{
|
||||||
|
QString cleanedUrl = url;
|
||||||
|
|
||||||
|
// Remove base and file extension
|
||||||
|
if (cleanedUrl.startsWith("https://json.edhrec.com/pages/")) {
|
||||||
|
cleanedUrl = cleanedUrl.mid(QString("https://json.edhrec.com/pages/").length());
|
||||||
|
}
|
||||||
|
if (cleanedUrl.endsWith(".json")) {
|
||||||
|
cleanedUrl.chop(5);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expecting something like: "commanders/the-ur-dragon/core/expensive"
|
||||||
|
QStringList parts = cleanedUrl.split('/', Qt::SkipEmptyParts);
|
||||||
|
|
||||||
|
if (parts.size() < 2) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
QString commanderName = parts[1];
|
||||||
|
QString gameChangerOpt;
|
||||||
|
|
||||||
|
// Define valid sets
|
||||||
|
QSet<QString> validGameChangers = {"exhibition", "core", "upgraded", "optimized", "cedh"};
|
||||||
|
|
||||||
|
// Check remaining parts after commander
|
||||||
|
for (int i = 2; i < parts.size(); ++i) {
|
||||||
|
QString part = parts[i].toLower();
|
||||||
|
if (validGameChangers.contains(part)) {
|
||||||
|
gameChangerOpt = part;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate and apply
|
||||||
|
if (!gameChangerButtons.contains(gameChangerOpt)) {
|
||||||
|
gameChangerOpt.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedGameChanger = gameChangerOpt;
|
||||||
|
|
||||||
|
updateOptionButtonSelection(gameChangerButtons, selectedGameChanger);
|
||||||
|
}
|
||||||
|
|
||||||
|
void EdhrecCommanderApiResponseBracketNavigationWidget::updateOptionButtonSelection(
|
||||||
|
QMap<QString, QPushButton *> &buttons,
|
||||||
|
const QString &selectedKey)
|
||||||
|
{
|
||||||
|
for (auto it = buttons.begin(); it != buttons.end(); ++it) {
|
||||||
|
it.value()->setStyleSheet(it.key() == selectedKey
|
||||||
|
? "background-color: lightblue; font-weight: bold; font-size: 24px;"
|
||||||
|
: "font-size: 24px");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,37 @@
|
||||||
|
#ifndef COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H
|
||||||
|
#define COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H
|
||||||
|
|
||||||
|
#include <QGridLayout>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMap>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QWidget>
|
||||||
|
|
||||||
|
class EdhrecCommanderApiResponseBracketNavigationWidget : public QWidget
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
explicit EdhrecCommanderApiResponseBracketNavigationWidget(QWidget *parent, const QString &baseUrl);
|
||||||
|
void retranslateUi();
|
||||||
|
void applyOptionsFromUrl(const QString &url);
|
||||||
|
QString getSelectedGameChanger() const
|
||||||
|
{
|
||||||
|
return selectedGameChanger;
|
||||||
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void requestNavigation();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QGridLayout *layout;
|
||||||
|
QLabel *gameChangerLabel;
|
||||||
|
|
||||||
|
QStringList gameChangerOptions = {"", "exhibition", "core", "upgraded", "optimized", "cedh"};
|
||||||
|
QString selectedGameChanger;
|
||||||
|
|
||||||
|
QMap<QString, QPushButton *> gameChangerButtons;
|
||||||
|
|
||||||
|
void updateOptionButtonSelection(QMap<QString, QPushButton *> &buttons, const QString &selectedKey);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // COCKATRICE_EDHREC_COMMANDER_API_RESPONSE_BRACKET_NAVIGATION_WIDGET_H
|
||||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue