├── .github
├── ISSUE_TEMPLATE
│ └── bug_report.md
├── [QC]_screenshot-qc.txt
├── dependabot.yml
└── workflows
│ └── release.yml
├── .gitignore
├── .pre-commit-config.yaml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.MD
├── Justfile
├── LICENSE
├── README.MD
├── build-aux
├── build.sh
├── generate-lupdate-project-file.py
├── generate-qt-creator-project-file.py
├── icon.ico
└── insert-dependency-versions.py
├── data
├── config
│ ├── backup-template.jinja
│ ├── export-template.jinja
│ ├── input.conf
│ ├── mpv-linux.conf
│ └── mpv-windows.conf
├── fonts
│ ├── NotoSans-Bold.ttf
│ ├── NotoSans-Italic.ttf
│ ├── NotoSans-Regular.ttf
│ ├── NotoSans-SemiBold.ttf
│ ├── NotoSansHebrew-Bold.ttf
│ ├── NotoSansHebrew-Regular.ttf
│ ├── NotoSansHebrew-SemiBold.ttf
│ └── NotoSansMono-Regular.ttf
├── icon.svg
├── icons
│ ├── aspect_ratio_black_24dp.svg
│ ├── close_black_24dp.svg
│ ├── close_fullscreen_black_24dp.svg
│ ├── comment_black_24dp.svg
│ ├── content_copy_black_24dp.svg
│ ├── delete_black_24dp.svg
│ ├── done_black_24dp.svg
│ ├── download_black_24dp.svg
│ ├── edit_black_24dp.svg
│ ├── exit_to_app_black_24dp.svg
│ ├── expand_more_black_24dp.svg
│ ├── file_open_black_24dp.svg
│ ├── horizontal_split_black_24dp.svg
│ ├── info_black_24dp.svg
│ ├── inventory_black_24dp.svg
│ ├── keyboard_arrow_down_black_24dp.svg
│ ├── keyboard_arrow_left_black_24dp.svg
│ ├── keyboard_arrow_right_black_24dp.svg
│ ├── keyboard_arrow_up_black_24dp.svg
│ ├── keyboard_backspace_black_24dp.svg
│ ├── keyboard_black_24dp.svg
│ ├── keyboard_return_black_24dp.svg
│ ├── language_black_24dp.svg
│ ├── launch_black_24dp.svg
│ ├── minimize_black_24dp.svg
│ ├── more_vert_black_24dp.svg
│ ├── movie_black_24dp.svg
│ ├── movie_edit_black_24dp.svg
│ ├── notes_black_24dp.svg
│ ├── open_in_full_black_24dp.svg
│ ├── palette_black_24dp.svg
│ ├── play_arrow_black_24dp.svg
│ ├── save_alt_black_24dp.svg
│ ├── save_as_black_24dp.svg
│ ├── save_black_24dp.svg
│ ├── settings_backup_restore_black_24dp.svg
│ ├── shortcut_black_24dp.svg
│ ├── space_bar_black_24dp.svg
│ ├── subtitles_black_24dp.svg
│ ├── title_black_24dp.svg
│ ├── update_black_24dp.svg
│ ├── upload_black_24dp.svg
│ └── vertical_split_black_24dp.svg
└── themes
│ ├── 01-dark.toml
│ ├── 02-light.toml
│ ├── Justfile
│ ├── color-generator.py
│ └── theme.template
├── docs
├── configuration.md
├── internationalization.md
└── releasing.md
├── i18n
├── de-DE.ts
├── es-MX.ts
├── he-IL.ts
└── it-IT.ts
├── main.py
├── mpvqc
├── __init__.py
├── application.py
├── injections.py
├── logging.py
├── models.py
├── pyobjects
│ ├── __init__.py
│ ├── application_paths.py
│ ├── comment_model
│ │ ├── __init__.py
│ │ ├── item.py
│ │ ├── model.py
│ │ ├── roles.py
│ │ ├── searcher.py
│ │ ├── undo.py
│ │ └── utils.py
│ ├── comment_type_validator.py
│ ├── export_template_model.py
│ ├── extended_document_exporter.py
│ ├── manager
│ │ ├── __init__.py
│ │ ├── impl.py
│ │ └── state.py
│ ├── player.py
│ ├── player_files.py
│ ├── player_framebuffer_object.py
│ ├── player_properties.py
│ ├── player_win_id.py
│ ├── text_validator.py
│ ├── themes.py
│ ├── utility.py
│ └── version_checker.py
├── services
│ ├── __init__.py
│ ├── application_environment.py
│ ├── application_paths.py
│ ├── comment_type_validator.py
│ ├── document_exporter.py
│ ├── document_importer.py
│ ├── file_startup.py
│ ├── font_loader.py
│ ├── formatter_time.py
│ ├── frameless
│ │ ├── __init__.py
│ │ ├── linux
│ │ │ ├── __init__.py
│ │ │ └── event.py
│ │ ├── service.py
│ │ └── win
│ │ │ ├── __init__.py
│ │ │ ├── c_structures.py
│ │ │ ├── event.py
│ │ │ └── utils.py
│ ├── key_command.py
│ ├── mimetype_provider.py
│ ├── operating_system_zoom_detector.py
│ ├── player.py
│ ├── resource.py
│ ├── resource_reader.py
│ ├── reverse_translator.py
│ ├── settings.py
│ ├── theme
│ │ ├── __init__.py
│ │ ├── parser.py
│ │ ├── schema.py
│ │ ├── service.py
│ │ └── utils.py
│ ├── type_mapper.py
│ ├── version_checker.py
│ └── video_selector.py
└── startup.py
├── pyproject.toml
├── qml
├── Main.qml
├── app
│ ├── MpvqcApplication.qml
│ ├── MpvqcContent.qml
│ ├── MpvqcContentSplitView.qml
│ ├── MpvqcDragAndDropHandler.qml
│ ├── MpvqcLabelWidthCalculator.qml
│ ├── MpvqcManager.qml
│ ├── MpvqcQuitHandler.qml
│ ├── MpvqcResizeToOriginalResolutionHandler.qml
│ ├── MpvqcTheme.qml
│ ├── MpvqcWindowVisibilityHandler.qml
│ ├── qmldir
│ ├── tst_MpvqcDragAndDropHandler.qml
│ ├── tst_MpvqcLabelWidthCalculator.qml
│ ├── tst_MpvqcQuitHandler.qml
│ ├── tst_MpvqcResizeToOriginalResolutionHandler.qml
│ └── tst_MpvqcWindowVisibilityHandler.qml
├── dialogs
│ ├── MpvqcDialogExportDocument.qml
│ ├── MpvqcDialogImportDocuments.qml
│ ├── MpvqcDialogImportSubtitles.qml
│ ├── MpvqcDialogImportVideo.qml
│ ├── MpvqcMessageBoxDocumentNotCompatible.qml
│ ├── MpvqcMessageBoxExtendedExport.qml
│ ├── MpvqcMessageBoxNewDocument.qml
│ ├── MpvqcMessageBoxQuit.qml
│ ├── MpvqcMessageBoxVersionCheck.qml
│ ├── MpvqcMessageBoxVideoFound.qml
│ ├── about
│ │ ├── MpvqcAboutView.qml
│ │ ├── MpvqcCreditsView.qml
│ │ ├── MpvqcDependenciesView.qml
│ │ ├── MpvqcDependency.qml
│ │ └── MpvqcDialogAbout.qml
│ ├── appearance
│ │ ├── MpvqcColorView.qml
│ │ ├── MpvqcDialogAppearance.qml
│ │ ├── MpvqcThemeView.qml
│ │ ├── tst_MpvqcColorView.qml
│ │ └── tst_MpvqcThemeView.qml
│ ├── backup
│ │ ├── MpvqcBackupView.qml
│ │ ├── MpvqcDialogBackup.qml
│ │ └── tst_MpvqcBackupView.qml
│ ├── commenttypes
│ │ ├── MpvqcCommentTypesView.qml
│ │ ├── MpvqcCommentTypesViewController.qml
│ │ ├── MpvqcDialogCommentTypes.qml
│ │ ├── MpvqcInputComponent.qml
│ │ ├── MpvqcInputControls.qml
│ │ ├── MpvqcInputTextField.qml
│ │ ├── MpvqcList.qml
│ │ ├── MpvqcListControls.qml
│ │ ├── tst_MpvqcCommentTypesViewController.qml
│ │ ├── tst_MpvqcInputComponent.qml
│ │ ├── tst_MpvqcInputControls.qml
│ │ ├── tst_MpvqcInputTextField.qml
│ │ ├── tst_MpvqcList.qml
│ │ └── tst_MpvqcListControls.qml
│ ├── editinput
│ │ ├── MpvqcDialogEditInput.qml
│ │ ├── MpvqcEditInputView.qml
│ │ └── tst_MpvqcDialogEditInput.qml
│ ├── editmpv
│ │ ├── MpvqcDialogEditMpv.qml
│ │ ├── MpvqcEditMpvView.qml
│ │ └── tst_MpvqcDialogEditMpv.qml
│ ├── export
│ │ ├── MpvqcDialogExport.qml
│ │ ├── MpvqcExportView.qml
│ │ └── tst_MpvqcExportView.qml
│ ├── import
│ │ ├── MpvqcDialogImport.qml
│ │ ├── MpvqcImportView.qml
│ │ └── tst_MpvqcImportView.qml
│ ├── qmldir
│ ├── shortcuts
│ │ ├── MpvqcDialogShortcuts.qml
│ │ ├── MpvqcShortcut.qml
│ │ ├── MpvqcShortcutButton.qml
│ │ ├── MpvqcShortcutFilterModel.qml
│ │ ├── MpvqcShortcutModel.qml
│ │ └── MpvqcShortcutView.qml
│ ├── tst_MpvqcDialogExportDocument.qml
│ ├── tst_MpvqcDialogImportDocuments.qml
│ ├── tst_MpvqcDialogImportSubtitles.qml
│ └── tst_MpvqcDialogImportVideo.qml
├── footer
│ ├── MpvqcFooter.qml
│ ├── MpvqcFooterContent.qml
│ ├── qmldir
│ └── tst_MpvqcFooter.qml
├── header
│ ├── MpvqcHeader.qml
│ ├── MpvqcMenuFile.qml
│ ├── MpvqcMenuHelp.qml
│ ├── MpvqcMenuOptions.qml
│ ├── MpvqcMenuVideo.qml
│ ├── MpvqcSubMenuExtendedExport.qml
│ ├── MpvqcSubMenuLanguage.qml
│ ├── MpvqcSubMenuSplitViewOrientation.qml
│ ├── MpvqcSubMenuWindowTitle.qml
│ ├── MpvqcWindowControls.qml
│ ├── MpvqcWindowTitle.qml
│ ├── qmldir
│ ├── tst_MpvqcMenuFile.qml
│ ├── tst_MpvqcMenuHelp.qml
│ ├── tst_MpvqcMenuOptions.qml
│ ├── tst_MpvqcMenuVideo.qml
│ ├── tst_MpvqcSubMenuLanguage.qml
│ ├── tst_MpvqcSubMenuSplitViewOrientation.qml
│ ├── tst_MpvqcSubMenuWindowTitle.qml
│ ├── tst_MpvqcWindowControls.qml
│ └── tst_MpvqcWindowTitle.qml
├── models
│ ├── MpvqcArtworkModel.qml
│ ├── MpvqcDeveloperModel.qml
│ ├── MpvqcLanguageModel.qml
│ ├── MpvqcLibraryModel.qml
│ └── qmldir
├── player
│ ├── MpvqcPlayerLinux.qml
│ ├── MpvqcPlayerMouseArea.qml
│ ├── MpvqcPlayerWindows.qml
│ ├── qmldir
│ └── tst_MpvqcPlayerMouseArea.qml
├── settings
│ ├── MpvqcSettings.qml
│ └── qmldir
├── shared
│ ├── MpvqcDebugRectangle.qml
│ ├── MpvqcDialog.qml
│ ├── MpvqcHeader.qml
│ ├── MpvqcKeyboardFocusableButtonBox.qml
│ ├── MpvqcMenu.qml
│ ├── MpvqcMessageBox.qml
│ ├── MpvqcNewCommentMenu.qml
│ ├── MpvqcSpinBoxRow.qml
│ ├── MpvqcSwitchRow.qml
│ ├── MpvqcTextFieldRow.qml
│ ├── qmldir
│ ├── tst_MpvqcDialog.qml
│ ├── tst_MpvqcMenu.qml
│ ├── tst_MpvqcNewCommentMenu.qml
│ ├── tst_MpvqcSpinBoxRow.qml
│ ├── tst_MpvqcSwitchRow.qml
│ └── tst_MpvqcTextFieldRow.qml
└── table
│ ├── MpvqcCommentHighlighter.js
│ ├── MpvqcCommentList.qml
│ ├── MpvqcCommentListDelegate.qml
│ ├── MpvqcContextMenu.qml
│ ├── MpvqcDeleteCommentMessageBox.qml
│ ├── MpvqcEditCommentPopup.qml
│ ├── MpvqcEditCommentTypeMenu.qml
│ ├── MpvqcEditTimePopup.qml
│ ├── MpvqcPlaceholder.qml
│ ├── MpvqcSearchBox.qml
│ ├── MpvqcTable.qml
│ ├── qmldir
│ └── tst_MpvqcCommentList.qml
├── test
├── __init__.py
├── conftest.py
├── mocks.py
├── pyobjects
│ ├── __init__.py
│ ├── comment_model
│ │ ├── __init__.py
│ │ ├── conftest.py
│ │ ├── test_add.py
│ │ ├── test_clear.py
│ │ ├── test_clipboard.py
│ │ ├── test_get_all.py
│ │ ├── test_import.py
│ │ ├── test_remove.py
│ │ ├── test_search.py
│ │ ├── test_undo_redo.py
│ │ └── test_update.py
│ ├── manager
│ │ ├── __init__.py
│ │ ├── test_impl.py
│ │ └── test_state.py
│ └── test_export_templates_model.py
├── services
│ ├── __init__.py
│ ├── test_application_paths.py
│ ├── test_comment_type_validator.py
│ ├── test_document_exporter.py
│ ├── test_document_importer.py
│ ├── test_file_startup.py
│ ├── test_font_loader.py
│ ├── test_formatter_time.py
│ ├── test_key_command.py
│ ├── test_player.py
│ ├── test_resource.py
│ ├── test_resource_reader.py
│ ├── test_reverse_translator.py
│ ├── test_settings.py
│ ├── test_version_checker.py
│ ├── test_video_selector.py
│ └── theme
│ │ ├── __init__.py
│ │ ├── test_parser.py
│ │ ├── test_service.py
│ │ └── test_utils.py
└── test_application.py
└── uv.lock
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: bug
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 |
16 | 1. Go to '...'
17 | 2. Click on '...'
18 | 3. Scroll down to '...'
19 | 4. See error
20 |
21 | **Expected behavior**
22 | A clear and concise description of what you expected to happen.
23 |
24 | **Screenshots**
25 | If applicable, add screenshots to help explain your problem.
26 |
27 | **Data**
28 |
29 | - OS: \[e.g. Windows or Linux\]
30 | - Version and commit id\[e.g. 0.9.0-beta - 0b3138ac\] (see `Help` → `About mpvQC`)
31 |
32 | **mpv.conf**
33 |
34 | - If you have modified the mpv configuration (`Options` ⟶ `Edit mpv.conf...`), list all your changes or a copy of your config
35 |
36 | **Additional context**
37 | Add any other context about the problem here.
38 |
--------------------------------------------------------------------------------
/.github/[QC]_screenshot-qc.txt:
--------------------------------------------------------------------------------
1 | [FILE]
2 |
3 | [DATA]
4 | [00:00:21] [Timing] Title fades in too soon
5 | [00:00:27] [Typeset] Font could be bigger
6 | [00:00:51] [Note]
7 | [00:01:17] [Spelling] here!
8 | # total lines: 4
9 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | # Set update schedule for GitHub Actions
2 |
3 | version: 2
4 | updates:
5 |
6 | - package-ecosystem: "github-actions"
7 | directory: "/"
8 | schedule:
9 | # Check for updates to GitHub Actions every week
10 | interval: "weekly"
11 |
--------------------------------------------------------------------------------
/.pre-commit-config.yaml:
--------------------------------------------------------------------------------
1 | repos:
2 | - repo: https://github.com/pre-commit/pre-commit-hooks
3 | rev: v5.0.0
4 | hooks:
5 | - id: end-of-file-fixer
6 | - id: trailing-whitespace
7 | - repo: https://github.com/biomejs/pre-commit
8 | rev: v1.9.4
9 | hooks:
10 | - id: biome-check
11 | name: "format json"
12 | files: "\\.(jsonc?)$"
13 | args:
14 | - "--bracket-spacing=true"
15 | - "--indent-style=space"
16 | - "--indent-width=4"
17 | - "--line-ending=lf"
18 | - "--line-width=120"
19 | - repo: https://github.com/ComPWA/taplo-pre-commit
20 | rev: v0.9.3
21 | hooks:
22 | - id: taplo-format
23 | name: "format toml"
24 | args:
25 | - "--option"
26 | - "align_comments=true"
27 | - "--option"
28 | - "allowed_blank_lines=1"
29 | - "--option"
30 | - "array_auto_collapse=false"
31 | - "--option"
32 | - "indent_string= "
33 | - repo: https://github.com/google/yamlfmt
34 | rev: v0.16.0
35 | hooks:
36 | - id: yamlfmt
37 | name: "format yml"
38 | args:
39 | - "-formatter"
40 | - "line_ending=lf"
41 | - "-formatter"
42 | - "retain_line_breaks_single=true"
43 | - "-formatter"
44 | - "scan_folded_as_literal=true"
45 | - repo: https://github.com/hukkin/mdformat
46 | rev: 0.7.22
47 | hooks:
48 | - id: mdformat
49 | name: "format md"
50 | exclude: ".github/"
51 | args:
52 | - "--number"
53 | - "--wrap"
54 | - "keep"
55 | - "--end-of-line"
56 | - "lf"
57 | additional_dependencies:
58 | - mdformat-gfm
59 | - repo: https://github.com/astral-sh/ruff-pre-commit
60 | rev: v0.11.9
61 | hooks:
62 | - id: ruff
63 | name: "lint python"
64 | args:
65 | - "--fix"
66 | - id: ruff-format
67 | name: "format python"
68 |
--------------------------------------------------------------------------------
/CONTRIBUTING.MD:
--------------------------------------------------------------------------------
1 | # Contributing to mpvQC
2 |
3 | Thank you for taking the time to contribute! We appreciate any help in improving mpvQC, whether it’s fixing bugs or
4 | adding new features.
5 |
6 | ______________________________________________________________________
7 |
8 | ## Pull Request Guidelines
9 |
10 | 1. **Conventional Commits:**\
11 | We use [Conventional Commits](https://www.conventionalcommits.org/) to structure our commit messages. Examples:
12 |
13 | - `fix: correct minor typos in code`
14 | - `feat: add new pirmary colors`
15 |
16 | 2. **Descriptive PRs:**
17 |
18 | - Provide a clear title and description.
19 | - Link any relevant issues (e.g., “Fixes #42”).
20 | - Keep your changes focused and self-contained.
21 |
22 | 3. **Code Reviews:**
23 |
24 | - Be open to feedback and discussion.
25 | - Make any requested changes or clarifications promptly.
26 |
27 | ______________________________________________________________________
28 |
29 | ## Coding Standards
30 |
31 | - Run `just lint-python` to check for any lint issues.
32 | - Use `just format` to automatically format your code.
33 |
34 | ______________________________________________________________________
35 |
36 | ## Testing
37 |
38 | - If you add or modify functionality, please include or update tests when possible.
39 | - Ensure all existing tests pass before making a pull request.
40 |
41 | ______________________________________________________________________
42 |
43 | ## Issues and Bug Reports
44 |
45 | - **Search First:** Check if an issue already exists for your topic.
46 | - **Create a New Issue:** Clearly describe the bug or problem, including steps to reproduce it, and provide any relevant
47 | system information if applicable.
48 |
49 | ______________________________________________________________________
50 |
51 | ## Feature Requests
52 |
53 | - If you’d like to implement a new feature, **please open a new issue** (or join a relevant discussion if one exists)
54 | before you start coding. This way, we can coordinate and ensure your contribution aligns with project goals.
55 |
56 | ______________________________________________________________________
57 |
58 | ## License
59 |
60 | By contributing to mpvQC, you agree that your contributions will be licensed under the same license that governs this
61 | project. See [LICENSE](LICENSE) for details.
62 |
--------------------------------------------------------------------------------
/README.MD:
--------------------------------------------------------------------------------
1 | # mpvQC
2 |
3 |
4 |
5 | A simple libmpv-based application for creating video file quality control reports.\
6 | https://mpvqc.github.io
7 |
8 | ______________________________________________________________________
9 |
10 | ## Development Setup
11 |
12 | 1. **Install these tools**
13 |
14 | - [Python 3.13 or later](https://www.python.org/downloads/)
15 | - [uv](https://github.com/astral-sh/uv)
16 | - [just](https://github.com/casey/just)
17 | - **Windows users also need**
18 | - [Git Bash](https://git-scm.com/downloads)
19 | - Be sure to run `just` inside Git Bash
20 |
21 | 2. **Clone the repository**
22 |
23 | 3. **Open a terminal** where you cloned it
24 |
25 | 4. **Initialize the environment**:
26 |
27 | ```shell
28 | just init
29 | ```
30 |
31 | 5. **Add libmpv to your path**
32 |
33 | - **Linux**: Install `libmpv` through your package manager
34 | - **Windows**: Download [libmpv (mpv-dev-x86_64)](https://github.com/shinchiro/mpv-winbuild-cmake/releases), extract it, and place the `libmpv-*.dll` in the repository’s root folder
35 |
36 | 6. **Compile Resources:**
37 |
38 | ```shell
39 | just build-develop
40 | ```
41 |
42 | 7. **Start the application:**
43 |
44 | ```shell
45 | uv run main.py
46 | ```
47 |
48 | Whenever you change files in the `data`, `i18n`, or `qml` directories, run:
49 |
50 | ```shell
51 | just build-develop
52 | ```
53 |
54 | This compiles them into a Python file in the mpvqc folder, so the app recognizes them on startup.
55 |
56 | **Tip:** Configure your IDE to run the `build-develop` before launching the application.
57 |
58 | ## Internationalization
59 |
60 | If you want to translate this application into more languages, see the [internationalization guide](docs/internationalization.md).
61 | Feel free to open a new issue if you need further assistance.
62 |
--------------------------------------------------------------------------------
/build-aux/build.sh:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env bash
2 |
3 | # Execute from repository root
4 |
5 | source .venv/bin/activate
6 |
7 | just clean
8 | just build-develop
9 |
--------------------------------------------------------------------------------
/build-aux/icon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpvqc/mpvQC/de1083ea8a80220d792c0ffd35411d50516d8485/build-aux/icon.ico
--------------------------------------------------------------------------------
/data/config/backup-template.jinja:
--------------------------------------------------------------------------------
1 | [FILE]
2 | date : {{ date }}
3 | path : {{ video_path }}
4 |
5 | [DATA]
6 | {% for comment in comments -%}
7 | [{{ comment['time'] | as_time }}] [{{ comment['commentType'] | as_comment_type }}] {{ comment['comment'] | trim }}
8 | {% endfor -%}
9 | # total lines: {{ comments | count }}
10 |
--------------------------------------------------------------------------------
/data/config/export-template.jinja:
--------------------------------------------------------------------------------
1 | [FILE]
2 | {{ 'date : ' + date + '\n' if write_date else '' -}}
3 | {{ 'generator : ' + generator + '\n' if write_generator else '' -}}
4 | {{ 'nick : ' + nickname + '\n' if write_nickname else '' -}}
5 | {{ 'path : ' + video_path + '\n' if write_video_path else '' -}}
6 |
7 | {{ '\n' }}[DATA]
8 | {% for comment in comments -%}
9 | [{{ comment['time'] | as_time }}] [{{ comment['commentType'] | as_comment_type }}] {{ comment['comment'] | trim }}
10 | {% endfor -%}
11 | # total lines: {{ comments | count }}
12 |
--------------------------------------------------------------------------------
/data/config/input.conf:
--------------------------------------------------------------------------------
1 | ##################################################
2 | # The following keys can be bound to anything #
3 | # This is not a comprehensive list of all keys #
4 | # There are many more, like a, A, @, ö, é, î ... #
5 | # Please never bind 'quit' to any key! #
6 | ##################################################
7 |
8 | SPACE cycle pause
9 | LEFT no-osd seek -2 relative+exact
10 | RIGHT no-osd seek 2 relative+exact
11 | shift+LEFT osd-bar seek -5 relative+keyframes
12 | shift+RIGHT osd-bar seek 5 relative+keyframes
13 | ctrl+LEFT no-osd sub-seek -1
14 | ctrl+RIGHT no-osd sub-seek 1
15 |
16 | MOUSE_BTN0 cycle pause # Left click on mouse
17 | MOUSE_BTN3 add volume 2 # Mouse wheel up
18 | MOUSE_BTN4 add volume -2 # Mouse wheel down
19 | MOUSE_BTN5 add chapter -1 # Backward button on mouse
20 | MOUSE_BTN6 add chapter 1 # Forward button on mouse
21 |
22 | p cycle pause
23 | . frame-step
24 | , frame-back-step
25 | 9 add volume -2
26 | 0 add volume 2
27 | m cycle mute
28 | j cycle sub
29 | J cycle sub down
30 | SHARP cycle audio # SHARP assigns the # key
31 | l ab_loop
32 | s screenshot subtitles
33 | S screenshot window
34 |
35 | # This burns in subtitles (i.e. always render them at video resolution)
36 | # It cycles through the values "no" (Don't blend subtitles with the video)
37 | # "yes" (Blend at display resolution)
38 | # "video" (Blend at video resolution)
39 | b cycle blend-subtitles
40 |
41 | # This displays statistics of the currently played file
42 | i script-binding stats/display-stats-toggle
43 |
--------------------------------------------------------------------------------
/data/config/mpv-linux.conf:
--------------------------------------------------------------------------------
1 | #########
2 | # Video #
3 | #########
4 |
5 | # HQ preset, uses Spline36 for upscaling and Mitchell-Netravali for downscaling
6 | profile=gpu-hq
7 |
8 | # Configure offset to match a frame rate of 60 fps; default 0.050
9 | # More info: https://github.com/mpvqc/mpvQC/issues/26
10 | video-timing-offset=0.016
11 |
12 | # Debanding is disabled because we don't want to alter the video while doing quality control
13 | deband=no
14 |
15 | # Potentially higher quality video output. Might be too demanding for old or low end hardware
16 | #scale=ewa_lanczossharp
17 | #cscale=ewa_lanczossoft
18 | #dscale=lanczos
19 |
20 |
21 | #############
22 | # Subtitles #
23 | #############
24 |
25 | # This disables the removal of very small gaps between subtitle lines
26 | # This might be a nice feature, but it hides flaws in the script
27 | # We don't want that while doing quality control
28 | sub-fix-timing=no
29 |
30 | # This makes sure that the current subtitle line is loaded after seeking
31 | demuxer-mkv-subtitle-preroll=yes
32 |
33 |
34 | ###########
35 | # OSC/OSD #
36 | ###########
37 |
38 | # Very slim On Screen Controller that consists of only a seekbar
39 | # Change the value of osc-valign to set the vertical position (Values between -1 and 1 are allowed)
40 | script-opts=osc-minmousemove=0,osc-hidetimeout=200,osc-layout=slimbox,osc-valign=0.6
41 | osd-bar-align-y=0
42 |
43 | # Bigger On Screen Controller with many buttons
44 | #script-opts=osc-minmousemove=0,osc-hidetimeout=200,osc-layout=box,osc-valign=0.5
45 |
46 |
47 | ###############
48 | # Screenshots #
49 | ###############
50 |
51 | #screenshot-directory=
52 | screenshot-format=png
53 | screenshot-high-bit-depth=no
54 |
--------------------------------------------------------------------------------
/data/config/mpv-windows.conf:
--------------------------------------------------------------------------------
1 | #########
2 | # Video #
3 | #########
4 |
5 | # HQ preset, uses Spline36 for upscaling and Mitchell-Netravali for downscaling
6 | profile=gpu-hq
7 |
8 | # Default video output. Use vo=gpu-next for a more modern renderer
9 | vo=gpu
10 |
11 | # Debanding is disabled because we don't want to alter the video while doing quality control
12 | deband=no
13 |
14 | # Potentially higher quality video output. Might be too demanding for old or low end hardware
15 | #scale=ewa_lanczossharp
16 | #cscale=ewa_lanczossoft
17 | #dscale=lanczos
18 |
19 |
20 | #############
21 | # Subtitles #
22 | #############
23 |
24 | # This disables the removal of very small gaps between subtitle lines
25 | # This might be a nice feature, but it hides flaws in the script
26 | # We don't want that while doing quality control
27 | sub-fix-timing=no
28 |
29 | # This makes sure that the current subtitle line is loaded after seeking
30 | demuxer-mkv-subtitle-preroll=yes
31 |
32 |
33 | ###########
34 | # OSC/OSD #
35 | ###########
36 |
37 | # Very slim On Screen Controller that consists of only a seekbar
38 | # Change the value of osc-valign to set the vertical position (Values between -1 and 1 are allowed)
39 | script-opts=osc-minmousemove=0,osc-hidetimeout=200,osc-layout=slimbox,osc-valign=0.6
40 | osd-bar-align-y=0
41 |
42 | # Bigger On Screen Controller with many buttons
43 | #script-opts=osc-minmousemove=0,osc-hidetimeout=200,osc-layout=box,osc-valign=0.5
44 |
45 |
46 | ###############
47 | # Screenshots #
48 | ###############
49 |
50 | #screenshot-directory=
51 | screenshot-format=png
52 | screenshot-high-bit-depth=no
53 |
--------------------------------------------------------------------------------
/data/fonts/NotoSans-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpvqc/mpvQC/de1083ea8a80220d792c0ffd35411d50516d8485/data/fonts/NotoSans-Bold.ttf
--------------------------------------------------------------------------------
/data/fonts/NotoSans-Italic.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpvqc/mpvQC/de1083ea8a80220d792c0ffd35411d50516d8485/data/fonts/NotoSans-Italic.ttf
--------------------------------------------------------------------------------
/data/fonts/NotoSans-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpvqc/mpvQC/de1083ea8a80220d792c0ffd35411d50516d8485/data/fonts/NotoSans-Regular.ttf
--------------------------------------------------------------------------------
/data/fonts/NotoSans-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpvqc/mpvQC/de1083ea8a80220d792c0ffd35411d50516d8485/data/fonts/NotoSans-SemiBold.ttf
--------------------------------------------------------------------------------
/data/fonts/NotoSansHebrew-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpvqc/mpvQC/de1083ea8a80220d792c0ffd35411d50516d8485/data/fonts/NotoSansHebrew-Bold.ttf
--------------------------------------------------------------------------------
/data/fonts/NotoSansHebrew-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpvqc/mpvQC/de1083ea8a80220d792c0ffd35411d50516d8485/data/fonts/NotoSansHebrew-Regular.ttf
--------------------------------------------------------------------------------
/data/fonts/NotoSansHebrew-SemiBold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpvqc/mpvQC/de1083ea8a80220d792c0ffd35411d50516d8485/data/fonts/NotoSansHebrew-SemiBold.ttf
--------------------------------------------------------------------------------
/data/fonts/NotoSansMono-Regular.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mpvqc/mpvQC/de1083ea8a80220d792c0ffd35411d50516d8485/data/fonts/NotoSansMono-Regular.ttf
--------------------------------------------------------------------------------
/data/icons/aspect_ratio_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/close_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/close_fullscreen_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/comment_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/content_copy_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/delete_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/done_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/download_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/edit_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/exit_to_app_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/expand_more_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/file_open_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/horizontal_split_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/info_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/inventory_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/keyboard_arrow_down_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/keyboard_arrow_left_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/keyboard_arrow_right_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/keyboard_arrow_up_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/keyboard_backspace_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/keyboard_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/keyboard_return_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/language_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/launch_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/minimize_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/more_vert_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/movie_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/movie_edit_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/notes_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/open_in_full_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/palette_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/play_arrow_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/save_alt_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/save_as_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/save_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/settings_backup_restore_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/shortcut_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/space_bar_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/subtitles_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/title_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/update_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/upload_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/icons/vertical_split_black_24dp.svg:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/data/themes/theme.template:
--------------------------------------------------------------------------------
1 | # required
2 | # possible values: v1
3 | schema-version = "v1"
4 |
5 | # required
6 | theme-name = ""
7 |
8 | # required
9 | # possible values: dark, light
10 | theme-variant = ""
11 |
12 | # required, hex color (#xxx or #xxxxxx)
13 | # Something that represents this color scheme
14 | theme-preview = ""
15 |
16 |
17 |
18 | [[colors]]
19 |
20 | # required, hex color
21 | # default background color
22 | background = ""
23 |
24 | # required, hex color
25 | # default text color
26 | foreground = ""
27 |
28 | # required, hex color
29 | # default color for control elements like check boxes or radio buttons
30 | control = ""
31 |
32 | # required, hex color
33 | # row background color when highlighted
34 | row-highlight = ""
35 |
36 | # optional, hex color
37 | # default: foreground
38 | # text color if row is highlighted
39 | row-highlight-text = ""
40 |
41 | # optional, hex color
42 | # default: background
43 | # row background color when not highlighted
44 | row-base = ""
45 |
46 | # optional, hex color
47 | # default: foreground
48 | # row text color when not highlighted
49 | row-base-text = ""
50 |
51 | # optional, hex color
52 | # default:
53 | # - if variant is light: 'row-base' color but 10% darker
54 | # - if variant is dark, 'row-base' color but 30% lighter
55 | # alternative row background color when not highlighted
56 | row-base-alternate = ""
57 |
58 | # optional, hex color
59 | # default: foreground
60 | # alternative row text color when not highlighted
61 | row-base-alternate-text = ""
62 |
--------------------------------------------------------------------------------
/docs/configuration.md:
--------------------------------------------------------------------------------
1 | # Configuring mpvQC
2 |
3 | mpvQC can be configured using the following environment variables:
4 |
5 | | **Name** | **Default Value** | **Operating System** | **Description** |
6 | | ---------------------------- | ----------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
7 | | `MPVQC_DEBUG` | _No default_ | All | Enables debug mode, intended primarily for developers and testing. |
8 | | `MPVQC_VIDEO_SCALING_FACTOR` | `1.0` | Linux | Specifies the desktop scaling factor. Because Linux does not provide a universal method to retrieve fractional scaling from the desktop environment, Linux users must set it manually. |
9 |
--------------------------------------------------------------------------------
/docs/internationalization.md:
--------------------------------------------------------------------------------
1 | # Adding Languages
2 |
3 | - Checkout repository
4 | - Make sure development environment is set up correctly for your OS
5 | - Create a new translation file by running
6 | ```shell
7 | just add-translation # just add-translation fr_FR
8 | ```
9 | - New `.ts` file appears in the `i18n` directory
10 | - Translate the `ts` file using Qt Linguist 6:
11 | ```shell
12 | pyside6-linguist i18n/.ts # pyside6-linguist i18n/fr_FR.ts
13 | ```
14 | - To test the translation:
15 | - Make the application portable
16 | ```shell
17 | touch portable
18 | ```
19 | - Run
20 | ```shell
21 | just build-develop
22 | ```
23 | - Start the application and close it
24 | - Edit the `appdata/settings.ini`
25 | ```ini
26 | [Common]
27 | language=
28 | ```
29 | - Start the application
30 | - Add a new entry in the `qml/models/MpvqcLanguageModel.qml` file
31 | - Open a new pull request
32 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | #
3 | # mpvQC
4 | #
5 | # Copyright (C) 2024 mpvQC developers
6 | #
7 | # This program is free software: you can redistribute it and/or modify
8 | # it under the terms of the GNU General Public License as published by
9 | # the Free Software Foundation, either version 3 of the License, or
10 | # (at your option) any later version.
11 | #
12 | # This program is distributed in the hope that it will be useful,
13 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
14 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 | # GNU General Public License for more details.
16 | #
17 | # You should have received a copy of the GNU General Public License
18 | # along with this program. If not, see .
19 |
20 |
21 | def main():
22 | import platform
23 |
24 | if platform.system() == "Windows":
25 | _add_directory_to_path()
26 |
27 | from mpvqc.startup import perform_startup
28 |
29 | perform_startup()
30 |
31 |
32 | def _add_directory_to_path():
33 | import os
34 | import sys
35 |
36 | os.environ["PATH"] = os.path.dirname(sys.argv[0]) + os.pathsep + os.environ["PATH"] # noqa: PTH120
37 | os.environ["PATH"] = os.path.dirname(__file__) + os.pathsep + os.environ["PATH"] # noqa: PTH120
38 |
39 |
40 | if __name__ == "__main__":
41 | main()
42 |
--------------------------------------------------------------------------------
/mpvqc/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
--------------------------------------------------------------------------------
/mpvqc/logging.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from collections.abc import Callable
19 |
20 |
21 | def qt_log_handler() -> Callable:
22 | from PySide6.QtCore import QtMsgType
23 |
24 | levels = {
25 | QtMsgType.QtInfoMsg: "INFO",
26 | QtMsgType.QtWarningMsg: "WARNING",
27 | QtMsgType.QtCriticalMsg: "CRITICAL",
28 | QtMsgType.QtFatalMsg: "FATAL",
29 | QtMsgType.QtDebugMsg: "DEBUG",
30 | }
31 |
32 | def handler(message_type: QtMsgType, _, message):
33 | level = levels.get(message_type)
34 | print(f"{level} {message}")
35 |
36 | return handler
37 |
--------------------------------------------------------------------------------
/mpvqc/models.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from dataclasses import dataclass
19 |
20 |
21 | @dataclass
22 | class Comment:
23 | time: int
24 | comment_type: str
25 | comment: str
26 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | # ruff: noqa: F401
19 | from .application_paths import MpvqcApplicationPathsPyObject
20 | from .comment_model import MpvqcCommentModelPyObject
21 | from .comment_type_validator import MpvqcCommentTypeValidatorPyObject
22 | from .export_template_model import MpvqcExportTemplateModelPyObject
23 | from .extended_document_exporter import MpvqcExtendedDocumentExporterPyObject
24 | from .manager import MpvqcManagerPyObject
25 | from .player import MpvqcMpvPlayerPyObject
26 | from .player_files import MpvqcPlayerFilesPyObject
27 | from .player_framebuffer_object import MpvqcMpvFrameBufferObjectPyObject
28 | from .player_properties import MpvqcMpvPlayerPropertiesPyObject
29 | from .player_win_id import MpvWindowPyObject
30 | from .text_validator import MpvqcDefaultTextValidatorPyObject
31 | from .themes import MpvqcThemesPyObject
32 | from .utility import MpvqcUtilityPyObject
33 | from .version_checker import MpvqcVersionCheckerPyObject
34 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/application_paths.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import inject
19 | from PySide6.QtCore import Property, QObject, QUrl
20 | from PySide6.QtQml import QmlElement
21 |
22 | from mpvqc.services import ApplicationPathsService, TypeMapperService
23 |
24 | QML_IMPORT_NAME = "pyobjects"
25 | QML_IMPORT_MAJOR_VERSION = 1
26 |
27 |
28 | @QmlElement
29 | class MpvqcApplicationPathsPyObject(QObject):
30 | _paths = inject.attr(ApplicationPathsService)
31 | _type_mapper: TypeMapperService = inject.attr(TypeMapperService)
32 |
33 | @Property(str, constant=True, final=True)
34 | def input_conf(self) -> str:
35 | return self._type_mapper.map_path_to_str(self._paths.file_input_conf)
36 |
37 | @Property(str, constant=True, final=True)
38 | def mpv_conf(self) -> str:
39 | return self._type_mapper.map_path_to_str(self._paths.file_mpv_conf)
40 |
41 | @Property(QUrl, constant=True, final=True)
42 | def dir_backup(self) -> QUrl:
43 | return self._type_mapper.map_path_to_url(self._paths.dir_backup)
44 |
45 | @Property(QUrl, constant=True, final=True)
46 | def settings(self) -> QUrl:
47 | return self._type_mapper.map_path_to_url(self._paths.file_settings)
48 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/comment_model/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | # ruff: noqa: F401
19 | from .model import MpvqcCommentModelPyObject
20 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/comment_model/item.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 |
19 | import itertools
20 |
21 | from PySide6.QtGui import QStandardItem
22 |
23 | from .roles import Role
24 |
25 | ID_COUNTER = itertools.count()
26 |
27 |
28 | class CommentItem(QStandardItem):
29 | def __init__(self):
30 | super().__init__()
31 | self._id = next(ID_COUNTER)
32 |
33 | def __lt__(self, other: "CommentItem") -> bool:
34 | this_time = self.data(Role.TIME)
35 | that_time = other.data(Role.TIME)
36 |
37 | if this_time < that_time:
38 | return True
39 | if this_time > that_time:
40 | return False
41 | return self._id < other._id
42 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/comment_model/roles.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from PySide6.QtCore import QByteArray
19 |
20 |
21 | class Role:
22 | TIME = 1010
23 | TYPE = 1020
24 | COMMENT = 1030
25 |
26 | MAPPING = {
27 | TIME: QByteArray(b"time"),
28 | TYPE: QByteArray(b"commentType"),
29 | COMMENT: QByteArray(b"comment"),
30 | }
31 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/comment_model/utils.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from typing import Any
19 |
20 | from PySide6.QtGui import QStandardItem, QStandardItemModel
21 |
22 | from mpvqc.models import Comment
23 |
24 | from .item import CommentItem
25 | from .roles import Role
26 |
27 |
28 | def retrieve_comments_from(model: QStandardItemModel) -> list[dict[str, Any]]:
29 | comments = []
30 | for row in range(model.rowCount()):
31 | item = model.item(row, column=0)
32 | comment = create_comment_from(item)
33 | comments.append(comment)
34 | return comments
35 |
36 |
37 | def create_comment_from(item: QStandardItem) -> dict[str, Any]:
38 | return {
39 | "time": int(item.data(Role.TIME)),
40 | "commentType": item.data(Role.TYPE),
41 | "comment": item.data(Role.COMMENT),
42 | }
43 |
44 |
45 | def create_item_from(comment: dict[str, Any] | Comment) -> CommentItem:
46 | item = CommentItem()
47 | if isinstance(comment, Comment):
48 | item.setData(comment.time, Role.TIME)
49 | item.setData(comment.comment_type, Role.TYPE)
50 | item.setData(comment.comment, Role.COMMENT)
51 | else:
52 | item.setData(comment["time"], Role.TIME)
53 | item.setData(comment["commentType"], Role.TYPE)
54 | item.setData(comment["comment"], Role.COMMENT)
55 | return item
56 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/comment_type_validator.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import inject
19 | from PySide6.QtCore import QObject, Slot
20 | from PySide6.QtQml import QmlElement
21 |
22 | from mpvqc.services import CommentTypeValidatorService
23 |
24 | QML_IMPORT_NAME = "pyobjects"
25 | QML_IMPORT_MAJOR_VERSION = 1
26 |
27 |
28 | @QmlElement
29 | class MpvqcCommentTypeValidatorPyObject(QObject):
30 | _validator: CommentTypeValidatorService = inject.attr(CommentTypeValidatorService)
31 |
32 | @Slot(str, list, result=str or None)
33 | def validate_new_comment_type(self, new_comment_type: str, existing_comment_types: list[str]) -> str | None:
34 | return self._validator.validate_new_comment_type(new_comment_type, existing_comment_types)
35 |
36 | @Slot(str, str, list, result=str or None)
37 | def validate_editing_of_comment_type(
38 | self, new_comment_type: str, comment_type_being_edited: str, existing_comment_types: list[str]
39 | ) -> str | None:
40 | return self._validator.validate_editing_of_comment_type(
41 | new_comment_type, comment_type_being_edited, existing_comment_types
42 | )
43 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/export_template_model.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import inject
19 | from PySide6.QtCore import QByteArray
20 | from PySide6.QtGui import QStandardItem, QStandardItemModel
21 | from PySide6.QtQml import QmlElement
22 |
23 | from mpvqc.services import ApplicationPathsService, TypeMapperService
24 |
25 | QML_IMPORT_NAME = "pyobjects"
26 | QML_IMPORT_MAJOR_VERSION = 1
27 |
28 |
29 | @QmlElement
30 | class MpvqcExportTemplateModelPyObject(QStandardItemModel):
31 | _app_paths: ApplicationPathsService = inject.attr(ApplicationPathsService)
32 | _type_mapper: TypeMapperService = inject.attr(TypeMapperService)
33 |
34 | def __init__(self):
35 | super().__init__()
36 | self.setItemRoleNames(Role.MAPPING)
37 | self.setSortRole(Role.NAME)
38 | self._initialize_model()
39 |
40 | def _initialize_model(self):
41 | for template in self._app_paths.files_export_templates:
42 | url = self._type_mapper.map_path_to_url(template)
43 |
44 | item = QStandardItem()
45 | item.setData(url, Role.PATH)
46 | item.setData(template.stem, Role.NAME)
47 | self.appendRow(item)
48 | self.sort(0)
49 |
50 |
51 | class Role:
52 | """
53 | See: https://doc.qt.io/qt-6/qstandarditem.html#ItemType-enum
54 | """
55 |
56 | NAME = 1010
57 | PATH = 1020
58 |
59 | MAPPING = {
60 | NAME: QByteArray(b"name"),
61 | PATH: QByteArray(b"path"),
62 | }
63 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/extended_document_exporter.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import inject
19 | from PySide6.QtCore import QObject, QUrl, Signal, Slot
20 | from PySide6.QtQml import QmlElement
21 |
22 | from mpvqc.services import DocumentExportService, TypeMapperService
23 |
24 | QML_IMPORT_NAME = "pyobjects"
25 | QML_IMPORT_MAJOR_VERSION = 1
26 |
27 |
28 | @QmlElement
29 | class MpvqcExtendedDocumentExporterPyObject(QObject):
30 | _exporter: DocumentExportService = inject.attr(DocumentExportService)
31 | _type_mapper: TypeMapperService = inject.attr(TypeMapperService)
32 |
33 | exportErrorOccurred = Signal(str, int or None)
34 |
35 | @Slot(result=QUrl)
36 | def generate_file_path_proposal(self) -> QUrl:
37 | path = self._exporter.generate_file_path_proposal()
38 | return self._type_mapper.map_path_to_url(path)
39 |
40 | @Slot(QUrl, QUrl)
41 | def export(self, template_url: QUrl, file_url: QUrl):
42 | file = self._type_mapper.map_url_to_path(file_url)
43 | template = self._type_mapper.map_url_to_path(template_url)
44 |
45 | error = self._exporter.export(file, template)
46 |
47 | if error:
48 | self.exportErrorOccurred.emit(error.message, error.line_nr)
49 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/manager/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | # ruff: noqa: F401
19 | from .impl import MpvqcManagerPyObject
20 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/player.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import inject
19 | from PySide6.QtCore import QObject, Slot
20 | from PySide6.QtQml import QmlElement
21 |
22 | from mpvqc.services import KeyCommandGeneratorService, PlayerService
23 |
24 | QML_IMPORT_NAME = "pyobjects"
25 | QML_IMPORT_MAJOR_VERSION = 1
26 |
27 |
28 | @QmlElement
29 | class MpvqcMpvPlayerPyObject(QObject):
30 | _player: PlayerService = inject.attr(PlayerService)
31 | _command_generator: KeyCommandGeneratorService = inject.attr(KeyCommandGeneratorService)
32 |
33 | @Slot()
34 | def pause(self) -> None:
35 | self._player.pause()
36 |
37 | @Slot(int, int)
38 | def handle_key_event(self, key: int, modifiers: int):
39 | if command := self._command_generator.generate_command(key, modifiers):
40 | self._player.execute(command)
41 |
42 | @Slot(int)
43 | def jump_to(self, seconds: int) -> None:
44 | self._player.jump_to(seconds)
45 |
46 | @Slot(int, int)
47 | def move_mouse(self, x, y) -> None:
48 | self._player.move_mouse(x, y)
49 |
50 | @Slot()
51 | def scroll_up(self) -> None:
52 | self._player.scroll_up()
53 |
54 | @Slot()
55 | def scroll_down(self) -> None:
56 | self._player.scroll_down()
57 |
58 | @Slot()
59 | def press_mouse_left(self) -> None:
60 | self._player.press_mouse_left()
61 |
62 | @Slot()
63 | def press_mouse_middle(self) -> None:
64 | self._player.press_mouse_middle()
65 |
66 | @Slot()
67 | def release_mouse_left(self) -> None:
68 | self._player.release_mouse_left()
69 |
70 | @Slot()
71 | def terminate(self) -> None:
72 | self._player.terminate()
73 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/player_files.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import inject
19 | from PySide6.QtCore import Property, QObject, QUrl
20 | from PySide6.QtQml import QmlElement
21 |
22 | from mpvqc.services import ApplicationPathsService, ResourceService, TypeMapperService
23 |
24 | QML_IMPORT_NAME = "pyobjects"
25 | QML_IMPORT_MAJOR_VERSION = 1
26 |
27 |
28 | @QmlElement
29 | class MpvqcPlayerFilesPyObject(QObject):
30 | _paths: ApplicationPathsService = inject.attr(ApplicationPathsService)
31 | _type_mapper: TypeMapperService = inject.attr(TypeMapperService)
32 | _resources: ResourceService = inject.attr(ResourceService)
33 |
34 | @Property(QUrl, constant=True, final=True)
35 | def input_conf_url(self) -> QUrl:
36 | return self._type_mapper.map_path_to_url(self._paths.file_input_conf)
37 |
38 | @Property(QUrl, constant=True, final=True)
39 | def mpv_conf_url(self) -> QUrl:
40 | return self._type_mapper.map_path_to_url(self._paths.file_mpv_conf)
41 |
42 | @Property(str, constant=True, final=True)
43 | def default_input_conf_content(self) -> str:
44 | return self._resources.input_conf_content
45 |
46 | @Property(str, constant=True, final=True)
47 | def default_mpv_conf_content(self) -> str:
48 | return self._resources.mpv_conf_content
49 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/player_win_id.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import inject
19 | from PySide6.QtCore import QCoreApplication, QObject
20 | from PySide6.QtQml import QmlElement
21 | from PySide6.QtQuick import QQuickWindow
22 |
23 | from mpvqc.services import FramelessWindowService, PlayerService
24 |
25 | QML_IMPORT_NAME = "pyobjects"
26 | QML_IMPORT_MAJOR_VERSION = 1
27 |
28 |
29 | # noinspection PyUnresolvedReferences
30 | @QmlElement
31 | class MpvWindowPyObject(QQuickWindow):
32 | _player: PlayerService = inject.attr(PlayerService)
33 | _frameless_window: FramelessWindowService = inject.attr(FramelessWindowService)
34 |
35 | def __init__(self):
36 | super().__init__()
37 | self._player.init(win_id=self.winId())
38 | q_app = QCoreApplication.instance()
39 | q_app.application_ready.connect(lambda: self._on_application_ready())
40 |
41 | def _on_application_ready(self):
42 | player_properties = QCoreApplication.instance().find_object(QObject, "mpvqcPlayerProperties")
43 | player_properties.init()
44 |
45 | self._frameless_window.event_filter.set_embedded_player_hwnd(self.winId())
46 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/text_validator.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from PySide6.QtCore import Slot
19 | from PySide6.QtGui import QValidator
20 | from PySide6.QtQml import QmlElement
21 |
22 | QML_IMPORT_NAME = "pyobjects"
23 | QML_IMPORT_MAJOR_VERSION = 1
24 |
25 |
26 | @QmlElement
27 | class MpvqcDefaultTextValidatorPyObject(QValidator):
28 | def validate(self, user_input: str, position: int):
29 | return QValidator.State.Acceptable, self.replace_special_characters(user_input), position
30 |
31 | @Slot(str, result=str)
32 | def replace_special_characters(self, string_to_replace) -> str:
33 | # fmt: off
34 | return string_to_replace \
35 | .replace("\xad", "") \
36 | .replace("\r", "") \
37 | .replace("\n", "")
38 | # fmt: on
39 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/themes.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import inject
19 | from PySide6.QtCore import QObject, Slot
20 | from PySide6.QtQml import QmlElement
21 |
22 | from mpvqc.services import ThemeService
23 |
24 | QML_IMPORT_NAME = "pyobjects"
25 | QML_IMPORT_MAJOR_VERSION = 1
26 |
27 |
28 | # noinspection PyPep8Naming
29 | @QmlElement
30 | class MpvqcThemesPyObject(QObject):
31 | _themes: ThemeService = inject.attr(ThemeService)
32 |
33 | @Slot(result=list)
34 | def getThemeSummaries(self) -> list[dict]:
35 | return self._themes.get_theme_summaries()
36 |
37 | @Slot(str, result=dict)
38 | def getThemeSummary(self, theme_identifier: str) -> dict:
39 | return self._themes.get_theme_summary(theme_identifier)
40 |
41 | @Slot(str, result=list)
42 | def getThemeColorOptions(self, theme_identifier: str) -> list[dict]:
43 | return self._themes.get_theme_colors(theme_identifier)
44 |
45 | @Slot(int, str, result=dict)
46 | def getThemeColorOption(self, color_option: int, theme_identifier: str):
47 | return self._themes.get_theme_color(color_option, theme_identifier)
48 |
--------------------------------------------------------------------------------
/mpvqc/pyobjects/version_checker.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 | from collections.abc import Callable
18 |
19 | import inject
20 | from PySide6.QtCore import QObject, QRunnable, QThreadPool, Signal, Slot
21 | from PySide6.QtQml import QmlElement
22 |
23 | from mpvqc.services import VersionCheckerService
24 |
25 | QML_IMPORT_NAME = "pyobjects"
26 | QML_IMPORT_MAJOR_VERSION = 1
27 |
28 |
29 | class VersionCheckRunnable(QRunnable):
30 | _checker: VersionCheckerService = inject.attr(VersionCheckerService)
31 |
32 | def __init__(self, callback: Callable[[str, str], None]):
33 | super().__init__()
34 | self._callback = callback
35 |
36 | @Slot()
37 | def run(self):
38 | title, text = self._checker.check_for_new_version()
39 | self._callback(title, text)
40 |
41 |
42 | @QmlElement
43 | class MpvqcVersionCheckerPyObject(QObject):
44 | versionChecked = Signal(str, str)
45 |
46 | @Slot()
47 | def check_for_new_version(self) -> None:
48 | check_runnable = VersionCheckRunnable(self.versionChecked.emit)
49 | QThreadPool().globalInstance().start(check_runnable)
50 |
--------------------------------------------------------------------------------
/mpvqc/services/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | # ruff: noqa: F401
19 | from .application_environment import ApplicationEnvironmentService
20 | from .application_paths import ApplicationPathsService
21 | from .comment_type_validator import CommentTypeValidatorService
22 | from .document_exporter import DocumentBackupService, DocumentExportService, DocumentRenderService
23 | from .document_importer import DocumentImporterService
24 | from .file_startup import FileStartupService
25 | from .font_loader import FontLoaderService
26 | from .formatter_time import TimeFormatterService
27 | from .frameless import FramelessWindowService
28 | from .key_command import KeyCommandGeneratorService
29 | from .mimetype_provider import MimetypeProviderService
30 | from .operating_system_zoom_detector import OperatingSystemZoomDetectorService
31 | from .player import PlayerService
32 | from .resource import ResourceService
33 | from .resource_reader import ResourceReaderService
34 | from .reverse_translator import ReverseTranslatorService
35 | from .settings import SettingsService
36 | from .theme import ThemeService
37 | from .type_mapper import TypeMapperService
38 | from .version_checker import VersionCheckerService
39 | from .video_selector import VideoSelectorService
40 |
--------------------------------------------------------------------------------
/mpvqc/services/application_environment.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import sys
19 | from functools import cached_property
20 | from pathlib import Path
21 |
22 |
23 | class ApplicationEnvironmentService:
24 | """"""
25 |
26 | @cached_property
27 | def is_portable(self) -> bool:
28 | return self.executing_directory.joinpath("portable").is_file()
29 |
30 | @cached_property
31 | def executing_directory(self) -> Path:
32 | return Path(sys.argv[0]).parent
33 |
--------------------------------------------------------------------------------
/mpvqc/services/file_startup.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from pathlib import Path
19 |
20 | import inject
21 |
22 | from .application_paths import ApplicationPathsService
23 | from .resource import ResourceService
24 |
25 |
26 | class FileStartupService:
27 | _paths: ApplicationPathsService = inject.attr(ApplicationPathsService)
28 | _resources: ResourceService = inject.attr(ResourceService)
29 |
30 | def create_missing_directories(self) -> None:
31 | self._paths.dir_config.mkdir(exist_ok=True, parents=True)
32 | self._paths.dir_backup.mkdir(exist_ok=True, parents=True)
33 | self._paths.dir_screenshots.mkdir(exist_ok=True, parents=True)
34 | self._paths.dir_export_templates.mkdir(exist_ok=True, parents=True)
35 |
36 | def create_missing_files(self) -> None:
37 | self._create_missing_input_conf()
38 | self._create_missing_mpv_conf()
39 |
40 | def _create_missing_input_conf(self) -> None:
41 | self._create_missing_file(path=self._paths.file_input_conf, content=self._resources.input_conf_content)
42 |
43 | def _create_missing_mpv_conf(self) -> None:
44 | self._create_missing_file(path=self._paths.file_mpv_conf, content=self._resources.mpv_conf_content)
45 |
46 | @staticmethod
47 | def _create_missing_file(path: Path, content: str) -> None:
48 | if not path.exists():
49 | path.write_text(content, encoding="utf-8", newline="\n")
50 |
--------------------------------------------------------------------------------
/mpvqc/services/font_loader.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from PySide6.QtCore import QDir
19 | from PySide6.QtGui import QFont, QFontDatabase
20 |
21 |
22 | class FontLoaderService:
23 | """"""
24 |
25 | @staticmethod
26 | def load_application_fonts():
27 | for entry_info in QDir(":/data/fonts").entryInfoList():
28 | resource_path = entry_info.filePath()
29 | if not QFontDatabase.addApplicationFont(resource_path) >= 0:
30 | msg = f"Cannot load font from {resource_path}"
31 | raise ValueError(msg)
32 |
33 | QFont.insertSubstitution("Noto Sans", "Noto Sans Hebrew")
34 |
--------------------------------------------------------------------------------
/mpvqc/services/formatter_time.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 |
19 | class TimeFormatterService:
20 | """"""
21 |
22 | @staticmethod
23 | def format_time_to_string(input_seconds: float, *, long_format: bool) -> str:
24 | hours, remainder = divmod(input_seconds, 3600)
25 | minutes, seconds = divmod(remainder, 60)
26 | if long_format:
27 | return f"{int(hours):02d}:{int(minutes):02d}:{int(seconds):02d}"
28 | else: # noqa: RET505
29 | return f"{int(minutes):02d}:{int(seconds):02d}"
30 |
--------------------------------------------------------------------------------
/mpvqc/services/frameless/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2024
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, version 3.
6 | #
7 | # This program is distributed in the hope that it will be useful, but
8 | # WITHOUT ANY WARRANTY; without even the implied warranty of
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 | # General Public License for more details.
11 | #
12 | # You should have received a copy of the GNU General Public License
13 | # along with this program. If not, see .
14 |
15 | # ruff: noqa: F401
16 | from .service import FramelessWindowService
17 |
--------------------------------------------------------------------------------
/mpvqc/services/frameless/linux/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, version 3.
6 | #
7 | # This program is distributed in the hope that it will be useful, but
8 | # WITHOUT ANY WARRANTY; without even the implied warranty of
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 | # General Public License for more details.
11 | #
12 | # You should have received a copy of the GNU General Public License
13 | # along with this program. If not, see .
14 |
15 | # Inspired and based on:
16 | # - https://github.com/zhiyiYo/PyQt-Frameless-Window
17 | # - https://gitee.com/Virace/pyside6-qml-frameless-window/tree/main
18 |
19 | # ruff: noqa: F401
20 | from .event import LinuxEventFilter
21 |
--------------------------------------------------------------------------------
/mpvqc/services/frameless/service.py:
--------------------------------------------------------------------------------
1 | # Copyright 2024
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, version 3.
6 | #
7 | # This program is distributed in the hope that it will be useful, but
8 | # WITHOUT ANY WARRANTY; without even the implied warranty of
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 | # General Public License for more details.
11 | #
12 | # You should have received a copy of the GNU General Public License
13 | # along with this program. If not, see .
14 |
15 | import sys
16 |
17 | from PySide6.QtGui import QGuiApplication, QWindow
18 |
19 |
20 | class FramelessWindowService:
21 | _event_filter = None
22 |
23 | def __init__(self):
24 | if sys.platform == "win32":
25 | from mpvqc.services.frameless.win import WindowsEventFilter
26 |
27 | # We need a reference to this filter as soon as possible
28 | # Needs to bound to a class variable, else garbage collector will clean up immediately
29 | self._event_filter = WindowsEventFilter()
30 |
31 | @property
32 | def event_filter(self):
33 | return self._event_filter
34 |
35 | def configure_for(self, app: QGuiApplication, top_lvl_window: QWindow):
36 | def configure_for_linux():
37 | from .linux import LinuxEventFilter
38 |
39 | # Needs to bound to a class variable, else garbage collector will clean up immediately
40 | self._event_filter = LinuxEventFilter(top_lvl_window, app)
41 | app.installEventFilter(self._event_filter)
42 |
43 | def configure_for_windows():
44 | hwnd_top_lvl = top_lvl_window.winId()
45 | self._event_filter.set_top_lvl_hwnd(hwnd_top_lvl)
46 |
47 | app.installNativeEventFilter(self._event_filter)
48 |
49 | from .win import configure_gwl_style, extend_frame_into_client_area
50 |
51 | extend_frame_into_client_area(hwnd_top_lvl)
52 | configure_gwl_style(hwnd_top_lvl)
53 |
54 | if sys.platform == "win32":
55 | configure_for_windows()
56 | elif sys.platform == "linux":
57 | configure_for_linux()
58 | else:
59 | msg = f"Unsupported platform: {sys.platform}"
60 | raise ValueError(msg)
61 |
--------------------------------------------------------------------------------
/mpvqc/services/frameless/win/__init__.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, version 3.
6 | #
7 | # This program is distributed in the hope that it will be useful, but
8 | # WITHOUT ANY WARRANTY; without even the implied warranty of
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 | # General Public License for more details.
11 | #
12 | # You should have received a copy of the GNU General Public License
13 | # along with this program. If not, see .
14 |
15 | # Inspired and based on:
16 | # - https://github.com/zhiyiYo/PyQt-Frameless-Window
17 | # - https://gitee.com/Virace/pyside6-qml-frameless-window/tree/main
18 |
19 | # ruff: noqa: F401
20 | from .event import WindowsEventFilter
21 | from .utils import configure_gwl_style, extend_frame_into_client_area
22 |
--------------------------------------------------------------------------------
/mpvqc/services/frameless/win/c_structures.py:
--------------------------------------------------------------------------------
1 | # Copyright 2023
2 | #
3 | # This program is free software: you can redistribute it and/or modify
4 | # it under the terms of the GNU General Public License as published by
5 | # the Free Software Foundation, version 3.
6 | #
7 | # This program is distributed in the hope that it will be useful, but
8 | # WITHOUT ANY WARRANTY; without even the implied warranty of
9 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
10 | # General Public License for more details.
11 | #
12 | # You should have received a copy of the GNU General Public License
13 | # along with this program. If not, see .
14 |
15 | # Inspired and based on:
16 | # - https://github.com/zhiyiYo/PyQt-Frameless-Window
17 | # - https://gitee.com/Virace/pyside6-qml-frameless-window/tree/main
18 |
19 | from ctypes import POINTER, Structure, c_int
20 | from ctypes.wintypes import HWND, RECT, UINT
21 |
22 |
23 | class MARGINS(Structure):
24 | _fields_ = [
25 | ("cxLeftWidth", c_int),
26 | ("cxRightWidth", c_int),
27 | ("cyTopHeight", c_int),
28 | ("cyBottomHeight", c_int),
29 | ]
30 |
31 |
32 | class PWINDOWPOS(Structure):
33 | _fields_ = [
34 | ("hWnd", HWND),
35 | ("hwndInsertAfter", HWND),
36 | ("x", c_int),
37 | ("y", c_int),
38 | ("cx", c_int),
39 | ("cy", c_int),
40 | ("flags", UINT),
41 | ]
42 |
43 |
44 | class NCCALCSIZE_PARAMS(Structure):
45 | _fields_ = [("rgrc", RECT * 3), ("lppos", POINTER(PWINDOWPOS))]
46 |
47 |
48 | LPNCCALCSIZE_PARAMS = POINTER(NCCALCSIZE_PARAMS)
49 |
--------------------------------------------------------------------------------
/mpvqc/services/mimetype_provider.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from functools import cached_property
19 |
20 | from PySide6.QtCore import QMimeDatabase
21 |
22 |
23 | class MimetypeProviderService:
24 | @cached_property
25 | def video_file_glob_pattern(self):
26 | patterns = set()
27 | patterns.add("*.avi")
28 | patterns.add("*.mkv")
29 | patterns.add("*.mp4")
30 |
31 | for mime_type in QMimeDatabase().allMimeTypes():
32 | if mime_type.name().startswith("video/"):
33 | patterns.update(mime_type.globPatterns())
34 |
35 | return f" ({' '.join(sorted(patterns))})"
36 |
37 | @cached_property
38 | def subtitle_file_glob_pattern(self):
39 | patterns = (f"*.{ext}" for ext in self.subtitle_file_extensions)
40 | return f" ({' '.join(sorted(patterns))})"
41 |
42 | @cached_property
43 | def subtitle_file_extensions(self) -> list[str]:
44 | # fmt: off
45 | return [
46 | "aqt", "ass", "idx", "js", "jss", "mks", "rt", "scc", "smi",
47 | "srt", "ssa", "sub", "sup", "utf", "utf-8", "utf8", "vtt"
48 | ]
49 | # fmt: on
50 |
--------------------------------------------------------------------------------
/mpvqc/services/resource.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import platform
19 | from functools import cache
20 |
21 | import inject
22 |
23 | from .resource_reader import ResourceReaderService
24 |
25 |
26 | class ResourceService:
27 | _resource_reader = inject.attr(ResourceReaderService)
28 |
29 | @property
30 | def input_conf_content(self) -> str:
31 | return self._read_from_resource(path=":/data/config/input.conf")
32 |
33 | @property
34 | def mpv_conf_content(self) -> str:
35 | match platform.system():
36 | case "Windows":
37 | return self._read_from_resource(path=":/data/config/mpv-windows.conf")
38 | case _:
39 | return self._read_from_resource(path=":/data/config/mpv-linux.conf")
40 |
41 | @property
42 | def backup_template(self) -> str:
43 | return self._read_from_resource(path=":/data/config/backup-template.jinja")
44 |
45 | @property
46 | def default_export_template(self) -> str:
47 | return self._read_from_resource(path=":/data/config/export-template.jinja")
48 |
49 | @cache
50 | def _read_from_resource(self, path: str) -> str:
51 | return self._resource_reader.read_from(path)
52 |
--------------------------------------------------------------------------------
/mpvqc/services/resource_reader.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from PySide6.QtCore import QFile, QIODevice
19 |
20 |
21 | class ResourceReaderService:
22 | """"""
23 |
24 | def read_from(self, file_path: str) -> str:
25 | resource_path = self._make_resource_path_from(file_path)
26 | return self._read_from(resource_path)
27 |
28 | @staticmethod
29 | def _make_resource_path_from(file_path: str) -> str:
30 | if file_path.startswith(":/"):
31 | return file_path
32 | if file_path.startswith("/"):
33 | return ":" + file_path
34 | return ":/" + file_path
35 |
36 | @staticmethod
37 | def _read_from(resource_path: str) -> str:
38 | file = QFile(resource_path)
39 | if not file.exists():
40 | raise FileNotFoundError(resource_path)
41 | try:
42 | if not file.open(QIODevice.OpenModeFlag.ReadOnly):
43 | msg = f"Can not open file to read: {resource_path}"
44 | raise ValueError(msg)
45 | return file.readAll().data().decode("utf-8")
46 | finally:
47 | if file.isOpen():
48 | file.close()
49 |
--------------------------------------------------------------------------------
/mpvqc/services/theme/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | # ruff: noqa: F401
19 | from .schema import Theme
20 | from .service import ThemeService
21 |
--------------------------------------------------------------------------------
/mpvqc/services/theme/utils.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import re
19 | from decimal import ROUND_HALF_UP, Decimal
20 |
21 | from PySide6.QtGui import QColor
22 |
23 | from mpvqc.services.theme.schema import ThemeParseError
24 |
25 | WHOLE_NUMBER = Decimal(0)
26 |
27 | MULTI_WHITESPACE = re.compile(r"\s+")
28 | HEX_COLOR_RE = re.compile(r"^#(?=(?:.{3}|.{6})$)[a-f0-9]*$")
29 | INT_OR_FLOAT_RE = re.compile(r"^[-+]?\d+(\.\d+)?$")
30 |
31 |
32 | def parse_color(_color_input: str) -> QColor:
33 | color_input = MULTI_WHITESPACE.sub(" ", _color_input).strip().lower()
34 |
35 | match color_input.split():
36 | case [color] if _is_hex(color):
37 | return QColor(color)
38 | case ["qt.darker", color, factor] if _is_hex(color) and _is_int_or_float(factor):
39 | return QColor(color).darker(_adapted_factor(factor))
40 | case ["qt.lighter", color, factor] if _is_hex(color) and _is_int_or_float(factor):
41 | return QColor(color).lighter(_adapted_factor(factor))
42 | case _:
43 | msg = f"Cannot parse color: {_color_input}"
44 | raise ThemeParseError(msg)
45 |
46 |
47 | def _is_hex(color: str) -> bool:
48 | return bool(HEX_COLOR_RE.fullmatch(color))
49 |
50 |
51 | def _is_int_or_float(factor: str) -> bool:
52 | return bool(INT_OR_FLOAT_RE.fullmatch(factor))
53 |
54 |
55 | def _adapted_factor(factor: str) -> int:
56 | f = Decimal(f"{float(factor) * 100}").quantize(WHOLE_NUMBER, ROUND_HALF_UP)
57 | return int(f)
58 |
--------------------------------------------------------------------------------
/mpvqc/services/type_mapper.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from pathlib import Path
19 |
20 | from PySide6.QtCore import QUrl
21 |
22 |
23 | class TypeMapperService:
24 | """"""
25 |
26 | @staticmethod
27 | def map_urls_to_path(urls: list[QUrl]) -> list[Path]:
28 | return list(map(TypeMapperService.map_url_to_path, urls))
29 |
30 | @staticmethod
31 | def map_url_to_path(url: QUrl) -> Path:
32 | return Path(url.toLocalFile()).resolve()
33 |
34 | @staticmethod
35 | def map_urls_to_path_strings(urls: list[QUrl]) -> list[str]:
36 | return list(map(TypeMapperService.map_url_to_path_string, urls))
37 |
38 | @staticmethod
39 | def map_url_to_path_string(url: QUrl) -> str:
40 | return f"{Path(url.toLocalFile()).resolve()}"
41 |
42 | @staticmethod
43 | def map_path_to_url(path: Path) -> QUrl:
44 | return QUrl.fromLocalFile(f"{path.resolve()}")
45 |
46 | @staticmethod
47 | def map_path_to_str(path: Path) -> str:
48 | return f"{path.resolve()}"
49 |
50 | @staticmethod
51 | def normalize_path_str(path: str) -> str:
52 | return f"{Path(path).resolve()}"
53 |
--------------------------------------------------------------------------------
/qml/Main.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import app
21 |
22 | MpvqcApplication {}
23 |
--------------------------------------------------------------------------------
/qml/app/MpvqcQuitHandler.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | pragma ComponentBehavior: Bound
21 |
22 | import QtQuick
23 |
24 | import dialogs
25 |
26 | Item {
27 | id: root
28 |
29 | required property var mpvqcApplication
30 | required property bool canClose
31 |
32 | readonly property var mpvqcMpvPlayerPyObject: mpvqcApplication.mpvqcMpvPlayerPyObject
33 | readonly property var mpvqcManager: mpvqcApplication.mpvqcManager
34 |
35 | property bool userConfirmedClose: false
36 |
37 | property var quitDialog: null
38 | property var quitDialogFactory: Component {
39 | MpvqcMessageBoxQuit {
40 | mpvqcApplication: root.mpvqcApplication
41 |
42 | onAccepted: {
43 | root._close();
44 | }
45 | }
46 | }
47 |
48 | function requestClose() {
49 | if (canClose || userConfirmedClose) {
50 | _close();
51 | } else {
52 | quitDialog = quitDialogFactory.createObject(root);
53 | quitDialog.closed.connect(quitDialog.destroy);
54 | quitDialog.open();
55 | }
56 | }
57 |
58 | function _close() {
59 | userConfirmedClose = true;
60 | _workaroundNativeWindowInterfering()
61 | mpvqcApplication.close();
62 | }
63 |
64 | function _workaroundNativeWindowInterfering() {
65 | if (Qt.platform.os === "windows" && mpvqcManager.saved) {
66 | mpvqcMpvPlayerPyObject.terminate()
67 | }
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/qml/app/MpvqcWindowVisibilityHandler.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 |
22 | QtObject {
23 | id: root
24 |
25 | required property var mpvqcApplication
26 |
27 | readonly property bool maximized: mpvqcApplication.visibility === Window.Maximized
28 | readonly property bool fullscreen: mpvqcApplication.visibility === Window.FullScreen
29 |
30 | property bool wasMaximizedBefore: false
31 |
32 | function toggleMaximized() {
33 | if (maximized) {
34 | mpvqcApplication.showNormal();
35 | } else {
36 | mpvqcApplication.showMaximized();
37 | }
38 | }
39 |
40 | function toggleFullScreen() {
41 | if (fullscreen) {
42 | disableFullScreen();
43 | } else {
44 | enableFullScreen();
45 | }
46 | }
47 |
48 | function enableFullScreen() {
49 | if (!fullscreen) {
50 | wasMaximizedBefore = maximized;
51 | mpvqcApplication.showFullScreen();
52 | }
53 | }
54 |
55 | function disableFullScreen() {
56 | if (fullscreen && wasMaximizedBefore) {
57 | mpvqcApplication.showMaximized();
58 | } else if (fullscreen) {
59 | mpvqcApplication.showNormal();
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/qml/app/qmldir:
--------------------------------------------------------------------------------
1 | module app
2 |
3 | MpvqcApplication MpvqcApplication.qml
4 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcDialogExportDocument.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick.Dialogs
21 |
22 | FileDialog {
23 | title: qsTranslate("FileInteractionDialogs", "Save QC Document As")
24 | fileMode: FileDialog.SaveFile
25 | defaultSuffix: "txt"
26 | nameFilters: [
27 | qsTranslate("FileInteractionDialogs", "QC documents") + " (*.txt)",
28 | qsTranslate("FileInteractionDialogs", "All files") + " (*)",
29 | ]
30 |
31 | signal savePressed(url fileUrl)
32 |
33 | onAccepted: {
34 | savePressed(currentFile);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcDialogImportDocuments.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick.Dialogs
21 |
22 | FileDialog {
23 | required property var mpvqcApplication
24 |
25 | readonly property var mpvqcManager: mpvqcApplication.mpvqcManager
26 | readonly property var mpvqcSettings: mpvqcApplication.mpvqcSettings
27 |
28 | title: qsTranslate("FileInteractionDialogs", "Open QC Document(s)")
29 | currentFolder: mpvqcSettings.lastDirectoryDocuments
30 | fileMode: FileDialog.OpenFiles
31 | nameFilters: [
32 | qsTranslate("FileInteractionDialogs", "QC documents") + " (*.txt)",
33 | qsTranslate("FileInteractionDialogs", "All files") + " (*)",
34 | ]
35 |
36 | onAccepted: {
37 | mpvqcSettings.lastDirectoryDocuments = currentFolder;
38 | mpvqcManager.openDocuments(selectedFiles);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcDialogImportSubtitles.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick.Dialogs
21 |
22 | FileDialog {
23 | required property var mpvqcApplication
24 |
25 | readonly property var mpvqcManager: mpvqcApplication.mpvqcManager
26 | readonly property var mpvqcSettings: mpvqcApplication.mpvqcSettings
27 | readonly property var mpvqcUtilityPyObject: mpvqcApplication.mpvqcUtilityPyObject
28 |
29 | title: qsTranslate("FileInteractionDialogs", "Open Subtitle(s)")
30 | currentFolder: mpvqcSettings.lastDirectorySubtitles
31 | fileMode: FileDialog.OpenFiles
32 | nameFilters: [
33 | qsTranslate("FileInteractionDialogs", "Subtitle files") + mpvqcUtilityPyObject.subtitleFileGlobPattern,
34 | qsTranslate("FileInteractionDialogs", "All files") + " (*)",
35 | ]
36 |
37 | onAccepted: {
38 | mpvqcSettings.lastDirectorySubtitles = currentFolder;
39 | mpvqcManager.openSubtitles(selectedFiles);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcDialogImportVideo.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick.Dialogs
21 |
22 | FileDialog {
23 | required property var mpvqcApplication
24 |
25 | readonly property var mpvqcManager: mpvqcApplication.mpvqcManager
26 | readonly property var mpvqcSettings: mpvqcApplication.mpvqcSettings
27 | readonly property var mpvqcUtilityPyObject: mpvqcApplication.mpvqcUtilityPyObject
28 |
29 | title: qsTranslate("FileInteractionDialogs", "Open Video")
30 | currentFolder: mpvqcSettings.lastDirectoryVideo
31 | nameFilters: [
32 | qsTranslate("FileInteractionDialogs", "Video files") + mpvqcUtilityPyObject.videoFileGlobPattern,
33 | qsTranslate("FileInteractionDialogs", "All files") + " (*)",
34 | ]
35 |
36 | onAccepted: {
37 | mpvqcSettings.lastDirectoryVideo = currentFolder;
38 | mpvqcManager.openVideo(currentFile);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcMessageBoxDocumentNotCompatible.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import shared
21 |
22 | MpvqcMessageBox {
23 | id: root
24 |
25 | required property int count
26 |
27 | title: count === 1
28 | ? qsTranslate("MessageBoxes", "Document Not Compatible")
29 | : qsTranslate("MessageBoxes", "Documents Not Compatible")
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcMessageBoxExtendedExport.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2024 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | import shared
24 |
25 | MpvqcMessageBox {
26 | title: qsTranslate("MessageBoxes", "Extended Exports")
27 |
28 | contentItem: Label {
29 | //: %1 will be the link to the Jinja templating engine. %2 will be the link to mpvQC's documentation about export templates
30 | text: qsTranslate("MessageBoxes", "mpvQC allows for customizing report exports using the %1 engine. To begin, visit %2")
31 | .arg(`Jinja template`)
32 | .arg(`https://mpvqc.github.io/export-templates`)
33 | horizontalAlignment: Text.AlignLeft
34 | wrapMode: Label.WordWrap
35 | elide: Text.ElideLeft
36 |
37 | onLinkActivated: link => {
38 | Qt.openUrlExternally(link);
39 | }
40 |
41 | MouseArea {
42 | anchors.fill: parent
43 | acceptedButtons: Qt.NoButton
44 | cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
45 | hoverEnabled: true
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcMessageBoxNewDocument.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick.Controls.Material
21 |
22 | import shared
23 |
24 | MpvqcMessageBox {
25 | title: qsTranslate("MessageBoxes", "Unsaved Changes")
26 | text: qsTranslate("MessageBoxes", "Do you really want to create a new QC document without saving your QC?")
27 | standardButtons: Dialog.Yes | Dialog.No
28 | }
29 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcMessageBoxQuit.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick.Controls.Material
21 |
22 | import shared
23 |
24 | MpvqcMessageBox {
25 | title: qsTranslate("MessageBoxes", "Unsaved Changes")
26 | text: qsTranslate("MessageBoxes", "Do you really want to quit without saving your QC?")
27 | standardButtons: Dialog.Yes | Dialog.Cancel
28 | }
29 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcMessageBoxVersionCheck.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | import shared
24 |
25 | MpvqcMessageBox {
26 | id: root
27 |
28 | readonly property var mpvqcVersionCheckerPyObject: mpvqcApplication.mpvqcVersionCheckerPyObject
29 |
30 | title: qsTranslate("MessageBoxes", "Checking for Updates...")
31 |
32 | contentItem: Label {
33 | text: qsTranslate("MessageBoxes", "Loading...")
34 | horizontalAlignment: Text.AlignLeft
35 | wrapMode: Label.WordWrap
36 | elide: Text.ElideLeft
37 |
38 | onLinkActivated: link => {
39 | Qt.openUrlExternally(link);
40 | }
41 |
42 | MouseArea {
43 | anchors.fill: parent
44 | acceptedButtons: Qt.NoButton
45 | cursorShape: parent.hoveredLink ? Qt.PointingHandCursor : Qt.ArrowCursor
46 | hoverEnabled: true
47 | }
48 | }
49 |
50 | Component.onCompleted: {
51 | root.mpvqcVersionCheckerPyObject.check_for_new_version();
52 | }
53 |
54 | Connections {
55 | target: root.mpvqcVersionCheckerPyObject
56 |
57 | function onVersionChecked(title: string, text: string) {
58 | root.title = title;
59 | root.contentItem.text = text;
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/qml/dialogs/MpvqcMessageBoxVideoFound.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick.Controls.Material
21 |
22 | import shared
23 |
24 | MpvqcMessageBox {
25 | title: qsTranslate("MessageBoxes", "Video Found")
26 | text: qsTranslate("MessageBoxes", "A video was found. Do you want to open it?")
27 | standardButtons: Dialog.Yes | Dialog.No
28 | }
29 |
--------------------------------------------------------------------------------
/qml/dialogs/about/MpvqcDialogAbout.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import shared
21 |
22 | MpvqcDialog {
23 | id: root
24 |
25 | MpvqcAboutView {
26 | //: Title of a tab in the about dialog
27 | property string title: qsTranslate("AboutDialog", "About")
28 |
29 | width: root.width
30 | }
31 |
32 | MpvqcCreditsView {
33 | //: Title of a tab in the about dialog
34 | property string title: qsTranslate("AboutDialog", "Credits")
35 |
36 | width: root.width
37 | }
38 |
39 | MpvqcDependenciesView {
40 | //: Title of a tab in the about dialog
41 | property string title: qsTranslate("AboutDialog", "Dependencies")
42 |
43 | width: root.width
44 | mpvqcApplication: root.mpvqcApplication
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/qml/dialogs/appearance/MpvqcDialogAppearance.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | import shared
24 |
25 | MpvqcDialog {
26 | id: root
27 |
28 | ScrollView {
29 | property string title: qsTranslate("AppearanceDialog", "Appearance")
30 |
31 | width: parent.width
32 |
33 | Column {
34 | width: parent.width
35 |
36 | MpvqcHeader {
37 | text: qsTranslate("AppearanceDialog", "Theme")
38 | width: parent.width
39 | }
40 |
41 | MpvqcThemeView {
42 | id: _themeView
43 |
44 | mpvqcApplication: root.mpvqcApplication
45 | width: parent.width
46 |
47 | // workaround padding issue in rtl
48 | Binding on x { when: root.mirrored; value: -8 }
49 | }
50 |
51 | MpvqcHeader {
52 | text: qsTranslate("AppearanceDialog", "Color")
53 | width: parent.width
54 | }
55 |
56 | MpvqcColorView {
57 | id: _colorView
58 |
59 | mpvqcApplication: root.mpvqcApplication
60 | width: parent.width
61 | }
62 | }
63 | }
64 |
65 | onRejected: {
66 | _themeView.reset();
67 | _colorView.reset();
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/qml/dialogs/backup/MpvqcDialogBackup.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import shared
21 |
22 | MpvqcDialog {
23 | id: root
24 |
25 | MpvqcBackupView {
26 | id: _backupView
27 |
28 | property string title: qsTranslate("BackupDialog", "Backup Settings")
29 |
30 | width: root.width
31 | mpvqcApplication: root.mpvqcApplication
32 | }
33 |
34 | onAccepted: {
35 | _backupView.accept();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/qml/dialogs/commenttypes/MpvqcDialogCommentTypes.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick.Controls.Material
21 |
22 | import shared
23 |
24 | MpvqcDialog {
25 | id: root
26 |
27 | standardButtons: Dialog.Ok | Dialog.Cancel | Dialog.Reset
28 |
29 | MpvqcCommentTypesView {
30 | id: _view
31 |
32 | property string title: qsTranslate("CommentTypesDialog", "Comment Types")
33 |
34 | mpvqcApplication: root.mpvqcApplication
35 | width: parent.width
36 | }
37 |
38 | onAccepted: {
39 | _view.visible = false;
40 | _view.acceptTemporaryState();
41 | }
42 |
43 | onReset: {
44 | _view.resetTemporaryEdits();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/qml/dialogs/commenttypes/tst_MpvqcList.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | Item {
24 | id: testHelper
25 |
26 | width: 400
27 | height: 400
28 |
29 | MpvqcList {
30 | id: objectUnderTest
31 | anchors.fill: testHelper
32 |
33 | model: ["Type 0", "Type 1", "Type 2", "Type 3", "Type 4", "Type 5"]
34 | itemHeight: 42
35 |
36 | mpvqcApplication: QtObject {
37 | property var mpvqcTheme: QtObject {
38 | property color control: "purple"
39 | }
40 | }
41 | }
42 |
43 | TestCase {
44 | name: "MpvqcList"
45 | when: windowShown
46 |
47 | function cleanup() {
48 | objectUnderTest.currentIndex = 0;
49 | }
50 |
51 | function test_selection_data() {
52 | return [
53 | {
54 | tag: "row-3",
55 | index: 3
56 | },
57 | {
58 | tag: "row-5",
59 | index: 5
60 | },
61 | ];
62 | }
63 |
64 | function test_selection(data) {
65 | ensureRenderedUntilItem(data.index + 1);
66 | compare(objectUnderTest.currentIndex, 0);
67 |
68 | const item = objectUnderTest.itemAtIndex(data.index);
69 | mouseClick(item);
70 |
71 | compare(objectUnderTest.currentIndex, data.index);
72 | }
73 |
74 | function ensureRenderedUntilItem(index: int): void {
75 | objectUnderTest.currentIndex = index;
76 | objectUnderTest.currentIndex = 0;
77 | }
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/qml/dialogs/editinput/MpvqcDialogEditInput.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | import shared
24 |
25 | MpvqcDialog {
26 | id: root
27 |
28 | property alias editView: _editView
29 |
30 | contentWidth: Math.min(1080, mpvqcApplication.width * 0.75)
31 | contentHeight: Math.min(1080, mpvqcApplication.height * 0.75)
32 | standardButtons: Dialog.Ok | Dialog.Cancel | Dialog.Reset
33 |
34 | MpvqcEditInputView {
35 | id: _editView
36 |
37 | property string title: qsTranslate("InputConfEditDialog", "Edit input.conf")
38 |
39 | width: root.contentWidth
40 | mpvqcApplication: root.mpvqcApplication
41 | }
42 |
43 | onAccepted: {
44 | _editView.accept();
45 | }
46 |
47 | onReset: {
48 | _editView.reset();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/qml/dialogs/editinput/tst_MpvqcDialogEditInput.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | TestCase {
24 | id: testCase
25 |
26 | width: 400
27 | height: 400
28 | visible: true
29 | when: windowShown
30 | name: "MpvqcDialogEditInput"
31 |
32 | Component {
33 | id: objectUnderTest
34 |
35 | MpvqcDialogEditInput {
36 |
37 | mpvqcApplication: QtObject {
38 | property var mpvqcPlayerFilesPyObject: QtObject {
39 | property string default_input_conf_content: "default"
40 | property url input_conf_url: ""
41 | }
42 | }
43 | }
44 | }
45 |
46 | function test_edit_accept() {
47 | let acceptCalled = false;
48 |
49 | const control = createTemporaryObject(objectUnderTest, testCase, {
50 | "editView.accept": () => {
51 | acceptCalled = true;
52 | }
53 | });
54 | verify(control);
55 |
56 | control.editView.textArea.text = "changed by user";
57 | control.accepted();
58 | verify(acceptCalled);
59 | }
60 |
61 | function test_edit_reset() {
62 | const control = createTemporaryObject(objectUnderTest, testCase);
63 | verify(control);
64 |
65 | control.editView.textArea.text = "changed by user";
66 |
67 | control.reset();
68 | compare(control.editView.textArea.text, "default");
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/qml/dialogs/editmpv/MpvqcDialogEditMpv.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | import shared
24 |
25 | MpvqcDialog {
26 | id: root
27 |
28 | property alias editView: _editView
29 |
30 | contentWidth: Math.min(1080, mpvqcApplication.width * 0.75)
31 | contentHeight: Math.min(1080, mpvqcApplication.height * 0.75)
32 | standardButtons: Dialog.Ok | Dialog.Cancel | Dialog.Reset
33 |
34 | MpvqcEditMpvView {
35 | id: _editView
36 |
37 | property string title: qsTranslate("MpvConfEditDialog", "Edit mpv.conf")
38 |
39 | width: root.contentWidth
40 | mpvqcApplication: root.mpvqcApplication
41 | }
42 |
43 | onAccepted: {
44 | _editView.accept();
45 | }
46 |
47 | onReset: {
48 | _editView.reset();
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/qml/dialogs/editmpv/tst_MpvqcDialogEditMpv.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | TestCase {
24 | id: testCase
25 |
26 | width: 400
27 | height: 400
28 | visible: true
29 | when: windowShown
30 | name: "MpvqcDialogEditMpv"
31 |
32 | Component {
33 | id: objectUnderTest
34 |
35 | MpvqcDialogEditMpv {
36 |
37 | mpvqcApplication: QtObject {
38 | property var mpvqcPlayerFilesPyObject: QtObject {
39 | property string default_mpv_conf_content: "default"
40 | property url mpv_conf_url: ""
41 | }
42 | }
43 | }
44 | }
45 |
46 | function test_edit_accept() {
47 | let acceptCalled = false;
48 |
49 | const control = createTemporaryObject(objectUnderTest, testCase, {
50 | "editView.accept": () => {
51 | acceptCalled = true;
52 | }
53 | });
54 | verify(control);
55 |
56 | control.editView.textArea.text = "changed by user";
57 | control.accepted();
58 | verify(acceptCalled);
59 | }
60 |
61 | function test_edit_reset() {
62 | const control = createTemporaryObject(objectUnderTest, testCase);
63 | verify(control);
64 |
65 | control.editView.textArea.text = "changed by user";
66 |
67 | control.reset();
68 | compare(control.editView.textArea.text, "default");
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/qml/dialogs/export/MpvqcDialogExport.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import shared
21 |
22 | MpvqcDialog {
23 | id: root
24 |
25 | MpvqcExportView {
26 | id: _exportView
27 |
28 | property string title: qsTranslate("ExportSettingsDialog", "Export Settings")
29 |
30 | width: root.width
31 | mpvqcApplication: root.mpvqcApplication
32 | }
33 |
34 | onAccepted: {
35 | _exportView.accept();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/qml/dialogs/import/MpvqcDialogImport.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import shared
21 |
22 | MpvqcDialog {
23 | id: root
24 |
25 | MpvqcImportView {
26 | id: _importView
27 |
28 | property string title: qsTranslate("ImportSettingsDialog", "Import Settings")
29 |
30 | width: root.width
31 | mpvqcApplication: root.mpvqcApplication
32 | }
33 |
34 | onAccepted: {
35 | _importView.accept();
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/qml/dialogs/qmldir:
--------------------------------------------------------------------------------
1 | module dialogs
2 |
3 | MpvqcDialogAbout about/MpvqcDialogAbout.qml
4 |
5 | MpvqcDialogAppearance appearance/MpvqcDialogAppearance.qml
6 |
7 | MpvqcDialogBackup backup/MpvqcDialogBackup.qml
8 |
9 | MpvqcDialogCommentTypes commenttypes/MpvqcDialogCommentTypes.qml
10 |
11 | MpvqcDialogImport import/MpvqcDialogImport.qml
12 |
13 | MpvqcDialogEditInput editinput/MpvqcDialogEditInput.qml
14 | MpvqcDialogEditMpv editmpv/MpvqcDialogEditMpv.qml
15 |
16 | MpvqcDialogExport export/MpvqcDialogExport.qml
17 |
18 | MpvqcDialogShortcuts shortcuts/MpvqcDialogShortcuts.qml
19 |
20 | MpvqcDialogExportDocument MpvqcDialogExportDocument.qml
21 | MpvqcDialogImportDocuments MpvqcDialogImportDocuments.qml
22 | MpvqcDialogImportSubtitles MpvqcDialogImportSubtitles.qml
23 | MpvqcDialogImportVideo MpvqcDialogImportVideo.qml
24 |
25 | MpvqcMessageBoxDocumentNotCompatible MpvqcMessageBoxDocumentNotCompatible.qml
26 | MpvqcMessageBoxExtendedExport MpvqcMessageBoxExtendedExport.qml
27 | MpvqcMessageBoxNewDocument MpvqcMessageBoxNewDocument.qml
28 | MpvqcMessageBoxQuit MpvqcMessageBoxQuit.qml
29 | MpvqcMessageBoxVersionCheck MpvqcMessageBoxVersionCheck.qml
30 | MpvqcMessageBoxVideoFound MpvqcMessageBoxVideoFound.qml
31 |
--------------------------------------------------------------------------------
/qml/dialogs/shortcuts/MpvqcDialogShortcuts.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 |
22 | import shared
23 |
24 | MpvqcDialog {
25 | id: root
26 |
27 | contentWidth: 500
28 | contentHeight: Math.min(1080, mpvqcApplication.height * 0.75)
29 |
30 | MpvqcShortcutView {
31 | property string title: qsTranslate("ShortcutsDialog", "Keyboard Shortcuts")
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/qml/dialogs/shortcuts/MpvqcShortcutButton.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2024 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | Button {
24 | readonly property bool hasContent: text || icon.source.toString()
25 |
26 | enabled: false
27 | visible: hasContent
28 | height: hasContent ? implicitHeight : 0
29 | width: hasContent ? implicitWidth : 0
30 | }
31 |
--------------------------------------------------------------------------------
/qml/dialogs/shortcuts/MpvqcShortcutFilterModel.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2024 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | // https://martin.rpdev.net/2019/01/15/using-delegatemodel-in-qml-for-sorting-and-filtering.html
21 |
22 | import QtQuick
23 | import QtQml.Models
24 |
25 | DelegateModel {
26 | property var filterAcceptsItem: item => true
27 |
28 | function update() {
29 | if (items.count > 0) {
30 | items.setGroups(0, items.count, "items");
31 | }
32 |
33 | const visible = [];
34 | for (let i = 0; i < items.count; ++i) {
35 | const item = items.get(i);
36 | if (filterAcceptsItem(item.model)) {
37 | visible.push(item);
38 | }
39 | }
40 |
41 | for (let i = 0; i < visible.length; ++i) {
42 | const item = visible[i];
43 | item.inVisible = true;
44 | if (item.visibleIndex !== i) {
45 | visibleItems.move(item.visibleIndex, i, 1);
46 | }
47 | }
48 | }
49 |
50 | groups: DelegateModelGroup {
51 | id: visibleItems
52 |
53 | name: "visible"
54 | includeByDefault: false
55 | }
56 |
57 | filterOnGroup: "visible"
58 |
59 | Component.onCompleted: {
60 | _filterModel.update();
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/qml/dialogs/tst_MpvqcDialogExportDocument.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | TestCase {
24 | id: testCase
25 |
26 | readonly property url currentFile: "file:///hello.txt"
27 |
28 | name: "MpvqcDialogExportDocument"
29 | when: windowShown
30 |
31 | Component {
32 | id: objectUnderTest
33 |
34 | MpvqcDialogExportDocument {
35 | property url savedUrlInTest
36 |
37 | onSavePressed: fileUrl => {
38 | this.savedUrlInTest = fileUrl;
39 | }
40 | }
41 | }
42 |
43 | function test_save() {
44 | const control = createTemporaryObject(objectUnderTest, testCase);
45 | verify(control);
46 |
47 | control.currentFile = testCase.currentFile;
48 | control.accepted();
49 | compare(control.savedUrlInTest, testCase.currentFile);
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/qml/dialogs/tst_MpvqcDialogImportDocuments.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | TestCase {
24 | id: testCase
25 |
26 | width: 400
27 | height: 400
28 | visible: true
29 | when: windowShown
30 | name: "MpvqcDialogImportDocuments"
31 |
32 | Component {
33 | id: objectUnderTest
34 |
35 | MpvqcDialogImportDocuments {
36 | id: __objectUnderTest
37 |
38 | property bool openDocumentsCalled: false
39 |
40 | mpvqcApplication: QtObject {
41 | property var mpvqcManager: QtObject {
42 | function openDocuments(files) {
43 | __objectUnderTest.openDocumentsCalled = true;
44 | }
45 | }
46 | property var mpvqcSettings: QtObject {
47 | property string lastDirectoryDocuments: "initial directory"
48 | }
49 | }
50 | }
51 | }
52 |
53 | function test_import() {
54 | const control = createTemporaryObject(objectUnderTest, testCase);
55 | verify(control);
56 |
57 | control.currentFolder = "some directory";
58 | control.accepted();
59 |
60 | verify(control.openDocumentsCalled);
61 | verify(!control.mpvqcSettings.lastDirectoryDocuments.toString().includes("initial directory"));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/qml/dialogs/tst_MpvqcDialogImportSubtitles.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | TestCase {
24 | id: testCase
25 |
26 | width: 400
27 | height: 400
28 | visible: true
29 | when: windowShown
30 | name: "MpvqcDialogImportSubtitles"
31 |
32 | Component {
33 | id: objectUnderTest
34 |
35 | MpvqcDialogImportSubtitles {
36 | id: __objectUnderTest
37 |
38 | property bool openSubtitlesCalled: false
39 |
40 | mpvqcApplication: QtObject {
41 | property var mpvqcManager: QtObject {
42 | function openSubtitles(files) {
43 | __objectUnderTest.openSubtitlesCalled = true;
44 | }
45 | }
46 | property var mpvqcSettings: QtObject {
47 | property string lastDirectorySubtitles: "initial directory"
48 | }
49 | property var supportedSubtitleFileExtensions: ["ass"]
50 | }
51 | }
52 | }
53 |
54 | function test_import() {
55 | const control = createTemporaryObject(objectUnderTest, testCase);
56 | verify(control);
57 |
58 | control.currentFolder = "some directory";
59 | control.accepted();
60 |
61 | verify(control.openSubtitlesCalled);
62 | verify(!control.mpvqcSettings.lastDirectorySubtitles.toString().includes("initial directory"));
63 | }
64 | }
65 |
--------------------------------------------------------------------------------
/qml/dialogs/tst_MpvqcDialogImportVideo.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | TestCase {
24 | id: testCase
25 |
26 | width: 400
27 | height: 400
28 | visible: true
29 | when: windowShown
30 | name: "MpvqcDialogImportVideo"
31 |
32 | Component {
33 | id: objectUnderTest
34 |
35 | MpvqcDialogImportVideo {
36 | id: __objectUnderTest
37 |
38 | property bool openVideoCalled: false
39 |
40 | mpvqcApplication: QtObject {
41 | property var mpvqcManager: QtObject {
42 | function openVideo(video) {
43 | __objectUnderTest.openVideoCalled = true;
44 | }
45 | }
46 | property var mpvqcSettings: QtObject {
47 | property string lastDirectoryVideo: "initial directory"
48 | }
49 | }
50 | }
51 | }
52 |
53 | function test_import() {
54 | const control = createTemporaryObject(objectUnderTest, testCase);
55 | verify(control);
56 |
57 | control.currentFolder = "some directory";
58 | control.accepted();
59 |
60 | verify(control.openVideoCalled);
61 | verify(!control.mpvqcSettings.lastDirectoryVideo.toString().includes("initial directory"));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/qml/footer/qmldir:
--------------------------------------------------------------------------------
1 | module footer
2 |
3 | MpvqcFooter MpvqcFooter.qml
4 |
--------------------------------------------------------------------------------
/qml/header/MpvqcSubMenuLanguage.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | pragma ComponentBehavior: Bound
21 |
22 | import QtQuick
23 | import QtQuick.Controls.Material
24 |
25 | import models
26 | import shared
27 |
28 | MpvqcMenu {
29 | id: root
30 |
31 | required property var mpvqcApplication
32 |
33 | readonly property var mpvqcSettings: mpvqcApplication.mpvqcSettings
34 |
35 | readonly property alias repeater: _repeater
36 |
37 | title: qsTranslate("MainWindow", "Language")
38 | icon.source: "qrc:/data/icons/language_black_24dp.svg"
39 | icon.height: 24
40 | icon.width: 24
41 |
42 | Repeater {
43 | id: _repeater
44 |
45 | model: MpvqcLanguageModel {}
46 |
47 | MenuItem {
48 | id: item
49 |
50 | required property string language
51 | required property string identifier
52 |
53 | property var timer: Timer {
54 | interval: 125
55 |
56 | onTriggered: {
57 | Qt.uiLanguage = item.identifier;
58 | root.mpvqcSettings.language = item.identifier;
59 | }
60 | }
61 |
62 | text: qsTranslate("Languages", item.language)
63 | autoExclusive: true
64 | checkable: true
65 | checked: item.identifier === Qt.uiLanguage
66 |
67 | function changeLanguage() {
68 | timer.start();
69 | }
70 |
71 | onTriggered: {
72 | changeLanguage();
73 | }
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/qml/header/MpvqcSubMenuSplitViewOrientation.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | import shared
24 |
25 | MpvqcMenu {
26 | id: root
27 |
28 | required property var mpvqcApplication
29 |
30 | readonly property var mpvqcSettings: mpvqcApplication.mpvqcSettings
31 |
32 | readonly property bool isVerticalLayout: mpvqcSettings.layoutOrientation === Qt.Vertical
33 |
34 | readonly property alias verticalLayout: _verticalLayout
35 | readonly property alias horizontalLayout: _horizontalLayout
36 |
37 | title: qsTranslate("MainWindow", "Application Layout")
38 | icon.source: "qrc:/data/icons/vertical_split_black_24dp.svg"
39 | icon.height: 24
40 | icon.width: 24
41 |
42 | MenuItem {
43 | id: _verticalLayout
44 |
45 | text: qsTranslate("MainWindow", "Video Above Comments")
46 | autoExclusive: true
47 | checkable: true
48 | checked: root.isVerticalLayout
49 |
50 | onTriggered: {
51 | root.mpvqcSettings.layoutOrientation = Qt.Vertical;
52 | }
53 | }
54 |
55 | MenuItem {
56 | id: _horizontalLayout
57 |
58 | text: qsTranslate("MainWindow", "Video Next to Comments")
59 | autoExclusive: true
60 | checkable: true
61 | checked: !root.isVerticalLayout
62 |
63 | onTriggered: {
64 | root.mpvqcSettings.layoutOrientation = Qt.Horizontal;
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/qml/header/qmldir:
--------------------------------------------------------------------------------
1 | module header
2 |
3 | MpvqcHeader MpvqcHeader.qml
4 |
--------------------------------------------------------------------------------
/qml/header/tst_MpvqcSubMenuWindowTitle.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | import settings
24 |
25 | TestCase {
26 | id: testCase
27 |
28 | width: 400
29 | height: 400
30 | visible: true
31 | when: windowShown
32 | name: "MpvqcSubMenuWindowTitle"
33 |
34 | Component {
35 | id: objectUnderTest
36 |
37 | MpvqcSubMenuWindowTitle {
38 | mpvqcApplication: QtObject {
39 | property var mpvqcSettings: QtObject {
40 | property var windowTitleFormat: MpvqcSettings.WindowTitleFormat.DEFAULT
41 | }
42 | }
43 | }
44 | }
45 |
46 | function test_selection() {
47 | const control = createTemporaryObject(objectUnderTest, testCase);
48 | verify(control);
49 |
50 | control.defaultFormat.triggered();
51 | compare(control.mpvqcApplication.mpvqcSettings.windowTitleFormat, MpvqcSettings.WindowTitleFormat.DEFAULT);
52 | verify(!control.fileNameFormat.checked);
53 | verify(!control.filePathFormat.checked);
54 |
55 | control.fileNameFormat.triggered();
56 | compare(control.mpvqcApplication.mpvqcSettings.windowTitleFormat, MpvqcSettings.WindowTitleFormat.FILE_NAME);
57 | verify(!control.defaultFormat.checked);
58 | verify(!control.filePathFormat.checked);
59 |
60 | control.filePathFormat.triggered();
61 | compare(control.mpvqcApplication.mpvqcSettings.windowTitleFormat, MpvqcSettings.WindowTitleFormat.FILE_PATH);
62 | verify(!control.defaultFormat.checked);
63 | verify(!control.fileNameFormat.checked);
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/qml/models/MpvqcArtworkModel.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 |
22 | ListModel {
23 | ListElement {
24 | name: "maleunam"
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/qml/models/MpvqcDeveloperModel.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 |
22 | ListModel {
23 | ListElement {
24 | name: "Elias Müller"
25 | }
26 | ListElement {
27 | name: "Frechdachs"
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/qml/models/MpvqcLanguageModel.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 |
22 | ListModel {
23 | readonly property string systemLanguage: {
24 | const uiLanguages = Qt.locale().uiLanguages;
25 | return _identifiers().find(language => uiLanguages.includes(language)) ?? "en-US";
26 | }
27 |
28 | function _identifiers(): list {
29 | const marshalled = [];
30 | for (let i = 0; i < count; i++) {
31 | marshalled.push(get(i).identifier);
32 | }
33 | return marshalled;
34 | }
35 |
36 | ListElement {
37 | language: QT_TRANSLATE_NOOP("Languages", "German")
38 | identifier: "de-DE"
39 | }
40 | ListElement {
41 | language: QT_TRANSLATE_NOOP("Languages", "English")
42 | identifier: "en-US"
43 | }
44 | ListElement {
45 | language: QT_TRANSLATE_NOOP("Languages", "Spanish")
46 | identifier: "es-MX"
47 | translator: "CiferrC"
48 | }
49 | ListElement {
50 | language: QT_TRANSLATE_NOOP("Languages", "Hebrew")
51 | identifier: "he-IL"
52 | translator: "cN3rd"
53 | }
54 | ListElement {
55 | language: QT_TRANSLATE_NOOP("Languages", "Italian")
56 | identifier: "it-IT"
57 | translator: "maddo"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/qml/models/MpvqcLibraryModel.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 |
22 | ListModel {
23 | ListElement {
24 | name: "inject"
25 | url: "https://github.com/ivankorobkov/python-inject"
26 | licence: "Apache-2.0"
27 | version: "@@pypi-inject@@"
28 | os: "linux, windows"
29 | }
30 | ListElement {
31 | name: "jinja2"
32 | url: "https://github.com/pallets/jinja/"
33 | licence: "BSD-3-Clause"
34 | version: "@@pypi-jinja2@@"
35 | os: "linux, windows"
36 | }
37 | ListElement {
38 | name: "python-mpv"
39 | url: "https://github.com/jaseg/python-mpv"
40 | licence: "GPL-3.0"
41 | version: "@@pypi-mpv@@"
42 | os: "linux, windows"
43 | }
44 | ListElement {
45 | name: "PySide6"
46 | url: "https://wiki.qt.io/Qt_for_Python"
47 | licence: "LGPL-3.0"
48 | version: "@@pypi-pyside6-essentials@@"
49 | os: "linux, windows"
50 | }
51 | ListElement {
52 | name: "pywin32"
53 | url: "https://github.com/mhammond/pywin32"
54 | licence: "PSF"
55 | version: "@@pypi-pywin32@@"
56 | os: "windows"
57 | }
58 | ListElement {
59 | name: "pytest"
60 | url: "https://github.com/pytest-dev/pytest"
61 | licence: "MIT"
62 | version: "@@pypi-pytest@@"
63 | os: "linux, windows"
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/qml/models/qmldir:
--------------------------------------------------------------------------------
1 | module models
2 | MpvqcArtworkModel MpvqcArtworkModel.qml
3 | MpvqcLibraryModel MpvqcLibraryModel.qml
4 | MpvqcDeveloperModel MpvqcDeveloperModel.qml
5 | MpvqcLanguageModel MpvqcLanguageModel.qml
6 |
--------------------------------------------------------------------------------
/qml/player/MpvqcPlayerLinux.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 |
22 | import pyobjects
23 | import shared
24 |
25 |
26 | MpvqcMpvFrameBufferObjectPyObject {
27 | id: root
28 |
29 | required property var mpvqcApplication
30 |
31 | readonly property var mpvqcNewCommentMenu: mpvqcApplication.mpvqcNewCommentMenu
32 |
33 | MpvqcPlayerMouseArea {
34 | mpvqcApplication: root.mpvqcApplication
35 | anchors.fill: root
36 |
37 | onRightMouseButtonPressed: {
38 | root.mpvqcNewCommentMenu.popupMenu()
39 | }
40 | }
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/qml/player/MpvqcPlayerWindows.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 |
22 | import pyobjects
23 | import shared
24 |
25 |
26 | WindowContainer {
27 | id: root
28 |
29 | required property var mpvqcApplication
30 |
31 | readonly property var mpvqcNewCommentMenu: mpvqcApplication.mpvqcNewCommentMenu
32 |
33 | window: MpvWindowPyObject {
34 | flags: Qt.FramelessWindowHint | Qt.WindowDoesNotAcceptFocus | Qt.WindowTransparentForInput
35 | color: "black"
36 | }
37 |
38 | MpvqcPlayerMouseArea {
39 | mpvqcApplication: root.mpvqcApplication
40 | anchors.fill: root
41 |
42 | onRightMouseButtonPressed: {
43 | root.mpvqcNewCommentMenu.popupMenu()
44 | }
45 |
46 | onPressed: {
47 | root.mpvqcApplication.requestActivate()
48 | }
49 | }
50 |
51 | }
52 |
--------------------------------------------------------------------------------
/qml/player/qmldir:
--------------------------------------------------------------------------------
1 | module player
2 |
3 | MpvqcPlayerLinux MpvqcPlayerLinux.qml
4 | MpvqcPlayerWindows MpvqcPlayerWindows.qml
5 |
--------------------------------------------------------------------------------
/qml/settings/qmldir:
--------------------------------------------------------------------------------
1 | module settings
2 |
3 | MpvqcSettings MpvqcSettings.qml
4 |
--------------------------------------------------------------------------------
/qml/shared/MpvqcDebugRectangle.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 |
22 | Rectangle {
23 | property var fill: parent
24 |
25 | anchors.fill: fill
26 | z: 10
27 | color: "transparent"
28 | border.color: "black"
29 | border.width: 1
30 | }
31 |
--------------------------------------------------------------------------------
/qml/shared/MpvqcDialog.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | pragma ComponentBehavior: Bound
21 |
22 | import QtQuick
23 | import QtQuick.Controls.Material
24 | import QtQuick.Layouts
25 |
26 | Dialog {
27 | id: root
28 |
29 | required property var mpvqcApplication
30 |
31 | property alias bar: _bar
32 | property alias stack: _stack
33 |
34 | default property alias content: _stack.children
35 |
36 | popupType: Qt.platform.os === "windows" ? Popup.Window : Popup.Item
37 | anchors.centerIn: parent
38 | parent: mpvqcApplication.contentItem
39 | contentWidth: 370
40 | contentHeight: 450
41 | modal: true
42 | dim: false
43 | z: 2
44 | closePolicy: Popup.CloseOnEscape
45 | standardButtons: Dialog.Ok
46 |
47 | contentItem: ColumnLayout {
48 | id: _layout
49 |
50 | TabBar {
51 | id: _bar
52 | contentWidth: _layout.width
53 |
54 | Repeater {
55 | model: root.content.length
56 |
57 | delegate: TabButton {
58 | required property int index
59 |
60 | text: root.content[index].title
61 | }
62 | }
63 | }
64 |
65 | StackLayout {
66 | id: _stack
67 | currentIndex: _bar.currentIndex
68 | }
69 | }
70 |
71 | onClosed: {
72 | root.bar.currentIndex = 0;
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/qml/shared/MpvqcHeader.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | Label {
24 |
25 | font.weight: Font.DemiBold
26 | font.pointSize: 14
27 | horizontalAlignment: Text.AlignHCenter
28 | topPadding: 15
29 | bottomPadding: 10
30 | }
31 |
--------------------------------------------------------------------------------
/qml/shared/MpvqcMenu.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | Menu {
24 |
25 | readonly property bool mMirrored: count > 0 && itemAt(0).mirrored
26 |
27 | z: 2
28 | x: mMirrored ? -width + parent.width : 0
29 | popupType: Qt.platform.os === "windows" ? Popup.Window : Popup.Item
30 | dim: false
31 |
32 | width: calculateMenuWidths()
33 |
34 | function calculateMenuWidths(): int {
35 | // Adapted from: https://martin.rpdev.net/2018/03/13/qt-quick-controls-2-automatically-set-the-width-of-menus.html
36 | let result = 0;
37 | let padding = 0;
38 | for (let i = 0; i < count; ++i) {
39 | let item = itemAt(i);
40 |
41 | if (!isMenuSeparator(item)) {
42 | result = Math.max(item.contentItem.implicitWidth, result);
43 | padding = Math.max(item.padding, padding);
44 | }
45 | }
46 | return (result + padding * 2) * 1.03;
47 | }
48 |
49 | function isMenuSeparator(item: Item): bool {
50 | return item instanceof MenuSeparator;
51 | }
52 |
53 | // *********************************************************
54 | // fixme: Workaround QTBUG-131786 to fake modal behavior on Windows
55 | onAboutToShow: enableFakeModal();
56 | onAboutToHide: disableFakeModal();
57 | // *********************************************************
58 | }
59 |
--------------------------------------------------------------------------------
/qml/shared/MpvqcMessageBox.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | Dialog {
24 | id: root
25 |
26 | required property var mpvqcApplication
27 |
28 | property alias text: _content.text
29 |
30 | popupType: Qt.platform.os === "windows" ? Popup.Window : Popup.Item
31 | width: 420
32 | z: 2
33 | parent: mpvqcApplication.contentItem
34 | standardButtons: Dialog.Ok
35 | closePolicy: Popup.CloseOnEscape
36 | anchors.centerIn: parent
37 | dim: false
38 |
39 | contentItem: Label {
40 | id: _content
41 |
42 | horizontalAlignment: Text.AlignLeft
43 | wrapMode: Label.WordWrap
44 | elide: Text.ElideLeft
45 | }
46 |
47 | footer: MpvqcKeyboardFocusableButtonBox {}
48 | }
49 |
--------------------------------------------------------------------------------
/qml/shared/MpvqcSpinBoxRow.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 | import QtQuick.Layouts
23 |
24 | RowLayout {
25 | id: root
26 |
27 | required property int prefWidth
28 |
29 | property int spinBoxWidth: 130
30 |
31 | property alias spinBox: _input
32 | property alias label: _label.text
33 | property alias suffix: _suffix.text
34 | property alias value: _input.value
35 | property alias valueFrom: _input.from
36 | property alias valueTo: _input.to
37 |
38 | signal valueModified(int value)
39 |
40 | Label {
41 | id: _label
42 |
43 | horizontalAlignment: Text.AlignRight
44 | wrapMode: Text.Wrap
45 | Layout.preferredWidth: root.prefWidth / 2
46 | }
47 |
48 | ColumnLayout {
49 | Layout.fillWidth: true
50 | Layout.leftMargin: 10
51 | Layout.topMargin: 20
52 |
53 | SpinBox {
54 | id: _input
55 | editable: true
56 | Layout.preferredWidth: root.spinBoxWidth
57 |
58 | onValueChanged: {
59 | root.valueModified(value);
60 | }
61 | }
62 |
63 | Label {
64 | id: _suffix
65 | horizontalAlignment: Text.AlignHCenter
66 | Layout.preferredWidth: root.spinBoxWidth
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/qml/shared/MpvqcSwitchRow.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 | import QtQuick.Layouts
23 |
24 | RowLayout {
25 | id: root
26 |
27 | required property int prefWidth
28 |
29 | property alias toggle: _switch
30 | property alias checked: _switch.checked
31 | property alias label: _label.text
32 |
33 | signal toggled(bool checked)
34 |
35 | Label {
36 | id: _label
37 |
38 | horizontalAlignment: Text.AlignRight
39 | wrapMode: Text.Wrap
40 | Layout.preferredWidth: root.prefWidth / 2
41 | }
42 |
43 | Switch {
44 | id: _switch
45 |
46 | onCheckedChanged: {
47 | root.toggled(checked);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/qml/shared/MpvqcTextFieldRow.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 | import QtQuick.Layouts
23 |
24 | RowLayout {
25 | id: root
26 |
27 | required property int prefWidth
28 |
29 | property alias label: _label.text
30 | property alias input: _textField.text
31 | property alias fontWeight: _textField.font.weight
32 | property alias implicitTextFieldWidth: _textField.implicitWidth
33 |
34 | signal textChanged(string text)
35 |
36 | Label {
37 | id: _label
38 |
39 | horizontalAlignment: Text.AlignRight
40 | wrapMode: Text.Wrap
41 | Layout.preferredWidth: root.prefWidth / 2
42 | }
43 |
44 | TextField {
45 | id: _textField
46 |
47 | focus: true
48 | selectByMouse: true
49 | bottomPadding: topPadding
50 | horizontalAlignment: Text.AlignLeft
51 |
52 | onTextChanged: {
53 | root.textChanged(text);
54 | }
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/qml/shared/qmldir:
--------------------------------------------------------------------------------
1 | module shared
2 |
3 | MpvqcDebugRectangle MpvqcDebugRectangle.qml
4 | MpvqcDialog MpvqcDialog.qml
5 | MpvqcHeader MpvqcHeader.qml
6 | MpvqcMenu MpvqcMenu.qml
7 | MpvqcMessageBox MpvqcMessageBox.qml
8 | MpvqcNewCommentMenu MpvqcNewCommentMenu.qml
9 | MpvqcSpinBoxRow MpvqcSpinBoxRow.qml
10 | MpvqcSwitchRow MpvqcSwitchRow.qml
11 | MpvqcTextFieldRow MpvqcTextFieldRow.qml
12 |
--------------------------------------------------------------------------------
/qml/shared/tst_MpvqcMenu.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 | import QtTest
23 |
24 | Item {
25 |
26 | MpvqcMenu {
27 | id: objectUnderTest1
28 |
29 | Action {
30 | text: "Short text"
31 | }
32 | }
33 |
34 | MpvqcMenu {
35 | id: objectUnderTest2
36 |
37 | Action {
38 | text: "Short text"
39 | }
40 | MenuSeparator {}
41 | }
42 |
43 | MpvqcMenu {
44 | id: objectUnderTest3
45 |
46 | Action {
47 | text: "Very very long text so that we can compare"
48 | }
49 | }
50 |
51 | TestCase {
52 | name: "MpvqcMenu"
53 |
54 | function test_width_data() {
55 | return [
56 | {
57 | tag: "same",
58 | equals: "equals",
59 | obj1: objectUnderTest1,
60 | obj2: objectUnderTest2
61 | },
62 | {
63 | tag: "different",
64 | obj1: objectUnderTest1,
65 | obj2: objectUnderTest3
66 | },
67 | ];
68 | }
69 |
70 | function test_width(data) {
71 | if (data.equals) {
72 | verify(data.obj1.width === data.obj2.width);
73 | } else {
74 | verify(data.obj1.width < data.obj2.width);
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/qml/shared/tst_MpvqcSpinBoxRow.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | Item {
24 | id: testHelper
25 |
26 | width: 400
27 | height: 400
28 |
29 | MpvqcSpinBoxRow {
30 | id: objectUnderTest
31 |
32 | prefWidth: testHelper.width
33 | valueFrom: 15
34 | value: 30
35 | valueTo: 45
36 |
37 | property int newValue: -1
38 |
39 | onValueModified: value => {
40 | objectUnderTest.newValue = value;
41 | }
42 |
43 | TestCase {
44 | name: "MpvqcSpinBoxRow"
45 | when: windowShown
46 |
47 | SignalSpy {
48 | id: valueModifiedSpy
49 | target: objectUnderTest
50 | signalName: "valueModified"
51 | }
52 |
53 | function init() {
54 | valueModifiedSpy.clear();
55 | objectUnderTest.newValue = -1;
56 | }
57 |
58 | function test_spinBox_data() {
59 | return [
60 | {
61 | tag: "increase",
62 | value: 31,
63 | exec: () => {
64 | objectUnderTest.spinBox.increase();
65 | }
66 | },
67 | ];
68 | }
69 |
70 | function test_spinBox(data) {
71 | data.exec();
72 | compare(objectUnderTest.newValue, data.value);
73 | compare(valueModifiedSpy.count, 1);
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/qml/shared/tst_MpvqcSwitchRow.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | Item {
24 | id: testHelper
25 |
26 | width: 400
27 | height: 400
28 |
29 | MpvqcSwitchRow {
30 | id: objectUnderTest
31 |
32 | property bool newChecked: false
33 |
34 | prefWidth: testHelper.width
35 |
36 | onCheckedChanged: {
37 | objectUnderTest.newChecked = checked;
38 | }
39 |
40 | TestCase {
41 | name: "MpvqcSwitchRow"
42 | when: windowShown
43 |
44 | SignalSpy {
45 | id: toggledSpy
46 | target: objectUnderTest
47 | signalName: "toggled"
48 | }
49 |
50 | function init() {
51 | objectUnderTest.newChecked = false;
52 | toggledSpy.clear();
53 | }
54 |
55 | function test_toggle() {
56 | verify(!objectUnderTest.checked);
57 |
58 | mouseClick(objectUnderTest.toggle);
59 | compare(toggledSpy.count, 1);
60 | verify(objectUnderTest.checked);
61 |
62 | mouseClick(objectUnderTest.toggle);
63 | compare(toggledSpy.count, 2);
64 | verify(!objectUnderTest.checked);
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/qml/shared/tst_MpvqcTextFieldRow.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtTest
22 |
23 | Item {
24 | id: testHelper
25 |
26 | width: 400
27 | height: 400
28 |
29 | MpvqcTextFieldRow {
30 | id: objectUnderTest
31 |
32 | property string newText: ''
33 |
34 | prefWidth: testHelper.width
35 |
36 | onTextChanged: text => {
37 | objectUnderTest.newText = text;
38 | }
39 |
40 | TestCase {
41 | name: "MpvqcTextFieldRow"
42 |
43 | SignalSpy {
44 | id: textChangedSpy
45 | target: objectUnderTest
46 | signalName: "textChanged"
47 | }
48 |
49 | function init() {
50 | objectUnderTest.newText = '';
51 | textChangedSpy.clear();
52 | }
53 |
54 | function test_text() {
55 | const firstText = "abc";
56 | const secondText = "def";
57 |
58 | objectUnderTest.input = firstText;
59 | verify(objectUnderTest.newText, firstText);
60 | compare(textChangedSpy.count, 1);
61 |
62 | objectUnderTest.input = secondText;
63 | verify(objectUnderTest.newText, secondText);
64 | compare(textChangedSpy.count, 2);
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/qml/table/MpvqcCommentHighlighter.js:
--------------------------------------------------------------------------------
1 | /*
2 | https://github.com/tc39/proposal-regex-escaping
3 | */
4 |
5 | /**
6 | *
7 | * @param comment {string}
8 | * @param highlightedText {string}
9 | * @returns {string}
10 | */
11 | function highlightComment(comment, highlightedText) {
12 | const re = new RegExp(RegExp.escape(highlightedText), "gi")
13 | return comment.replace(re, "$&")
14 | }
15 |
16 | // this is a direct translation to code of the spec
17 | if (!RegExp.escape) {
18 | RegExp.escape = S => {
19 | // 1. let str be ToString(S).
20 | // 2. ReturnIfAbrupt(str).
21 | let str = String(S)
22 | // 3. Let cpList be a List containing in order the code
23 | // points as defined in 6.1.4 of str, starting at the first element of str.
24 | let cpList = Array.from(str[Symbol.iterator]())
25 | // 4. let cuList be a new List
26 | let cuList = []
27 | // 5. For each code point c in cpList in List order, do:
28 | for (let c of cpList) {
29 | // i. If c is a SyntaxCharacter then do:
30 | if ("^$\\.*+?()[]{}|".indexOf(c) !== -1) {
31 | // a. Append "\" to cuList.
32 | cuList.push("\\")
33 | }
34 | // Append c to cpList.
35 | cuList.push(c)
36 | }
37 | // 7. Return a String whose elements are, in order, the elements of cuList.
38 | return cuList.join("")
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/qml/table/MpvqcContextMenu.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick
21 | import QtQuick.Controls.Material
22 |
23 | import "../shared"
24 |
25 | MpvqcMenu {
26 | id: root
27 |
28 | required property int currentListIndex
29 | required property point openedAt
30 |
31 | signal copyCommentClicked(index: int)
32 | signal deleteCommentClicked(index: int)
33 | signal editCommentClicked(index: int)
34 |
35 | modal: true
36 |
37 | x: root.mirrored ? openedAt.x - width : openedAt.x
38 | y: openedAt.y
39 |
40 | MenuItem {
41 | id: _editItem
42 |
43 | //: Context menu on right click in comments table
44 | text: qsTranslate("CommentTable", "Edit Comment")
45 | icon.source: "qrc:/data/icons/edit_black_24dp.svg"
46 |
47 | onTriggered: {
48 | root.exit = null;
49 | root.editCommentClicked(root.currentListIndex);
50 | }
51 | }
52 |
53 | MenuItem {
54 | id: _copyItem
55 |
56 | //: Context menu on right click in comments table
57 | text: qsTranslate("CommentTable", "Copy Comment")
58 | icon.source: "qrc:/data/icons/content_copy_black_24dp.svg"
59 |
60 | onTriggered: root.copyCommentClicked(root.currentListIndex)
61 | }
62 |
63 | MenuItem {
64 | id: _deleteItem
65 |
66 | //: Context menu on right click in comments table
67 | text: qsTranslate("CommentTable", "Delete Comment")
68 | icon.source: "qrc:/data/icons/delete_black_24dp.svg"
69 |
70 | onTriggered: root.deleteCommentClicked(root.currentListIndex)
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/qml/table/MpvqcDeleteCommentMessageBox.qml:
--------------------------------------------------------------------------------
1 | /*
2 | mpvQC
3 |
4 | Copyright (C) 2022 mpvQC developers
5 |
6 | This program is free software: you can redistribute it and/or modify
7 | it under the terms of the GNU General Public License as published by
8 | the Free Software Foundation, either version 3 of the License, or
9 | (at your option) any later version.
10 |
11 | This program is distributed in the hope that it will be useful,
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 | GNU General Public License for more details.
15 |
16 | You should have received a copy of the GNU General Public License
17 | along with this program. If not, see .
18 | */
19 |
20 | import QtQuick.Controls.Material
21 |
22 | import "../shared"
23 |
24 | MpvqcMessageBox {
25 | id: root
26 |
27 | required property int commentIndex
28 |
29 | signal deleteCommentConfirmed(index: int)
30 |
31 | title: qsTranslate("MessageBoxes", "Delete Comment")
32 | text: qsTranslate("MessageBoxes", "Do you really want to delete this comment?")
33 | standardButtons: Dialog.Yes | Dialog.Cancel
34 |
35 | onAccepted: {
36 | root.deleteCommentConfirmed(root.commentIndex);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/qml/table/qmldir:
--------------------------------------------------------------------------------
1 | module table
2 |
3 | MpvqcTable MpvqcTable.qml
4 |
--------------------------------------------------------------------------------
/test/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 |
19 | def add_repository_root_to_path():
20 | import os
21 | from pathlib import Path
22 |
23 | os.environ["PATH"] = str(Path(__file__).parent.parent.absolute()) + os.pathsep + os.environ["PATH"]
24 |
25 |
26 | add_repository_root_to_path()
27 |
--------------------------------------------------------------------------------
/test/conftest.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2025 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from collections.abc import Generator
19 | from importlib.util import find_spec
20 | from typing import Any
21 |
22 | import pytest
23 |
24 | from mpvqc.application import MpvqcApplication
25 | from mpvqc.services import TypeMapperService
26 |
27 |
28 | @pytest.fixture(scope="session", autouse=True)
29 | def check_generated_resources():
30 | if find_spec("test.generated_resources") is None:
31 | message = (
32 | "Can not find resource module 'test.generated_resources'\n"
33 | "To execute individual tests, please run 'just test-python' once before"
34 | )
35 | raise FileNotFoundError(message)
36 | import test.generated_resources # noqa: F401
37 |
38 |
39 | @pytest.fixture(scope="session")
40 | def type_mapper() -> TypeMapperService:
41 | return TypeMapperService()
42 |
43 |
44 | @pytest.fixture(scope="session")
45 | def qt_app() -> Generator[MpvqcApplication, Any]:
46 | app = MpvqcApplication([])
47 | yield app
48 | app.shutdown()
49 |
--------------------------------------------------------------------------------
/test/mocks.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from PySide6.QtCore import QObject, QUrl, Signal
19 |
20 |
21 | class MockedMessageBox(QObject):
22 | accepted = Signal()
23 | rejected = Signal()
24 | closed = Signal()
25 |
26 | def open(self):
27 | pass
28 |
29 |
30 | class MockedDialog(QObject):
31 | accepted = Signal()
32 | rejected = Signal()
33 | savePressed = Signal(QUrl)
34 |
35 | def __init__(self):
36 | super().__init__()
37 | self.openCalled = False
38 |
39 | def open(self):
40 | self.openCalled = True
41 |
--------------------------------------------------------------------------------
/test/pyobjects/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
--------------------------------------------------------------------------------
/test/pyobjects/comment_model/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
--------------------------------------------------------------------------------
/test/pyobjects/comment_model/test_clipboard.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import pytest
19 | from PySide6.QtGui import QClipboard
20 |
21 | from mpvqc.models import Comment
22 |
23 |
24 | @pytest.fixture(scope="session")
25 | def clipboard(qt_app) -> QClipboard:
26 | return qt_app.clipboard()
27 |
28 |
29 | def test_copy_to_clipboard(make_model, clipboard):
30 | # noinspection PyArgumentList
31 | model, _ = make_model(
32 | set_comments=[
33 | Comment(time=100, comment_type="Phrasing", comment="Comment Content 1"),
34 | Comment(time=200, comment_type="Translation", comment="Comment Content 2"),
35 | Comment(time=300, comment_type="Spelling", comment="Comment Content 3"),
36 | ],
37 | set_player_time=0,
38 | )
39 |
40 | model.copy_to_clipboard(0)
41 | assert clipboard.text() == "[00:01:40] [Phrasing] Comment Content 1"
42 |
43 | model.copy_to_clipboard(1)
44 | assert clipboard.text() == "[00:03:20] [Translation] Comment Content 2"
45 |
46 | model.copy_to_clipboard(2)
47 | assert clipboard.text() == "[00:05:00] [Spelling] Comment Content 3"
48 |
--------------------------------------------------------------------------------
/test/pyobjects/comment_model/test_get_all.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import pytest
19 |
20 | from mpvqc.models import Comment
21 |
22 | DEFAULT_COMMENTS = [
23 | Comment(time=0, comment_type="commentType", comment="Word 1"),
24 | Comment(time=5, comment_type="commentType", comment="Word 2"),
25 | Comment(time=10, comment_type="commentType", comment="Word 3"),
26 | Comment(time=15, comment_type="commentType", comment="Word 4"),
27 | Comment(time=20, comment_type="commentType", comment="Word 5"),
28 | ]
29 |
30 |
31 | @pytest.fixture
32 | def model(make_model):
33 | # noinspection PyArgumentList
34 | model, _ = make_model(
35 | set_comments=DEFAULT_COMMENTS,
36 | set_player_time=0,
37 | )
38 | return model
39 |
40 |
41 | def test_get_all_comments(model):
42 | actual = [
43 | Comment(time=comment["time"], comment_type=comment["commentType"], comment=comment["comment"])
44 | for comment in model.comments()
45 | ]
46 |
47 | assert actual == DEFAULT_COMMENTS
48 |
--------------------------------------------------------------------------------
/test/pyobjects/manager/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
--------------------------------------------------------------------------------
/test/pyobjects/test_export_templates_model.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from pathlib import Path
19 | from unittest.mock import MagicMock
20 |
21 | import inject
22 |
23 | from mpvqc.pyobjects.export_template_model import MpvqcExportTemplateModelPyObject, Role
24 | from mpvqc.services import ApplicationPathsService
25 |
26 |
27 | def make_model(mocked_paths: tuple[Path, ...]) -> MpvqcExportTemplateModelPyObject:
28 | mock = MagicMock()
29 | mock.files_export_templates = mocked_paths
30 |
31 | def config(binder: inject.Binder):
32 | binder.bind(ApplicationPathsService, mock)
33 |
34 | inject.configure(config, clear=True)
35 | # noinspection PyCallingNonCallable
36 | return MpvqcExportTemplateModelPyObject()
37 |
38 |
39 | def test_no_templates():
40 | model = make_model(mocked_paths=())
41 | assert model.rowCount() == 0
42 |
43 |
44 | def test_templates():
45 | model = make_model(mocked_paths=(Path.home(), Path.cwd()))
46 | assert model.rowCount() == 2
47 |
48 |
49 | def test_templates_sorted():
50 | model = make_model(
51 | mocked_paths=(
52 | Path("/xy"),
53 | Path("/z"),
54 | Path("/a"),
55 | Path("/b"),
56 | )
57 | )
58 |
59 | expected = ["a", "b", "xy", "z"]
60 | actual = [
61 | model.item(0, 0).data(Role.NAME),
62 | model.item(1, 0).data(Role.NAME),
63 | model.item(2, 0).data(Role.NAME),
64 | model.item(3, 0).data(Role.NAME),
65 | ]
66 | assert actual == expected
67 |
--------------------------------------------------------------------------------
/test/services/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
--------------------------------------------------------------------------------
/test/services/test_font_loader.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from PySide6.QtCore import QFile
19 | from PySide6.QtGui import QFontDatabase
20 |
21 | from mpvqc.services import FontLoaderService
22 |
23 |
24 | def test_fonts_present_in_resources(qt_app):
25 | variants = [
26 | "NotoSans-Regular.ttf",
27 | "NotoSans-Italic.ttf",
28 | "NotoSans-Bold.ttf",
29 | "NotoSans-SemiBold.ttf",
30 | "NotoSansHebrew-Bold.ttf",
31 | "NotoSansHebrew-Regular.ttf",
32 | "NotoSansHebrew-SemiBold.ttf",
33 | "NotoSansMono-Regular.ttf",
34 | ]
35 | for variant in variants:
36 | file = QFile(f":/data/fonts/{variant}")
37 | assert file.exists(), f"Expected to find {variant} in resources but couldn't"
38 |
39 |
40 | def test_fonts_loaded(qt_app):
41 | # It's not possible to clear Qt's entire font database. Additionally, font backends on different OS's behave
42 | # differently. Therefore, we just test for the common font families.
43 | verifiable_font_families = [
44 | "Noto Sans",
45 | "Noto Sans Hebrew",
46 | "Noto Sans Mono",
47 | ]
48 |
49 | FontLoaderService().load_application_fonts()
50 | loaded_font_families = QFontDatabase.families()
51 |
52 | for font_family in verifiable_font_families:
53 | assert font_family in loaded_font_families, (
54 | f"Cannot find font family '{font_family}' in loaded font families {loaded_font_families}"
55 | )
56 |
--------------------------------------------------------------------------------
/test/services/test_formatter_time.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import pytest
19 |
20 | from mpvqc.services import TimeFormatterService
21 |
22 |
23 | @pytest.fixture(scope="module")
24 | def service():
25 | return TimeFormatterService()
26 |
27 |
28 | @pytest.mark.parametrize(
29 | ("expected", "input_seconds"),
30 | [
31 | ("00:00:00", 0),
32 | ("00:01:08", 68),
33 | ("00:16:39", 999),
34 | ("02:46:40", 10000),
35 | ],
36 | )
37 | def test_format_time_to_string_long(service, expected, input_seconds):
38 | actual = service.format_time_to_string(input_seconds, long_format=True)
39 | assert expected == actual
40 |
41 |
42 | @pytest.mark.parametrize(
43 | ("expected", "input_seconds"),
44 | [
45 | ("00:00", 0),
46 | ("01:08", 68),
47 | ("16:39", 999),
48 | ],
49 | )
50 | def test_format_time_to_string_short(service, expected, input_seconds):
51 | actual = service.format_time_to_string(input_seconds, long_format=False)
52 | assert expected == actual
53 |
--------------------------------------------------------------------------------
/test/services/test_resource_reader.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | from unittest.mock import patch
19 |
20 | import pytest
21 |
22 | from mpvqc.services import ResourceReaderService
23 |
24 |
25 | @pytest.fixture(scope="module")
26 | def service() -> ResourceReaderService:
27 | return ResourceReaderService()
28 |
29 |
30 | @pytest.mark.parametrize(
31 | "file_path",
32 | [
33 | ":/data/icon.svg",
34 | "/data/icon.svg",
35 | "data/icon.svg",
36 | ],
37 | )
38 | def test_read_from(service, file_path):
39 | assert service.read_from(file_path).startswith(">")
45 |
46 | module = "mpvqc.services.resource_reader"
47 |
48 | with (
49 | patch(f"{module}.QFile.exists", return_value=True),
50 | patch(f"{module}.QFile.open", return_value=False),
51 | pytest.raises(ValueError), # noqa: PT011
52 | ):
53 | service.read_from("")
54 |
--------------------------------------------------------------------------------
/test/services/test_reverse_translator.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2022 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import pytest
19 |
20 | from mpvqc.services import ReverseTranslatorService
21 |
22 |
23 | @pytest.fixture
24 | def service() -> ReverseTranslatorService:
25 | return ReverseTranslatorService()
26 |
27 |
28 | @pytest.mark.parametrize(
29 | ("expected", "translated"),
30 | [
31 | ("Spelling", "Spelling"),
32 | ("Spelling", "Rechtschreibung"),
33 | ("Spelling", "איות"),
34 | ("Spelling", "Typo"),
35 | ("Spelling", "Ortografía"),
36 | ("not-found", "not-found"),
37 | ],
38 | )
39 | def test_lookup2(service, expected, translated):
40 | assert expected == service.lookup(translated)
41 |
--------------------------------------------------------------------------------
/test/services/theme/__init__.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2025 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
--------------------------------------------------------------------------------
/test/services/theme/test_utils.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import pytest
19 | from PySide6.QtGui import QColor
20 |
21 | from mpvqc.services.theme.schema import ThemeParseError
22 | from mpvqc.services.theme.utils import parse_color
23 |
24 |
25 | @pytest.mark.parametrize(
26 | ("string", "expected_hex"),
27 | [
28 | ("#2e3440", "#2e3440"),
29 | ("Qt.darker #bf616a 1.3", "#934b52"),
30 | ("Qt.darker #bf616a 1.5", "#7f4147"),
31 | ("qt.Lighter #bf6 1.5", "#f4ffe5"),
32 | ("qt.lighter #bf616a 1.3", "#f87e8a"),
33 | ("Qt.lighter #bf616a 1.5", "#ffa1aa"),
34 | ],
35 | )
36 | def test_parse_color(string: str, expected_hex: str) -> None:
37 | actual = parse_color(string).name(QColor.NameFormat.HexRgb)
38 | assert expected_hex == actual
39 |
40 |
41 | @pytest.mark.parametrize(
42 | "string",
43 | [
44 | "bf616a",
45 | "Qt.darker bf616a 1.3",
46 | "Qt.lighter #bf616a",
47 | ],
48 | )
49 | def test_parse_color_errors(string: str) -> None:
50 | with pytest.raises(ThemeParseError):
51 | parse_color(string)
52 |
--------------------------------------------------------------------------------
/test/test_application.py:
--------------------------------------------------------------------------------
1 | # mpvQC
2 | #
3 | # Copyright (C) 2024 mpvQC developers
4 | #
5 | # This program is free software: you can redistribute it and/or modify
6 | # it under the terms of the GNU General Public License as published by
7 | # the Free Software Foundation, either version 3 of the License, or
8 | # (at your option) any later version.
9 | #
10 | # This program is distributed in the hope that it will be useful,
11 | # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 | # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 | # GNU General Public License for more details.
14 | #
15 | # You should have received a copy of the GNU General Public License
16 | # along with this program. If not, see .
17 |
18 | import pytest
19 | from PySide6.QtCore import QObject, QUrl
20 |
21 | QML = """
22 | import QtQuick
23 | import QtQuick.Controls
24 |
25 | ApplicationWindow {
26 | visible: false; width: 50; height: 50
27 |
28 | Button { objectName: "button-click-me"; text: "Click Me" }
29 | }
30 | """
31 |
32 |
33 | def test_find_object(qt_app):
34 | qt_app._engine.loadData(QML.encode(), QUrl())
35 | obj = qt_app.find_object(QObject, "button-click-me")
36 | assert obj
37 |
38 | with pytest.raises(ValueError): # noqa: PT011
39 | qt_app.find_object(QObject, "other-button-that-does-not-exist")
40 |
--------------------------------------------------------------------------------