diff --git a/.github/actions/initialize-build-environment/action.yml b/.github/actions/initialize-build-environment/action.yml
index 18aed6d3..12e10df1 100644
--- a/.github/actions/initialize-build-environment/action.yml
+++ b/.github/actions/initialize-build-environment/action.yml
@@ -39,7 +39,7 @@ runs:
HOMEBREW_NO_INSTALL_CLEANUP: 1
run: |
brew update
- brew install ninja
+ brew install ninja ccache imagemagick create-dmg
- name: Install Qt
uses: jurplel/install-qt-action@v4
diff --git a/.github/actions/initialize-vcpkg/action.yml b/.github/actions/initialize-vcpkg/action.yml
index e19dd5ab..1d083ef5 100644
--- a/.github/actions/initialize-vcpkg/action.yml
+++ b/.github/actions/initialize-vcpkg/action.yml
@@ -31,7 +31,7 @@ runs:
QT_DIR: ${{ env.Qt_ROOT_DIR }}/lib/cmake/Qt6
Qt6_DIR: ${{ env.Qt_ROOT_DIR }}/lib/cmake/Qt6
VCPKG_CMAKE_RELEASE_BUILD_TYPE: "RelWithDebInfo"
- VCPKG_KEEP_ENV_VARS: "QT_DIR;Qt6_DIR;VCPKG_CMAKE_RELEASE_BUILD_TYPE;VCPKG_BUILD_TYPE"
+ VCPKG_KEEP_ENV_VARS: "QT_DIR;Qt6_DIR;VCPKG_CMAKE_RELEASE_BUILD_TYPE;VCPKG_BUILD_TYPE;MACOSX_DEPLOYMENT_TARGET"
shell: pwsh
run: |
if (!(Test-Path $env:VCPKG_DEFAULT_BINARY_CACHE)) {
diff --git a/.github/instructions/viewmodel-binding.instructions.md b/.github/instructions/viewmodel-binding.instructions.md
new file mode 100644
index 00000000..50eddd12
--- /dev/null
+++ b/.github/instructions/viewmodel-binding.instructions.md
@@ -0,0 +1,103 @@
+# View-Model ↔ Document Binding Prompt
+
+Use this prompt to guide new view-model bindings for future document elements. Keep property specifics out; focus on state design, controller-driven transitions, transactions, and synchronization patterns. Derive patterns from existing implementations (e.g., `TrackViewModelContextData`, `LabelViewModelContextData`, `TempoViewModelContextData`).
+
+## Core Goals
+- Mirror document collections to view-model collections with clear ownership and mapping tables in both directions.
+- Drive UI interactions through controllers; never mutate document state directly from QML.
+- Guard against infinite loops by conditioning view→doc updates on active states.
+- Wrap mutating operations in transactions with start/commit/abort semantics tied to state entry/exit.
+
+- Instrument every state with entry/exit logging (use `qCInfo` with a per-context logging category) to trace flows during debugging, even for states without handlers.
+
+## State Machine Design
+- Build a `QStateMachine` with explicit states for idle, rubber-band selection, move/drag, edit/adjust flows, and per-property operations as needed.
+- Keep transitions driven by signals emitted from interaction controllers and internal guards (e.g., started/not-started, commit/abort, finish).
+- Example (move flow, list rotation):
+ - `idle` → `movePending` on `moveTransactionWillStart` (from controller).
+ - `movePending` → `moveProcessing` on `moveTransactionStarted`; → `idle` on `moveTransactionNotStarted`.
+ - `moveProcessing` → `moveCommitting` on `moveTransactionWillCommit`; → `moveAborting` on `moveTransactionWillAbort`.
+ - `moveCommitting`/`moveAborting` → `idle` (reset guards).
+- Example (edit flow, text-like):
+ - `idle` → `namePending` on `nameTransactionWillStart`.
+ - `namePending` → `nameProgressing` on `nameTransactionStarted`; → `idle` if not started.
+ - `nameProgressing` → `nameCommitting` on commit; → `nameAborting` on abort.
+ - `nameCommitting`/`nameAborting` → `idle`.
+- Rubber-band selection: `idle` → `rubberBandDragging` on start, back to `idle` on finish.
+
+## Controller-Driven Transitions
+- Wire controller signals to emit local signals that the state machine consumes (two patterns):
+ 1) **Started/Committed/Aborted**: drag/move and text edits use started/commit/abort triplets.
+ 2) **Started/Finished**: toggle/slider/height edits use started/finished pairs.
+- Set the current target item/index when the controller signals a start; clear it on commit/finish/abort handlers.
+- For rotations or list moves: only propagate view→doc when in the move-processing state; otherwise apply doc→view rotations.
+
+## Transactions
+- Begin a transaction when entering the corresponding "pending" state. Abort immediately if the controller could not start.
+- On commit states: if the new value differs, write to the document and `commitTransaction` with a descriptive label; otherwise `abortTransaction`.
+- On abort states: always `abortTransaction` and reset local guards (`target`, flags like `moveChanged`).
+- Track whether any change occurred during move/drag (`moveChanged`) to avoid committing no-op transactions.
+
+## Synchronization Patterns
+- Maintain bidirectional maps: `doc -> view` and `view -> doc`. Insert/remove bindings on collection signals (`itemInserted`/`itemRemoved`), not "aboutTo" when you need the item fully constructed.
+- When binding a new item:
+ - Create the view-model item, insert into both maps and the view-model collection at the correct index.
+ - Connect doc→view signals to update view items, guarded by equality checks.
+ - Connect view→doc signals but gate them with state checks (only honor during the relevant progressing/doing states; otherwise revert the view to the doc value).
+ - Initialize view properties from the doc model after wiring connections.
+- Selection sync: listen to document selection model `itemSelected` and mark the view item selected; initialize selection for pre-selected items after binding.
+- Rotation sync: doc→view rotations apply when *not* moving; view→doc rotations apply only while the move state is active, and should mark a change flag.
+
+## Example Snippets
+- **Doc→View guarded update** (avoid loops):
+ ```cpp
+ connect(control, &ControlType::propertyChanged, viewItem, [=](auto value) {
+ if (viewItem->property() == value) return;
+ viewItem->setProperty(value);
+ });
+ ```
+- **View→Doc gated by state**:
+ ```cpp
+ connect(viewItem, &ViewType::propertyChanged, docItem, [=] {
+ if (!stateMachine->configuration().contains(propertyProgressingState)) {
+ viewItem->setProperty(docItem->property());
+ return;
+ }
+ // defer actual write to commit handler
+ });
+ ```
+- **Transaction commit handler**:
+ ```cpp
+ void ContextData::onNameCommittingStateEntered() {
+ if (!target || nameTxId == Invalid) { target = {}; return; }
+ auto viewItem = viewMap.value(target);
+ if (viewItem->name() == target->name()) {
+ tx->abortTransaction(nameTxId);
+ } else {
+ target->setName(viewItem->name());
+ tx->commitTransaction(nameTxId, tr("Renaming item"));
+ }
+ nameTxId = {}; target = {};
+ }
+ ```
+- **Rotate handling**:
+ ```cpp
+ connect(docList, &List::rotated, this, [=](int l, int m, int r) {
+ if (stateMachine->configuration().contains(moveProcessingState)) return;
+ viewList->rotate(l, m, r);
+ });
+ connect(viewList, &ViewList::rotated, this, [=](int l, int m, int r) {
+ if (!stateMachine->configuration().contains(moveProcessingState)) return;
+ moveChanged = true;
+ docList->rotate(l, m, r);
+ });
+ ```
+
+## Implementation Checklist
+- Define states and transitions before binding to controllers; start the state machine immediately.
+- Create controllers via context helper methods; hook all relevant signals to emit local transition signals and set the current target.
+- Bind document collections first, then replay existing selection to the view.
+- For each commit/finish handler: compare values, write document, commit transaction; otherwise abort. Always reset `target` and flags.
+- Keep all strings ASCII; add concise comments only where non-obvious.
+
+Use this prompt verbatim when extending bindings to new document elements to maintain consistent interaction, transaction, and synchronization behavior across the codebase.
diff --git a/.github/workflows/dev-build.yml b/.github/workflows/dev-build.yml
index 03dca6ce..7dd6dc8c 100644
--- a/.github/workflows/dev-build.yml
+++ b/.github/workflows/dev-build.yml
@@ -16,6 +16,7 @@ on:
- 'LICENSE'
- 'crowdin.yml'
- '.github/**'
+ - '**/translations/*.ts'
workflow_dispatch:
inputs:
identifier:
@@ -40,16 +41,16 @@ jobs:
os:
- windows-2025
# - ubuntu-24.04
- # - macos-15
-
+ - macos-15
env:
- QT_VERSION: 6.9.2
+ QT_VERSION: 6.10.1
VCPKG_REF: 74e6536215718009aae747d86d84b78376bf9e09
INNOSETUP_REF: is-6_5_4
VERSION_IDENTIFIER: ${{ github.sha }}${{ github.event.inputs.identifier && '.' || '' }}${{ github.event.inputs.identifier }}
BUILD_DIR: ${{ github.workspace }}/build/build
INSTALL_DIR: ${{ github.workspace }}/build/install
CCACHE_DIR: ${{ github.workspace }}/build/ccache
+ MACOSX_DEPLOYMENT_TARGET: 13.0
runs-on: ${{ matrix.os }}
@@ -87,7 +88,10 @@ jobs:
-InstallDir $env:INSTALL_DIR `
-VersionIdentifier $env:VERSION_IDENTIFIER `
${{ github.event.inputs.use_ccache == 'true' && '-CCache' || '' }}
- Write-Output ARTIFACT_NAME=$($output.ApplicationName)_$($output.Semver -replace '[\.\-\+]', '_') >> $env:GITHUB_ENV
+ Write-Output ARTIFACT_NAME=$($output.ApplicationName)_$($output.Semver -replace '[\.\-\+]', '_')_${{ runner.os }}_${{ runner.arch }} >> $env:GITHUB_ENV
+ Write-Output APPLICATION_SEMVER=$($output.Semver) >> $env:GITHUB_ENV
+ Write-Output APPLICATION_DISPLAY_NAME=$($output.ApplicationDisplayName) >> $env:GITHUB_ENV
+ Write-Output APPLICATION_NAME=$($output.ApplicationName) >> $env:GITHUB_ENV
Write-Output INSTALLER_FILE_BASE=$($output.InstallerFileBase) >> $env:GITHUB_ENV
- name: Save CCache cache
@@ -102,11 +106,22 @@ jobs:
$output = & ./scripts/ci/Collect-Symbol-Files.ps1 -VcpkgRootDir $env:VCPKG_ROOT_DIR -InstallDir $env:INSTALL_DIR
Write-Output SYMBOL_FILES_PATH=$($output.Path) >> $env:GITHUB_ENV
- - name: Pack
+ - name: Create InnoSetup installer (Windows)
+ if: ${{ runner.os == 'Windows' }}
run: |
$output = & ./scripts/ci/Pack.ps1 -BuildDir $env:BUILD_DIR -InstallerFileBase $env:INSTALLER_FILE_BASE -InnoSetupCommit $env:INNOSETUP_REF
Write-Output PACKAGE_PATH=$($output.Path) >> $env:GITHUB_ENV
+ - name: Create DMG installer (macOS)
+ if: ${{ runner.os == 'macOS' }}
+ run: |
+ $output = & ./scripts/ci/Create-DMG.ps1 `
+ -AppPath $(Join-Path $env:INSTALL_DIR $env:APPLICATION_NAME'.app') `
+ -Semver $env:APPLICATION_SEMVER `
+ -ApplicationDisplayName $env:APPLICATION_DISPLAY_NAME `
+ -InstallerFileBase $env:INSTALLER_FILE_BASE
+ Write-Output PACKAGE_PATH=$($output) >> $env:GITHUB_ENV
+
- name: Upload symbol files
uses: actions/upload-artifact@v4
with:
diff --git a/crowdin.yml b/crowdin.yml
index 14e32c6a..35758df7 100644
--- a/crowdin.yml
+++ b/crowdin.yml
@@ -1,13 +1,5 @@
files:
- - source: /src/plugins/coreplugin/res/translations/Core_en_US.ts
- translation: /src/plugins/coreplugin/res/translations/Core_%locale_with_underscore%.ts
- - source: /src/plugins/audio/res/translations/org.diffscope.audio_en_US.ts
- translation: /src/plugins/audio/res/translations/org.diffscope.audio_%locale_with_underscore%.ts
- - source: /src/plugins/welcomewizard/res/translations/org.diffscope.welcomewizard_en_US.ts
- translation: /src/plugins/welcomewizard/res/translations/org.diffscope.welcomewizard_%locale_with_underscore%.ts
- - source: /src/plugins/achievement/res/translations/org.diffscope.achievement_en_US.ts
- translation: /src/plugins/achievement/res/translations/org.diffscope.achievement_%locale_with_underscore%.ts
- - source: /src/plugins/maintenance/res/translations/org.diffscope.maintenance_en_US.ts
- translation: /src/plugins/maintenance/res/translations/org.diffscope.maintenance_%locale_with_underscore%.ts
- - source: /src/libs/application/uishell/share/translations/uishell_en_US.ts
- translation: /src/libs/application/uishell/share/translations/uishell_%locale_with_underscore%.ts
+ - source: '/**/translations/*_en_US.ts'
+ translation: '/%original_path%/%file_name%_%locale_with_underscore%.ts'
+ translation_replace:
+ '_en_US': ''
diff --git a/scripts/ci/Build.ps1 b/scripts/ci/Build.ps1
index d7bee6de..0afa4394 100644
--- a/scripts/ci/Build.ps1
+++ b/scripts/ci/Build.ps1
@@ -78,6 +78,8 @@ Write-Host "Semver: $semver"
$installerFileBase = "${applicationName}_$($semver -replace '[\.\-\+]', '_')_installer"
+$depsDir = (Get-ChildItem -Path $(Join-Path $VcpkgRootDir installed) | Where-Object {$_.Name -ne "vcpkg"})[0].FullName
+
cmake -S . -B $(Resolve-Path $BuildDir) -G Ninja `
-DCMAKE_BUILD_TYPE=RelWithDebInfo `
"-DCMAKE_TOOLCHAIN_FILE=$(Join-Path $VcpkgRootDir scripts/buildsystems/vcpkg.cmake)" `
@@ -85,6 +87,8 @@ cmake -S . -B $(Resolve-Path $BuildDir) -G Ninja `
"-DCMAKE_CXX_COMPILER_LAUNCHER=$($CCache ? 'ccache' : '')" `
-DCMAKE_MSVC_DEBUG_INFORMATION_FORMAT=Embedded `
-DCK_ENABLE_CONSOLE:BOOL=FALSE `
+ -DQT_NO_PRIVATE_MODULE_WARNING:BOOL=ON `
+ "-DQMSETUP_APPLOCAL_DEPS_PATHS_RELWITHDEBINFO=$(Join-Path $depsDir lib)" `
-DAPPLICATION_INSTALL:BOOL=ON `
-DAPPLICATION_CONFIGURE_INSTALLER:BOOL=ON `
-DINNOSETUP_USE_UNOFFICIAL_LANGUAGE:BOOL=ON `
diff --git a/scripts/ci/Collect-Symbol-Files.ps1 b/scripts/ci/Collect-Symbol-Files.ps1
index 5c4e9206..914b3c52 100644
--- a/scripts/ci/Collect-Symbol-Files.ps1
+++ b/scripts/ci/Collect-Symbol-Files.ps1
@@ -47,6 +47,7 @@ if ($IsWindows) {
}
dsymutil $dllFile.FullName -o "$pdbTargetDirectory/$($dllFile.Name).dSYM"
strip -S $dllFile.FullName
+ codesign --force --sign - $dllFile.FullName
} else {
Write-Host "Skip: $dllFile"
}
diff --git a/scripts/ci/Create-DMG.ps1 b/scripts/ci/Create-DMG.ps1
index f46f57d3..c4dd5544 100644
--- a/scripts/ci/Create-DMG.ps1
+++ b/scripts/ci/Create-DMG.ps1
@@ -32,6 +32,8 @@ New-Item -ItemType Directory -Path $TempDir | Out-Null
$Bg1xOut = Join-Path $TempDir "dmg_background.png"
$Bg2xOut = Join-Path $TempDir "dmg_background@2x.png"
$BgTiff = Join-Path $TempDir "dmg_background.tiff"
+$AppBundleName = "$ApplicationDisplayName.app"
+$AppBundlePath = Join-Path $TempDir $AppBundleName
$VersionText = "Version $Semver"
@@ -87,16 +89,24 @@ try {
Remove-Item $DmgPath -Force
}
+ if (Test-Path $AppBundlePath) {
+ Remove-Item $AppBundlePath -Recurse -Force
+ }
+
+ Move-Item -Path $AppPath -Destination $AppBundlePath
+
+ & codesign --deep --force --sign - $AppBundlePath | Write-Host
+
<# TODO: create-dmg currently places hidden .background file to the right of the visible area, so we have to leave some space for the horizontal scroll bar #>
& create-dmg `
--volname "$ApplicationDisplayName" `
--background "$BgTiff" `
--window-size 600 448 `
--icon-size 128 `
- --icon "$(Split-Path $AppPath -Leaf)" 132 280 `
+ --icon "$(Split-Path $AppBundlePath -Leaf)" 132 280 `
--app-drop-link 468 280 `
"$DmgPath" `
- "$AppPath" | Write-Host
+ "$AppBundlePath" | Write-Host
if ($LASTEXITCODE -ne 0) {
throw "create-dmg failed"
diff --git a/scripts/vcpkg b/scripts/vcpkg
index 5e0443fe..6fb07583 160000
--- a/scripts/vcpkg
+++ b/scripts/vcpkg
@@ -1 +1 @@
-Subproject commit 5e0443fea12ce12f165fb16d7546b20a64894615
+Subproject commit 6fb07583f1e76206975508f33a21bfddce799bc0
diff --git a/src/app/CMakeLists.txt b/src/app/CMakeLists.txt
index 4264e630..d95d1d65 100644
--- a/src/app/CMakeLists.txt
+++ b/src/app/CMakeLists.txt
@@ -29,6 +29,7 @@ endif()
ck_configure_application(
${_ico_args}
${_icns_args}
+ INFO_PLIST ${CMAKE_CURRENT_SOURCE_DIR}/info.plist.in
)
qm_configure_target(${PROJECT_NAME}
@@ -70,6 +71,12 @@ ck_add_shared_files(
# SRC conf/${CK_PLATFORM_LOWER}/qtmediate.json DEST ${CK_BUILD_QT_CONF_DIR} # qtmediate.json
)
+if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/icons/dspx.icns)
+ ck_add_shared_files(
+ SRC ${CMAKE_CURRENT_BINARY_DIR}/icons/dspx.icns DEST ${CK_BUILD_DATA_DIR}
+ )
+endif()
+
file(GLOB _icons icons/*)
list(FILTER _icons EXCLUDE REGEX CMakeLists.txt)
diff --git a/src/app/info.plist.in b/src/app/info.plist.in
new file mode 100644
index 00000000..c10a6e46
--- /dev/null
+++ b/src/app/info.plist.in
@@ -0,0 +1,92 @@
+
+
+
+
+
+ CFBundleDevelopmentRegion
+ English
+
+ CFBundleExecutable
+ @APPLICATION_NAME@
+
+ CFBundleIconFile
+ app.icns
+
+ CFBundleIdentifier
+ @APPLICATION_NAME@
+
+ CFBundleInfoDictionaryVersion
+ 6.0
+
+ CFBundleName
+ @APPLICATION_DISPLAY_NAME@
+
+ CFBundlePackageType
+ APPL
+
+ CFBundleShortVersionString
+ @APPLICATION_SEMVER@
+
+ CFBundleSignature
+ ????
+
+ CFBundleVersion
+ @APPLICATION_SEMVER@
+
+ CSResourcesFileMapped
+
+
+ NSHumanReadableCopyright
+ @RC_COPYRIGHT@
+
+ UTExportedTypeDeclarations
+
+
+ UTTypeIdentifier
+ org.diffscope.dspx
+
+ UTTypeDescription
+ DiffScope Project Exchange Format
+
+ UTTypeConformsTo
+
+ public.json
+
+
+ UTTypeTagSpecification
+
+ public.filename-extension
+
+ dspx
+
+
+ public.mime-type
+ application/vnd.openvpi.dspx+json
+
+
+
+
+ CFBundleDocumentTypes
+
+
+ CFBundleTypeName
+ DiffScope Project File
+
+ CFBundleTypeRole
+ Editor
+
+ LSItemContentTypes
+
+ org.diffscope.dspx
+
+
+ CFBundleTypeIconFile
+ dspx.icns
+
+ LSHandlerRank
+ Default
+
+
+
+
+
diff --git a/src/app/main.cpp b/src/app/main.cpp
index b1b4c6f8..041d94f7 100644
--- a/src/app/main.cpp
+++ b/src/app/main.cpp
@@ -39,6 +39,8 @@ static QSettings::Format getJsonSettingsFormat() {
static QQmlEngine *engine{};
+static constexpr char kNoWarningLastInitialization[] = "--no-warning-last-initialization";
+
class MyLoaderSpec : public Loader::LoaderSpec {
public:
MyLoaderSpec() {
@@ -55,6 +57,11 @@ class MyLoaderSpec : public Loader::LoaderSpec {
QStringLiteral("/config.json");
pluginPaths << ApplicationInfo::applicationLocation(ApplicationInfo::BuiltinPlugins);
coreName = QStringLiteral("org.diffscope.core");
+ extraArguments << Argument{
+ {kNoWarningLastInitialization},
+ {},
+ QStringLiteral("Suppress warning about 'Last initialization was aborted abnormally'")
+ };
}
QSettings *createExtensionSystemSettings(QSettings::Scope scope) override {
@@ -102,11 +109,18 @@ class MyLoaderSpec : public Loader::LoaderSpec {
locale.setNumberOptions(QLocale::OmitGroupSeparator);
RuntimeInterface::setTranslationManager(new TranslationManager(RuntimeInterface::instance()));
RuntimeInterface::translationManager()->setLocale(locale);
- RuntimeInterface::translationManager()->addTranslationPath(ApplicationInfo::systemLocation(ApplicationInfo::Resources) + QStringLiteral("/ChorusKit/translations"));
- RuntimeInterface::translationManager()->addTranslationPath(ApplicationInfo::systemLocation(ApplicationInfo::Resources) + QStringLiteral("/svscraft/translations"));
- RuntimeInterface::translationManager()->addTranslationPath(ApplicationInfo::systemLocation(ApplicationInfo::Resources) + QStringLiteral("/uishell/translations"));
+ auto translationBaseDir =
+#ifdef Q_OS_MAC
+ ApplicationInfo::systemLocation(ApplicationInfo::Resources) + QStringLiteral("/share");
+#else
+ ApplicationInfo::systemLocation(ApplicationInfo::Resources);
+#endif
+ RuntimeInterface::translationManager()->addTranslationPath(translationBaseDir + QStringLiteral("/ChorusKit/translations"));
+ RuntimeInterface::translationManager()->addTranslationPath(translationBaseDir + QStringLiteral("/svscraft/translations"));
+ RuntimeInterface::translationManager()->addTranslationPath(translationBaseDir + QStringLiteral("/uishell/translations"));
- if (settings->value("lastInitializationAbortedFlag").toBool()) {
+ bool lastInitializationWarningSuppressed = QApplication::arguments().contains(kNoWarningLastInitialization);
+ if (settings->value("lastInitializationAbortedFlag").toBool() && !lastInitializationWarningSuppressed) {
qInfo() << "Last initialization was aborted abnormally";
QQmlComponent component(engine, "DiffScope.UIShell", "InitializationFailureWarningDialog");
std::unique_ptr dialog(component.isError() ? nullptr : component.createWithInitialProperties({
diff --git a/src/libs/3rdparty/choruskit b/src/libs/3rdparty/choruskit
index ead08258..e40b3316 160000
--- a/src/libs/3rdparty/choruskit
+++ b/src/libs/3rdparty/choruskit
@@ -1 +1 @@
-Subproject commit ead082581b7116763a27e29f733fa13e4edb963b
+Subproject commit e40b331652f9a81eea9be505305dbb198abd8dae
diff --git a/src/libs/3rdparty/opendspx b/src/libs/3rdparty/opendspx
index 0a4bb52e..45fbaf09 160000
--- a/src/libs/3rdparty/opendspx
+++ b/src/libs/3rdparty/opendspx
@@ -1 +1 @@
-Subproject commit 0a4bb52e0f199d74d288eda2c9c41bfe2d34d80d
+Subproject commit 45fbaf0987083c57bf5a06c0adcbd88956d0334a
diff --git a/src/libs/3rdparty/qactionkit b/src/libs/3rdparty/qactionkit
index 42b9cd90..573def48 160000
--- a/src/libs/3rdparty/qactionkit
+++ b/src/libs/3rdparty/qactionkit
@@ -1 +1 @@
-Subproject commit 42b9cd9053d76aeb8d66728a650827d97f40f11a
+Subproject commit 573def486e3f8c0f62768bcdcbc490b24cbd59af
diff --git a/src/libs/3rdparty/scopicflow b/src/libs/3rdparty/scopicflow
index 06238363..d32af0d9 160000
--- a/src/libs/3rdparty/scopicflow
+++ b/src/libs/3rdparty/scopicflow
@@ -1 +1 @@
-Subproject commit 062383639e43b2baa9c3ae20674c8dd153d3a73e
+Subproject commit d32af0d99f7e6fd1023412c2686fde559a5da7db
diff --git a/src/libs/3rdparty/svscraft b/src/libs/3rdparty/svscraft
index 70fab799..1289b602 160000
--- a/src/libs/3rdparty/svscraft
+++ b/src/libs/3rdparty/svscraft
@@ -1 +1 @@
-Subproject commit 70fab7997428056a557a82a8e3dce37941c15795
+Subproject commit 1289b602146a559e1c9d69f3347043e8cc935920
diff --git a/src/libs/application/dspxmodel/src/AnchorNode.cpp b/src/libs/application/dspxmodel/src/AnchorNode.cpp
index 22eaba9f..47aae0d2 100644
--- a/src/libs/application/dspxmodel/src/AnchorNode.cpp
+++ b/src/libs/application/dspxmodel/src/AnchorNode.cpp
@@ -19,8 +19,9 @@ namespace dspx {
void AnchorNodePrivate::setInterp(AnchorNode::InterpolationMode interp_) {
Q_Q(AnchorNode);
- if (auto engine = qjsEngine(q); engine && (interp_ != AnchorNode::None && interp_ != AnchorNode::Linear && interp_ != AnchorNode::Hermite)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Interpolation mode must be one of None, Linear, or Hermite"));
+ if ((interp_ != AnchorNode::None && interp_ != AnchorNode::Linear && interp_ != AnchorNode::Hermite)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Interpolation mode must be one of None, Linear, or Hermite"));
return;
}
setInterpUnchecked(interp_);
@@ -33,8 +34,9 @@ namespace dspx {
void AnchorNodePrivate::setX(int x_) {
Q_Q(AnchorNode);
- if (auto engine = qjsEngine(q); engine && x_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Position must be greater or equal to 0"));
+ if (x_ < 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Position must be greater or equal to 0"));
return;
}
setXUnchecked(x_);
diff --git a/src/libs/application/dspxmodel/src/ClipTime.cpp b/src/libs/application/dspxmodel/src/ClipTime.cpp
index 6e80b886..478bc8d6 100644
--- a/src/libs/application/dspxmodel/src/ClipTime.cpp
+++ b/src/libs/application/dspxmodel/src/ClipTime.cpp
@@ -37,8 +37,9 @@ namespace dspx {
void ClipTimePrivate::setLength(int length_) {
Q_Q(ClipTime);
- if (auto engine = qjsEngine(q); engine && length_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Length must be greater than or equal to 0"));
+ if (length_ < 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Length must be greater than or equal to 0"));
return;
}
setLengthUnchecked(length_);
@@ -51,8 +52,9 @@ namespace dspx {
void ClipTimePrivate::setClipStart(int clipStart_) {
Q_Q(ClipTime);
- if (auto engine = qjsEngine(q); engine && clipStart_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("ClipStart must be greater than or equal to 0"));
+ if (clipStart_ < 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("ClipStart must be greater than or equal to 0"));
return;
}
setClipStartUnchecked(clipStart_);
@@ -65,8 +67,9 @@ namespace dspx {
void ClipTimePrivate::setClipLen(int clipLen_) {
Q_Q(ClipTime);
- if (auto engine = qjsEngine(q); engine && clipLen_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("ClipLen must be greater than or equal to 0"));
+ if (clipLen_ < 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("ClipLen must be greater than or equal to 0"));
return;
}
setClipLenUnchecked(clipLen_);
diff --git a/src/libs/application/dspxmodel/src/Control.cpp b/src/libs/application/dspxmodel/src/Control.cpp
index d0c823ca..62d68586 100644
--- a/src/libs/application/dspxmodel/src/Control.cpp
+++ b/src/libs/application/dspxmodel/src/Control.cpp
@@ -33,8 +33,9 @@ namespace dspx {
void ControlPrivate::setGain(double gain_) {
Q_Q(Control);
- if (auto engine = qjsEngine(q); engine && (gain_ < 0)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Gain must be greater or equal to 0"));
+ if ((gain_ < 0)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Gain must be greater or equal to 0"));
return;
}
setGainUnchecked(gain_);
@@ -47,8 +48,9 @@ namespace dspx {
void ControlPrivate::setPan(double pan_) {
Q_Q(Control);
- if (auto engine = qjsEngine(q); engine && (pan_ < -1 || pan_ > 1)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Pan must be in range [-1.0, 1.0]"));
+ if ((pan_ < -1 || pan_ > 1)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Pan must be in range [-1.0, 1.0]"));
return;
}
setPanUnchecked(pan_);
diff --git a/src/libs/application/dspxmodel/src/Control.h b/src/libs/application/dspxmodel/src/Control.h
index 20135658..777294e7 100644
--- a/src/libs/application/dspxmodel/src/Control.h
+++ b/src/libs/application/dspxmodel/src/Control.h
@@ -14,7 +14,7 @@ namespace dspx {
class ControlPrivate;
- class Control : public QObject {
+ class DSPX_MODEL_EXPORT Control : public QObject {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
diff --git a/src/libs/application/dspxmodel/src/EntityObject.cpp b/src/libs/application/dspxmodel/src/EntityObject.cpp
index a42f104a..b95fc8a6 100644
--- a/src/libs/application/dspxmodel/src/EntityObject.cpp
+++ b/src/libs/application/dspxmodel/src/EntityObject.cpp
@@ -22,7 +22,7 @@ namespace dspx {
EntityObject::~EntityObject() {
Q_D(EntityObject);
if (d->model && d->handle) {
-
+ Q_ASSERT(false && "EntityObject::~EntityObject: handle is not null. You should call Model::destroyItem() to delete EntityObject.");
}
}
diff --git a/src/libs/application/dspxmodel/src/Global.cpp b/src/libs/application/dspxmodel/src/Global.cpp
index e687463f..3747dcaa 100644
--- a/src/libs/application/dspxmodel/src/Global.cpp
+++ b/src/libs/application/dspxmodel/src/Global.cpp
@@ -34,8 +34,9 @@ namespace dspx {
void GlobalPrivate::setCentShift(int centShift) {
Q_Q(Global);
- if (auto engine = qjsEngine(q); engine && (centShift < -50 || centShift > 50)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Cent shift must be in range [-50, 50]"));
+ if ((centShift < -50 || centShift > 50)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Cent shift must be in range [-50, 50]"));
return;
}
setCentShiftUnchecked(centShift);
diff --git a/src/libs/application/dspxmodel/src/Global.h b/src/libs/application/dspxmodel/src/Global.h
index 651f2129..8eeaa2ca 100644
--- a/src/libs/application/dspxmodel/src/Global.h
+++ b/src/libs/application/dspxmodel/src/Global.h
@@ -5,6 +5,8 @@
#include
+#include
+
namespace QDspx {
struct Global;
}
@@ -17,7 +19,7 @@ namespace dspx {
class GlobalPrivate;
- class Global : public QObject {
+ class DSPX_MODEL_EXPORT Global : public QObject {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
diff --git a/src/libs/application/dspxmodel/src/Label.cpp b/src/libs/application/dspxmodel/src/Label.cpp
index 7fdfecfe..2b508749 100644
--- a/src/libs/application/dspxmodel/src/Label.cpp
+++ b/src/libs/application/dspxmodel/src/Label.cpp
@@ -19,8 +19,9 @@ namespace dspx {
void LabelPrivate::setPos(int pos_) {
Q_Q(Label);
- if (auto engine = qjsEngine(q); engine && pos_ < -0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Pos must be greater or equal to 0"));
+ if (pos_ < -0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Pos must be greater or equal to 0"));
return;
}
setPosUnchecked(pos_);
diff --git a/src/libs/application/dspxmodel/src/Master.cpp b/src/libs/application/dspxmodel/src/Master.cpp
index 95dd4e05..7f971fc6 100644
--- a/src/libs/application/dspxmodel/src/Master.cpp
+++ b/src/libs/application/dspxmodel/src/Master.cpp
@@ -16,18 +16,36 @@ namespace dspx {
public:
Master *q_ptr;
ModelPrivate *pModel;
+ Handle handle;
BusControl *control;
+ bool multiChannelOutput{};
};
Master::Master(Model *model) : QObject(model), d_ptr(new MasterPrivate) {
Q_D(Master);
d->q_ptr = this;
d->pModel = ModelPrivate::get(model);
+ d->handle = model->handle();
d->control = d->pModel->createObject(model->handle());
}
void Master::handleProxySetEntityProperty(int property, const QVariant &value) {
Q_D(Master);
- ModelPrivate::proxySetEntityPropertyNotify(d->control, property, value);
+ switch (property) {
+ case ModelStrategy::P_ControlGain:
+ case ModelStrategy::P_ControlPan:
+ case ModelStrategy::P_ControlMute: {
+ ModelPrivate::proxySetEntityPropertyNotify(d->control, property, value);
+ break;
+ }
+ case ModelStrategy::P_MultiChannelOutput: {
+ d->multiChannelOutput = value.toBool();
+ Q_EMIT multiChannelOutputChanged(d->multiChannelOutput);
+ break;
+ }
+ default:
+ Q_UNREACHABLE();
+ }
+
}
Master::~Master() = default;
@@ -35,6 +53,14 @@ namespace dspx {
Q_D(const Master);
return d->control;
}
+ bool Master::multiChannelOutput() const {
+ Q_D(const Master);
+ return d->multiChannelOutput;
+ }
+ void Master::setMultiChannelOutput(bool multiChannelOutput) {
+ Q_D(Master);
+ d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_MultiChannelOutput, multiChannelOutput);
+ }
QDspx::Master Master::toQDspx() const {
return {
diff --git a/src/libs/application/dspxmodel/src/Master.h b/src/libs/application/dspxmodel/src/Master.h
index 507ae783..d0ac456d 100644
--- a/src/libs/application/dspxmodel/src/Master.h
+++ b/src/libs/application/dspxmodel/src/Master.h
@@ -1,9 +1,10 @@
#ifndef DIFFSCOPE_DSPX_MODEL_MASTER_H
#define DIFFSCOPE_DSPX_MODEL_MASTER_H
+#include
#include
-#include
+#include
namespace QDspx {
struct Master;
@@ -19,21 +20,27 @@ namespace dspx {
class MasterPrivate;
- class Master : public QObject {
+ class DSPX_MODEL_EXPORT Master : public QObject {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_DECLARE_PRIVATE(Master)
Q_PROPERTY(BusControl *control READ control CONSTANT)
-
+ Q_PROPERTY(bool multiChannelOutput READ multiChannelOutput WRITE setMultiChannelOutput NOTIFY multiChannelOutputChanged)
public:
~Master() override;
BusControl *control() const;
+ bool multiChannelOutput() const;
+ void setMultiChannelOutput(bool multiChannelOutput);
+
QDspx::Master toQDspx() const;
void fromQDspx(const QDspx::Master &master);
+ Q_SIGNALS:
+ void multiChannelOutputChanged(bool multiChannelOutput);
+
private:
friend class ModelPrivate;
explicit Master(Model *model);
diff --git a/src/libs/application/dspxmodel/src/Model.cpp b/src/libs/application/dspxmodel/src/Model.cpp
index a91105e0..cce0485a 100644
--- a/src/libs/application/dspxmodel/src/Model.cpp
+++ b/src/libs/application/dspxmodel/src/Model.cpp
@@ -210,7 +210,7 @@ namespace dspx {
}
QDspx::Model Model::toQDspx() const {
- return {
+ QDspx::Model model = {
.version = QDspx::Model::V1,
.content = {
.global = global()->toQDspx(),
@@ -220,6 +220,17 @@ namespace dspx {
.workspace = workspace()->toQDspx(),
}
};
+ model.content.workspace["diffscope"] = QJsonObject{
+ {"loop", QJsonObject{
+ {"enabled", timeline()->isLoopEnabled()},
+ {"start", timeline()->loopStart()},
+ {"length", timeline()->loopLength()},
+ }},
+ {"master", QJsonObject{
+ {"multiChannelOutput", master()->multiChannelOutput()}
+ }}
+ };
+ return model;
}
void Model::fromQDspx(const QDspx::Model &model) {
@@ -229,6 +240,25 @@ namespace dspx {
d->timeline->fromQDspx(model.content.timeline);
d->tracks->fromQDspx(model.content.tracks);
d->workspace->fromQDspx(model.content.workspace);
+ {
+ auto loop = model.content.workspace.value("diffscope").value("loop").toObject();
+ auto enabled = loop.value("enabled").toBool();
+ auto start = loop.value("start").toInt();
+ auto length = loop.value("length").toInt();
+ if (start < 0 || length <= 0) {
+ d->timeline->setLoopEnabled(false);
+ d->timeline->setLoopStart(0);
+ d->timeline->setLoopLength(1920);
+ } else {
+ d->timeline->setLoopEnabled(enabled);
+ d->timeline->setLoopStart(start);
+ d->timeline->setLoopLength(length);
+ }
+ }
+ {
+ auto master = model.content.workspace.value("diffscope").value("master").toObject();
+ d->master->setMultiChannelOutput(master.value("multiChannelOutput").toBool());
+ }
}
Label *Model::createLabel() {
@@ -353,10 +383,17 @@ namespace dspx {
}
case ModelStrategy::P_ControlGain:
case ModelStrategy::P_ControlPan:
- case ModelStrategy::P_ControlMute: {
+ case ModelStrategy::P_ControlMute:
+ case ModelStrategy::P_MultiChannelOutput: {
ModelPrivate::proxySetEntityPropertyNotify(d->master, property, value);
break;
}
+ case ModelStrategy::P_LoopEnabled:
+ case ModelStrategy::P_LoopLength:
+ case ModelStrategy::P_LoopStart: {
+ ModelPrivate::proxySetEntityPropertyNotify(d->timeline, property, value);
+ break;
+ }
default:
Q_UNREACHABLE();
}
diff --git a/src/libs/application/dspxmodel/src/ModelStrategy.h b/src/libs/application/dspxmodel/src/ModelStrategy.h
index 0a56fbfa..d36200c6 100644
--- a/src/libs/application/dspxmodel/src/ModelStrategy.h
+++ b/src/libs/application/dspxmodel/src/ModelStrategy.h
@@ -61,15 +61,21 @@ namespace dspx {
P_ControlGain,
P_ControlMute,
P_ControlPan,
+ P_ControlRecord,
P_ControlSolo,
P_Denominator,
P_EditorId,
P_EditorName,
+ P_Height,
P_JsonObject,
P_KeyNumber,
P_Language,
P_Length,
+ P_LoopEnabled,
+ P_LoopLength,
+ P_LoopStart,
P_Measure,
+ P_MultiChannelOutput,
P_Name,
P_Numerator,
P_Onset,
@@ -236,6 +242,10 @@ namespace dspx {
auto v = value.toInt();
return v >= 0;
};
+ static auto validateIntGreaterZero = [](const QVariant &value) {
+ auto v = value.toInt();
+ return v > 0;
+ };
static auto validateDoubleGreaterOrEqualZero = [](const QVariant &value) {
auto v = value.toDouble();
return v >= 0;
@@ -280,7 +290,11 @@ namespace dspx {
{P_EditorName, QMetaType::QString},
{P_ControlGain, QMetaType::Double},
{P_ControlPan, QMetaType::Double, validatePan},
- {P_ControlMute, QMetaType::Bool}
+ {P_ControlMute, QMetaType::Bool},
+ {P_MultiChannelOutput, QMetaType::Bool},
+ {P_LoopEnabled, QMetaType::Bool},
+ {P_LoopStart, QMetaType::Int, validateIntGreaterOrEqualZero},
+ {P_LoopLength, QMetaType::Int, validateIntGreaterZero},
};
case EI_Label: return {
{P_Position, QMetaType::Int, validateIntGreaterOrEqualZero},
@@ -348,7 +362,9 @@ namespace dspx {
{P_ControlGain, QMetaType::Double},
{P_ControlPan, QMetaType::Double, validatePan},
{P_ControlMute, QMetaType::Bool},
- {P_ControlSolo, QMetaType::Bool}
+ {P_ControlRecord, QMetaType::Bool},
+ {P_ControlSolo, QMetaType::Bool},
+ {P_Height, QMetaType::Double, validateDoubleGreaterOrEqualZero}
};
case EI_WorkspaceInfo: return {
{P_JsonObject, QMetaType::QJsonObject}
diff --git a/src/libs/application/dspxmodel/src/Note.cpp b/src/libs/application/dspxmodel/src/Note.cpp
index 9888c90c..3760f649 100644
--- a/src/libs/application/dspxmodel/src/Note.cpp
+++ b/src/libs/application/dspxmodel/src/Note.cpp
@@ -23,8 +23,9 @@ namespace dspx {
void NotePrivate::setCentShift(int centShift_) {
Q_Q(Note);
- if (auto engine = qjsEngine(q); engine && (centShift_ < -50 || centShift_ > 50)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("CentShift must be in range [-50, 50]"));
+ if ((centShift_ < -50 || centShift_ > 50)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("CentShift must be in range [-50, 50]"));
return;
}
setCentShiftUnchecked(centShift_);
@@ -37,8 +38,9 @@ namespace dspx {
void NotePrivate::setKeyNum(int keyNum_) {
Q_Q(Note);
- if (auto engine = qjsEngine(q); engine && (keyNum_ < 0 || keyNum_ > 127)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("KeyNum must be in range [0, 127]"));
+ if ((keyNum_ < 0 || keyNum_ > 127)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("KeyNum must be in range [0, 127]"));
return;
}
setKeyNumUnchecked(keyNum_);
@@ -51,8 +53,9 @@ namespace dspx {
void NotePrivate::setLength(int length_) {
Q_Q(Note);
- if (auto engine = qjsEngine(q); engine && length_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Length must be greater than or equal to 0"));
+ if (length_ < 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Length must be greater than or equal to 0"));
return;
}
setLengthUnchecked(length_);
@@ -65,8 +68,9 @@ namespace dspx {
void NotePrivate::setPos(int pos_) {
Q_Q(Note);
- if (auto engine = qjsEngine(q); engine && pos_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Pos must be greater than or equal to 0"));
+ if (pos_ < 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Pos must be greater than or equal to 0"));
return;
}
setPosUnchecked(pos_);
diff --git a/src/libs/application/dspxmodel/src/Tempo.cpp b/src/libs/application/dspxmodel/src/Tempo.cpp
index 0da9844a..da07fa53 100644
--- a/src/libs/application/dspxmodel/src/Tempo.cpp
+++ b/src/libs/application/dspxmodel/src/Tempo.cpp
@@ -19,8 +19,9 @@ namespace dspx {
void TempoPrivate::setPos(int pos_) {
Q_Q(Tempo);
- if (auto engine = qjsEngine(q); engine && pos_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Pos must be greater or equal to 0"));
+ if (pos_ < 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Pos must be greater or equal to 0"));
return;
}
setPosUnchecked(pos_);
@@ -33,8 +34,9 @@ namespace dspx {
void TempoPrivate::setValue(double value_) {
Q_Q(Tempo);
- if (auto engine = qjsEngine(q); engine && (value_ < 10.0 || value_ > 1000.0)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Value must be in range [10.0, 1000.0]"));
+ if ((value_ < 10.0 || value_ > 1000.0)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Value must be in range [10.0, 1000.0]"));
return;
}
setValueUnchecked(value_);
diff --git a/src/libs/application/dspxmodel/src/TimeSignature.cpp b/src/libs/application/dspxmodel/src/TimeSignature.cpp
index 5148bf3d..8f0fa068 100644
--- a/src/libs/application/dspxmodel/src/TimeSignature.cpp
+++ b/src/libs/application/dspxmodel/src/TimeSignature.cpp
@@ -23,8 +23,9 @@ namespace dspx {
void TimeSignaturePrivate::setIndex(int index_) {
Q_Q(TimeSignature);
- if (auto engine = qjsEngine(q); engine && index_ < 0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Index must be greater or equal to 0"));
+ if (index_ < 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Index must be greater or equal to 0"));
return;
}
setIndexUnchecked(index_);
@@ -37,8 +38,9 @@ namespace dspx {
void TimeSignaturePrivate::setNumerator(int numerator_) {
Q_Q(TimeSignature);
- if (auto engine = qjsEngine(q); engine && numerator_ < 1) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Numerator must be greater or equal to 1"));
+ if (numerator_ < 1) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Numerator must be greater or equal to 1"));
return;
}
setNumeratorUnchecked(numerator_);
diff --git a/src/libs/application/dspxmodel/src/Timeline.cpp b/src/libs/application/dspxmodel/src/Timeline.cpp
index 7119ef2c..b73df2ac 100644
--- a/src/libs/application/dspxmodel/src/Timeline.cpp
+++ b/src/libs/application/dspxmodel/src/Timeline.cpp
@@ -1,7 +1,10 @@
#include "Timeline.h"
+#include
+
#include
+#include
#include
#include
#include
@@ -14,12 +17,69 @@ namespace dspx {
public:
Timeline *q_ptr;
ModelPrivate *pModel;
+ Handle handle;
+
+ bool loopEnabled{false};
+ int loopStart{0};
+ int loopLength{1920};
+
+ void setLoopStartUnchecked(int loopStart_) {
+ Q_Q(Timeline);
+ pModel->strategy->setEntityProperty(handle, ModelStrategy::P_LoopStart, loopStart_);
+ }
+
+ void setLoopStart(int loopStart_) {
+ Q_Q(Timeline);
+ if (loopStart_ < 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Loop start must be greater or equal to 0"));
+ return;
+ }
+ setLoopStartUnchecked(loopStart_);
+ }
+
+ void setLoopLengthUnchecked(int loopLength_) {
+ Q_Q(Timeline);
+ pModel->strategy->setEntityProperty(handle, ModelStrategy::P_LoopLength, loopLength_);
+ }
+
+ void setLoopLength(int loopLength_) {
+ Q_Q(Timeline);
+ if (loopLength_ <= 0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Loop length must be greater than 0"));
+ return;
+ }
+ setLoopLengthUnchecked(loopLength_);
+ }
};
- Timeline::Timeline(Model *model) : QObject(model), d_ptr(new TimelinePrivate) {
+ Timeline::Timeline(Model *model)
+ : QObject(model), d_ptr(new TimelinePrivate) {
Q_D(Timeline);
d->q_ptr = this;
d->pModel = ModelPrivate::get(model);
+ d->handle = model->handle();
+ }
+
+ void Timeline::handleProxySetEntityProperty(int property, const QVariant &value) {
+ Q_D(Timeline);
+ switch (property) {
+ case ModelStrategy::P_LoopEnabled:
+ d->loopEnabled = value.toBool();
+ Q_EMIT loopEnabledChanged(d->loopEnabled);
+ break;
+ case ModelStrategy::P_LoopStart:
+ d->loopStart = value.toInt();
+ Q_EMIT loopStartChanged(d->loopStart);
+ break;
+ case ModelStrategy::P_LoopLength:
+ d->loopLength = value.toInt();
+ Q_EMIT loopLengthChanged(d->loopLength);
+ break;
+ default:
+ Q_UNREACHABLE();
+ }
}
Timeline::~Timeline() = default;
@@ -39,6 +99,38 @@ namespace dspx {
return d->pModel->timeSignatures;
}
+ bool Timeline::isLoopEnabled() const {
+ Q_D(const Timeline);
+ return d->loopEnabled;
+ }
+
+ void Timeline::setLoopEnabled(bool enabled) {
+ Q_D(Timeline);
+ d->pModel->strategy->setEntityProperty(d->handle, ModelStrategy::P_LoopEnabled, enabled);
+ }
+
+ int Timeline::loopStart() const {
+ Q_D(const Timeline);
+ return d->loopStart;
+ }
+
+ void Timeline::setLoopStart(int loopStart) {
+ Q_D(Timeline);
+ Q_ASSERT(loopStart >= 0);
+ d->setLoopStartUnchecked(loopStart);
+ }
+
+ int Timeline::loopLength() const {
+ Q_D(const Timeline);
+ return d->loopLength;
+ }
+
+ void Timeline::setLoopLength(int loopLength) {
+ Q_D(Timeline);
+ Q_ASSERT(loopLength > 0);
+ d->setLoopLengthUnchecked(loopLength);
+ }
+
QDspx::Timeline Timeline::toQDspx() const {
return {
labels()->toQDspx(),
diff --git a/src/libs/application/dspxmodel/src/Timeline.h b/src/libs/application/dspxmodel/src/Timeline.h
index 8ce439e2..2352052f 100644
--- a/src/libs/application/dspxmodel/src/Timeline.h
+++ b/src/libs/application/dspxmodel/src/Timeline.h
@@ -29,6 +29,9 @@ namespace dspx {
Q_PROPERTY(LabelSequence *labels READ labels CONSTANT)
Q_PROPERTY(TempoSequence *tempos READ tempos CONSTANT)
Q_PROPERTY(TimeSignatureSequence *timeSignatures READ timeSignatures CONSTANT)
+ Q_PROPERTY(bool loopEnabled READ isLoopEnabled WRITE setLoopEnabled NOTIFY loopEnabledChanged)
+ Q_PRIVATE_PROPERTY(d_func(), int loopStart MEMBER loopStart WRITE setLoopStart NOTIFY loopStartChanged)
+ Q_PRIVATE_PROPERTY(d_func(), int loopLength MEMBER loopLength WRITE setLoopLength NOTIFY loopLengthChanged)
public:
~Timeline() override;
@@ -36,12 +39,27 @@ namespace dspx {
TempoSequence *tempos() const;
TimeSignatureSequence *timeSignatures() const;
+ bool isLoopEnabled() const;
+ void setLoopEnabled(bool enabled);
+
+ int loopStart() const;
+ void setLoopStart(int loopStart);
+
+ int loopLength() const;
+ void setLoopLength(int loopLength);
+
QDspx::Timeline toQDspx() const;
void fromQDspx(const QDspx::Timeline &timeline);
+ Q_SIGNALS:
+ void loopEnabledChanged(bool enabled);
+ void loopStartChanged(int loopStart);
+ void loopLengthChanged(int loopLength);
+
private:
friend class ModelPrivate;
explicit Timeline(Model *model);
+ void handleProxySetEntityProperty(int property, const QVariant &value);
QScopedPointer d_ptr;
};
diff --git a/src/libs/application/dspxmodel/src/Track.cpp b/src/libs/application/dspxmodel/src/Track.cpp
index cb10f594..a0e7140d 100644
--- a/src/libs/application/dspxmodel/src/Track.cpp
+++ b/src/libs/application/dspxmodel/src/Track.cpp
@@ -31,6 +31,7 @@ namespace dspx {
d->pModel = ModelPrivate::get(model);
d->name = d->pModel->strategy->getEntityProperty(handle, ModelStrategy::P_Name).toString();
d->colorId = d->pModel->strategy->getEntityProperty(handle, ModelStrategy::P_ColorId).toInt();
+ d->height = d->pModel->strategy->getEntityProperty(handle, ModelStrategy::P_Height).toDouble();
d->control = d->pModel->createObject(handle);
d->workspace = d->pModel->createObject(d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Workspace));
d->clips = d->pModel->createObject(this, d->pModel->strategy->getAssociatedSubEntity(handle, ModelStrategy::R_Children));
@@ -53,6 +54,16 @@ namespace dspx {
d->pModel->strategy->setEntityProperty(handle(), ModelStrategy::P_ColorId, colorId);
}
+ double Track::height() const {
+ Q_D(const Track);
+ return d->height;
+ }
+
+ void Track::setHeight(double height) {
+ Q_D(Track);
+ d->pModel->strategy->setEntityProperty(handle(), ModelStrategy::P_Height, height);
+ }
+
TrackControl *Track::control() const {
Q_D(const Track);
return d->control;
@@ -80,7 +91,11 @@ namespace dspx {
.clips = clips()->toQDspx(),
.workspace = workspace()->toQDspx(),
};
- track.workspace["diffscope"]["colorId"] = colorId();
+ track.workspace["diffscope"] = QJsonObject{
+ {"colorId", colorId()},
+ {"height", height()},
+ {"record", control()->record()},
+ };
return track;
}
@@ -90,6 +105,8 @@ namespace dspx {
clips()->fromQDspx(track.clips);
workspace()->fromQDspx(track.workspace);
setColorId(track.workspace["diffscope"]["colorId"].toInt());
+ setHeight(track.workspace["diffscope"]["height"].toDouble(80));
+ control()->setRecord(track.workspace["diffscope"]["record"].toBool());
}
TrackList *Track::trackList() const {
@@ -110,9 +127,15 @@ namespace dspx {
Q_EMIT colorIdChanged(d->colorId);
break;
}
+ case ModelStrategy::P_Height: {
+ d->height = value.toDouble();
+ Q_EMIT heightChanged(d->height);
+ break;
+ }
case ModelStrategy::P_ControlGain:
case ModelStrategy::P_ControlPan:
case ModelStrategy::P_ControlMute:
+ case ModelStrategy::P_ControlRecord:
case ModelStrategy::P_ControlSolo: {
ModelPrivate::proxySetEntityPropertyNotify(d->control, property, value);
break;
diff --git a/src/libs/application/dspxmodel/src/Track.h b/src/libs/application/dspxmodel/src/Track.h
index c686f3d6..c49fd48c 100644
--- a/src/libs/application/dspxmodel/src/Track.h
+++ b/src/libs/application/dspxmodel/src/Track.h
@@ -26,6 +26,7 @@ namespace dspx {
Q_DECLARE_PRIVATE(Track)
Q_PROPERTY(ClipSequence *clips READ clips CONSTANT)
Q_PROPERTY(int colorId READ colorId WRITE setColorId NOTIFY colorIdChanged)
+ Q_PROPERTY(double height READ height WRITE setHeight NOTIFY heightChanged)
Q_PROPERTY(TrackControl *control READ control CONSTANT)
Q_PROPERTY(QString name READ name WRITE setName NOTIFY nameChanged)
Q_PROPERTY(Workspace *workspace READ workspace CONSTANT)
@@ -39,6 +40,9 @@ namespace dspx {
int colorId() const;
void setColorId(int colorId);
+ double height() const;
+ void setHeight(double height);
+
TrackControl *control() const;
QString name() const;
@@ -54,6 +58,7 @@ namespace dspx {
Q_SIGNALS:
void nameChanged(const QString &name);
void colorIdChanged(int colorId);
+ void heightChanged(double height);
void trackListChanged();
protected:
diff --git a/src/libs/application/dspxmodel/src/TrackControl.cpp b/src/libs/application/dspxmodel/src/TrackControl.cpp
index 1e543252..f3142173 100644
--- a/src/libs/application/dspxmodel/src/TrackControl.cpp
+++ b/src/libs/application/dspxmodel/src/TrackControl.cpp
@@ -13,6 +13,7 @@ namespace dspx {
TrackControl *q_ptr;
ModelPrivate *pModel;
bool solo;
+ bool record;
};
TrackControl::TrackControl(Handle handle, Model *model) : Control(handle, model), d_ptr(new TrackControlPrivate) {
@@ -20,6 +21,7 @@ namespace dspx {
d->q_ptr = this;
d->pModel = ModelPrivate::get(model);
d->solo = d->pModel->strategy->getEntityProperty(handle, ModelStrategy::P_ControlSolo).toBool();
+ d->record = d->pModel->strategy->getEntityProperty(handle, ModelStrategy::P_ControlRecord).toBool();
}
TrackControl::~TrackControl() = default;
@@ -34,6 +36,16 @@ namespace dspx {
d->pModel->strategy->setEntityProperty(handle(), ModelStrategy::P_ControlSolo, solo);
}
+ bool TrackControl::record() const {
+ Q_D(const TrackControl);
+ return d->record;
+ }
+
+ void TrackControl::setRecord(bool record) {
+ Q_D(TrackControl);
+ d->pModel->strategy->setEntityProperty(handle(), ModelStrategy::P_ControlRecord, record);
+ }
+
QDspx::TrackControl TrackControl::toQDspx() const {
return {
.gain = gain(),
@@ -57,6 +69,11 @@ namespace dspx {
Q_EMIT soloChanged(d->solo);
break;
}
+ case ModelStrategy::P_ControlRecord: {
+ d->record = value.toBool();
+ Q_EMIT recordChanged(d->record);
+ break;
+ }
default: {
Control::handleProxySetEntityProperty(property, value);
}
diff --git a/src/libs/application/dspxmodel/src/TrackControl.h b/src/libs/application/dspxmodel/src/TrackControl.h
index d7018840..5d077a01 100644
--- a/src/libs/application/dspxmodel/src/TrackControl.h
+++ b/src/libs/application/dspxmodel/src/TrackControl.h
@@ -11,12 +11,13 @@ namespace dspx {
class TrackControlPrivate;
- class TrackControl : public Control {
+ class DSPX_MODEL_EXPORT TrackControl : public Control {
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("")
Q_DECLARE_PRIVATE(TrackControl)
Q_PROPERTY(bool solo READ solo WRITE setSolo NOTIFY soloChanged)
+ Q_PROPERTY(bool record READ record WRITE setRecord NOTIFY recordChanged)
public:
~TrackControl() override;
@@ -24,11 +25,15 @@ namespace dspx {
bool solo() const;
void setSolo(bool solo);
+ bool record() const;
+ void setRecord(bool record);
+
QDspx::TrackControl toQDspx() const;
void fromQDspx(const QDspx::TrackControl &trackControl);
Q_SIGNALS:
void soloChanged(bool solo);
+ void recordChanged(bool record);
private:
friend class ModelPrivate;
diff --git a/src/libs/application/dspxmodel/src/Track_p.h b/src/libs/application/dspxmodel/src/Track_p.h
index 4f597df9..4a4caeba 100644
--- a/src/libs/application/dspxmodel/src/Track_p.h
+++ b/src/libs/application/dspxmodel/src/Track_p.h
@@ -13,6 +13,7 @@ namespace dspx {
ClipSequence *clips;
QString name;
int colorId;
+ double height;
TrackControl *control;
Workspace *workspace;
TrackList *trackList;
diff --git a/src/libs/application/dspxmodel/src/Vibrato.cpp b/src/libs/application/dspxmodel/src/Vibrato.cpp
index 73c84e31..be5c2d3a 100644
--- a/src/libs/application/dspxmodel/src/Vibrato.cpp
+++ b/src/libs/application/dspxmodel/src/Vibrato.cpp
@@ -44,8 +44,9 @@ namespace dspx {
void VibratoPrivate::setEnd(double end_) {
Q_Q(Vibrato);
- if (auto engine = qjsEngine(q); engine && (end_ < 0.0 || end_ > 1.0)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("End must be in range [0, 1]"));
+ if ((end_ < 0.0 || end_ > 1.0)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("End must be in range [0, 1]"));
return;
}
setEndUnchecked(end_);
@@ -58,8 +59,9 @@ namespace dspx {
void VibratoPrivate::setFreq(double freq_) {
Q_Q(Vibrato);
- if (auto engine = qjsEngine(q); engine && freq_ < 0.0) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Freq must be greater than or equal to 0"));
+ if (freq_ < 0.0) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Freq must be greater than or equal to 0"));
return;
}
setFreqUnchecked(freq_);
@@ -72,8 +74,9 @@ namespace dspx {
void VibratoPrivate::setPhase(double phase_) {
Q_Q(Vibrato);
- if (auto engine = qjsEngine(q); engine && (phase_ < 0.0 || phase_ > 1.0)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Phase must be in range [0, 1]"));
+ if ((phase_ < 0.0 || phase_ > 1.0)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Phase must be in range [0, 1]"));
return;
}
setPhaseUnchecked(phase_);
@@ -86,8 +89,9 @@ namespace dspx {
void VibratoPrivate::setStart(double start_) {
Q_Q(Vibrato);
- if (auto engine = qjsEngine(q); engine && (start_ < 0.0 || start_ > 1.0)) {
- engine->throwError(QJSValue::RangeError, QStringLiteral("Start must be in range [0, 1]"));
+ if ((start_ < 0.0 || start_ > 1.0)) {
+ if (auto engine = qjsEngine(q))
+ engine->throwError(QJSValue::RangeError, QStringLiteral("Start must be in range [0, 1]"));
return;
}
setStartUnchecked(start_);
diff --git a/src/libs/application/dspxmodel/src/selectionmodel/SelectionModel.cpp b/src/libs/application/dspxmodel/src/selectionmodel/SelectionModel.cpp
index 8dc589dd..b5c542a5 100644
--- a/src/libs/application/dspxmodel/src/selectionmodel/SelectionModel.cpp
+++ b/src/libs/application/dspxmodel/src/selectionmodel/SelectionModel.cpp
@@ -167,22 +167,22 @@ namespace dspx {
if (targetSelectionType != d->selectionType) {
switch (d->selectionType) {
case ST_AnchorNode:
- // d->anchorNodeSelectionModel->d_func()->clearAll();
+ // d->anchorNodeSelectionModel->d_func()->select(nullptr, command);
break;
case ST_Clip:
- d->clipSelectionModel->d_func()->clearAll();
+ d->clipSelectionModel->d_func()->select(nullptr, command);
break;
case ST_Label:
- d->labelSelectionModel->d_func()->clearAll();
+ d->labelSelectionModel->d_func()->select(nullptr, command);
break;
case ST_Note:
- d->noteSelectionModel->d_func()->clearAll();
+ d->noteSelectionModel->d_func()->select(nullptr, command);
break;
case ST_Tempo:
- d->tempoSelectionModel->d_func()->clearAll();
+ d->tempoSelectionModel->d_func()->select(nullptr, command);
break;
case ST_Track:
- d->trackSelectionModel->d_func()->clearAll();
+ d->trackSelectionModel->d_func()->select(nullptr, command);
break;
default:
break;
diff --git a/src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.cpp b/src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.cpp
index fb0d040e..124889a7 100644
--- a/src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.cpp
+++ b/src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.cpp
@@ -9,9 +9,10 @@ namespace dspx {
return item->trackList() == selectionModel->model()->tracks();
}
- TrackSelectionModel::TrackSelectionModel(QObject *parent) : QObject(parent), d_ptr(new TrackSelectionModelPrivate) {
+ TrackSelectionModel::TrackSelectionModel(SelectionModel *parent) : QObject(parent), d_ptr(new TrackSelectionModelPrivate) {
Q_D(TrackSelectionModel);
d->q_ptr = this;
+ d->selectionModel = parent;
}
TrackSelectionModel::~TrackSelectionModel() = default;
diff --git a/src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.h b/src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.h
index 0b4a975c..215b64a9 100644
--- a/src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.h
+++ b/src/libs/application/dspxmodel/src/selectionmodel/TrackSelectionModel.h
@@ -35,7 +35,7 @@ namespace dspx {
private:
friend class SelectionModel;
- explicit TrackSelectionModel(QObject *parent = nullptr);
+ explicit TrackSelectionModel(SelectionModel *parent = nullptr);
QScopedPointer d_ptr;
};
diff --git a/src/libs/application/transactional/TransactionController.cpp b/src/libs/application/transactional/TransactionController.cpp
index ce52e860..a03a4d9f 100644
--- a/src/libs/application/transactional/TransactionController.cpp
+++ b/src/libs/application/transactional/TransactionController.cpp
@@ -82,7 +82,7 @@ namespace Core {
Q_D(TransactionController);
// Validate range
- if (step < 0 || step > totalSteps()) {
+ if (step > totalSteps()) {
return;
}
@@ -288,6 +288,10 @@ namespace Core {
if (wasExclusive) {
Q_EMIT q->exclusiveToTransactionChanged(false);
}
+ if (cleanStep >= currentStep) {
+ cleanStep = -1;
+ Q_EMIT q->cleanStepChanged(cleanStep);
+ }
Q_EMIT q->currentStepChanged(currentStep);
Q_EMIT q->totalStepsChanged(q->totalSteps());
Q_EMIT q->transactionCommitted(name);
diff --git a/src/libs/application/uishell/share/translations/uishell.ts b/src/libs/application/uishell/share/translations/uishell.ts
new file mode 100644
index 00000000..0eb11a54
--- /dev/null
+++ b/src/libs/application/uishell/share/translations/uishell.ts
@@ -0,0 +1,584 @@
+
+
+
+
+ ActionLayoutsEditor
+
+
+ Action
+ Action
+
+
+
+ Menu
+ Menu
+
+
+
+ Action group
+ Action group
+
+
+
+ Separator
+ Separator
+
+
+
+ Stretch
+ Stretch
+
+
+
+ BubbleNotification
+
+
+ Do Not Show Again
+ Do Not Show Again
+
+
+
+ Collapse to Notifications Panel
+ Collapse to Notifications Panel
+
+
+
+ Clear
+ Clear
+
+
+
+ Abort
+ Abort
+
+
+
+ DigitalClock
+
+
+ Digital clock
+ Digital clock
+
+
+
+ FileView
+
+
+ New project
+ New project
+
+
+
+ No result found
+ No result found
+
+
+
+ HomeWindow
+
+
+ Empty
+ Empty
+
+
+ Open
+ Open
+
+
+ Open File Location
+ Open File Location
+
+
+ Reveal in %1
+ Reveal in %1
+
+
+ Remove from "Recovery Files"
+ Remove from "Recovery Files"
+
+
+ Remove from "Recent Files"
+ Remove from "Recent Files"
+
+
+ Recent Files
+ Recent Files
+
+
+ Recovery Files
+ Recovery Files
+
+
+ New project
+ New project
+
+
+ Search
+ Search
+
+
+ Grid view
+ Grid view
+
+
+ List view
+ List view
+
+
+ No result found
+ No result found
+
+
+ No recovery file
+If %1 crashes, automatic recovery files will be displayed here.
+ No recovery file
+If %1 crashes, automatic recovery files will be displayed here.
+
+
+
+ InitializationFailureWarningDialog
+
+
+ %1 exited abnormally during the last initialization
+ %1 exited abnormally during the last initialization
+
+
+
+ This is probably caused by a faulty plugin. Please <a href="#logs">check the logs</a> for more information.<br/><br/>You may view the plugin list and disable some plugins.
+ This is probably caused by a faulty plugin. Please <a href="#logs">check the logs</a> for more information.<br/><br/>You may view the plugin list and disable some plugins.
+
+
+
+ LyricPronunciationEditor
+
+
+ Lyric Pronunciation Editor
+ Lyric Pronunciation Editor
+
+
+
+ Current pronunciation is %1. Candidate pronunciations are %2. Activate to modify pronunciation.
+ Current pronunciation is %1. Candidate pronunciations are %2. Activate to modify pronunciation.
+
+
+
+ Customize pronunciation of "%1"
+ Customize pronunciation of "%1"
+
+
+
+ OK
+ OK
+
+
+
+ Edit lyric
+ Edit lyric
+
+
+
+ Customize Pronunciation...
+ Customize Pronunciation...
+
+
+
+ Edit Lyric...
+ Edit Lyric...
+
+
+
+ Insert Cell Before
+ Insert Cell Before
+
+
+
+ Insert Cell After
+ Insert Cell After
+
+
+
+ Delete Cell
+ Delete Cell
+
+
+
+
+ Insert Line Before
+ Insert Line Before
+
+
+
+
+ Insert Line After
+ Insert Line After
+
+
+
+
+ Delete Line
+ Delete Line
+
+
+
+ Lyrics Line %1
+ Lyrics Line %1
+
+
+
+ Append Cell
+ Append Cell
+
+
+
+ PluginView
+
+
+ Restart %1?
+ Restart %1?
+
+
+
+ After restart, plugin changes will be applied.
+ After restart, plugin changes will be applied.
+
+
+
+ Enabling %1 will also enable the following plugins:
+ Enabling %1 will also enable the following plugins:
+
+
+
+
+ Continue?
+ Continue?
+
+
+
+ Disabling %1 will also disable the following plugins:
+ Disabling %1 will also disable the following plugins:
+
+
+
+
+ Restart required
+ Restart required
+
+
+
+ Back
+ Back
+
+
+
+ Plugin name
+ Plugin name
+
+
+
+ Vendor
+ Vendor
+
+
+
+ Version
+ Version
+
+
+
+ Visit plugin homepage
+ Visit plugin homepage
+
+
+
+ Description
+ Description
+
+
+
+ Required
+ Required
+
+
+
+ Enabled
+ Enabled
+
+
+
+ Disabled
+ Disabled
+
+
+
+ Plugin status: Error
+ Plugin status: Error
+
+
+
+ Plugin status: Not loaded
+ Plugin status: Not loaded
+
+
+
+ Plugin status: Loaded
+ Plugin status: Loaded
+
+
+
+ Error details
+ Error details
+
+
+
+ Details
+ Details
+
+
+
+ Dependencies
+ Dependencies
+
+
+
+ Plugins required by this plugin, including indirect dependencies
+ Plugins required by this plugin, including indirect dependencies
+
+
+
+ Dependents
+ Dependents
+
+
+
+ Plugins that require this plugin, including indirect dependants
+ Plugins that require this plugin, including indirect dependants
+
+
+
+ Additional Info
+ Additional Info
+
+
+
+ Identifier
+ Identifier
+
+
+
+ Category
+ Category
+
+
+
+ Path
+ Path
+
+
+
+ Reveal in %1
+ Reveal in %1
+
+
+ Finder
+ Finder
+
+
+ File Explorer
+ File Explorer
+
+
+
+ Compat version
+ Compat version
+
+
+
+ Copyright
+ Copyright
+
+
+
+ License
+ License
+
+
+
+ This plugin does not require other plugins.
+ This plugin does not require other plugins.
+
+
+
+ No plugins require this plugin.
+ No plugins require this plugin.
+
+
+
+ Plugin is not available on this platform.
+ Plugin is not available on this platform.
+
+
+
+ Plugin is enabled as dependency of an enabled plugin.
+ Plugin is enabled as dependency of an enabled plugin.
+
+
+
+ Plugin is enabled by command line argument.
+ Plugin is enabled by command line argument.
+
+
+
+ Plugin is disabled by command line argument.
+ Plugin is disabled by command line argument.
+
+
+
+ Search
+ Search
+
+
+
+ No result found
+ No result found
+
+
+
+ ProjectWindow
+
+
+ Empty
+ Empty
+
+
+
+ Left Docking View
+ Left Docking View
+
+
+
+ Top Docking View
+ Top Docking View
+
+
+
+ Bottom Docking View
+ Bottom Docking View
+
+
+
+ Right Docking View
+ Right Docking View
+
+
+
+ SettingDialog
+
+
+ Settings
+ Settings
+
+
+
+
+ Search
+ Search
+
+
+
+ No result found
+ No result found
+
+
+
+ This page is in compatibility mode
+ This page is in compatibility mode
+
+
+
+ This settings page cannot be displayed because its type is not supported.
+ This settings page cannot be displayed because its type is not supported.
+
+
+
+ Cannot Apply Settings
+ Cannot Apply Settings
+
+
+
+ Failed to apply "%1"
+ Failed to apply "%1"
+
+
+
+ OK
+ OK
+
+
+
+ Cancel
+ Cancel
+
+
+
+ Apply
+ Apply
+
+
+
+ TempoTimeSignatureIndicator
+
+
+ Tempo
+ Tempo
+
+
+
+ Time Signature
+ Time Signature
+
+
+
+ WelcomeWizardDialog
+
+
+
+ Welcome
+ Welcome
+
+
+
+ Logo of %1
+ Logo of %1
+
+
+
+ This wizard will help you complete the initial configuration
+ This wizard will help you complete the initial configuration
+
+
+
+ Skip
+ Skip
+
+
+
+ Previous
+ Previous
+
+
+
+ Continue
+ Continue
+
+
+
+ Next
+ Next
+
+
+
+ Finish
+ Finish
+
+
+
diff --git a/src/libs/application/uishell/share/translations/uishell_en_US.ts b/src/libs/application/uishell/share/translations/uishell_en_US.ts
index 5e0fb864..91e0caa2 100644
--- a/src/libs/application/uishell/share/translations/uishell_en_US.ts
+++ b/src/libs/application/uishell/share/translations/uishell_en_US.ts
@@ -1,571 +1,584 @@
-
+
ActionLayoutsEditor
-
- Action
- Action
+
+ Action
+ Action
-
- Menu
- Menu
+
+ Menu
+ Menu
-
- Action group
- Action group
+
+ Action group
+ Action group
-
- Separator
- Separator
+
+ Separator
+ Separator
-
- Stretch
- Stretch
+
+ Stretch
+ Stretch
-
-
+
+
BubbleNotification
-
- Do Not Show Again
- Do Not Show Again
+
+ Do Not Show Again
+ Do Not Show Again
-
- Collapse to Notifications Panel
- Collapse to Notifications Panel
+
+ Collapse to Notifications Panel
+ Collapse to Notifications Panel
-
- Clear
- Clear
+
+ Clear
+ Clear
-
- Abort
- Abort
+
+ Abort
+ Abort
-
-
+
+
DigitalClock
-
- Digital clock
- Digital clock
+
+ Digital clock
+ Digital clock
-
-
+
+
+ FileView
+
+
+ New project
+ New project
+
+
+
+ No result found
+ No result found
+
+
+
HomeWindow
-
- Empty
- Empty
+
+ Empty
+ Empty
-
- Open
- Open
+ Open
+ Open
- Open File Location
- Open File Location
+ Open File Location
+ Open File Location
-
- Reveal in %1
- Reveal in %1
+ Reveal in %1
+ Reveal in %1
-
- Remove from "Recovery Files"
- Remove from "Recovery Files"
+ Remove from "Recovery Files"
+ Remove from "Recovery Files"
-
- Remove from "Recent Files"
- Remove from "Recent Files"
+ Remove from "Recent Files"
+ Remove from "Recent Files"
-
- Recent Files
- Recent Files
+ Recent Files
+ Recent Files
-
- Recovery Files
- Recovery Files
+ Recovery Files
+ Recovery Files
-
- New project
- New project
+ New project
+ New project
-
-
- Search
- Search
+ Search
+ Search
-
- Grid view
- Grid view
+ Grid view
+ Grid view
-
- List view
- List view
+ List view
+ List view
-
- No result found
- No result found
+ No result found
+ No result found
-
- No recovery file
+ No recovery file
If %1 crashes, automatic recovery files will be displayed here.
- No recovery file
+ No recovery file
If %1 crashes, automatic recovery files will be displayed here.
-
-
+
+
InitializationFailureWarningDialog
-
- %1 exited abnormally during the last initialization
- %1 exited abnormally during the last initialization
+
+ %1 exited abnormally during the last initialization
+ %1 exited abnormally during the last initialization
-
- This is probably caused by a faulty plugin. Please <a href="#logs">check the logs</a> for more information.<br/><br/>You may view the plugin list and disable some plugins.
- This is probably caused by a faulty plugin. Please <a href="#logs">check the logs</a> for more information.<br/><br/>You may view the plugin list and disable some plugins.
+
+ This is probably caused by a faulty plugin. Please <a href="#logs">check the logs</a> for more information.<br/><br/>You may view the plugin list and disable some plugins.
+ This is probably caused by a faulty plugin. Please <a href="#logs">check the logs</a> for more information.<br/><br/>You may view the plugin list and disable some plugins.
-
-
+
+
LyricPronunciationEditor
-
- Lyric Pronunciation Editor
- Lyric Pronunciation Editor
+
+ Lyric Pronunciation Editor
+ Lyric Pronunciation Editor
-
- Current pronunciation is %1. Candidate pronunciations are %2. Activate to modify pronunciation.
- Current pronunciation is %1. Candidate pronunciations are %2. Activate to modify pronunciation.
+
+ Current pronunciation is %1. Candidate pronunciations are %2. Activate to modify pronunciation.
+ Current pronunciation is %1. Candidate pronunciations are %2. Activate to modify pronunciation.
-
- Customize pronunciation of "%1"
- Customize pronunciation of "%1"
+
+ Customize pronunciation of "%1"
+ Customize pronunciation of "%1"
-
- OK
- OK
+
+ OK
+ OK
-
- Edit lyric
- Edit lyric
+
+ Edit lyric
+ Edit lyric
-
- Customize Pronunciation...
- Customize Pronunciation...
+
+ Customize Pronunciation...
+ Customize Pronunciation...
-
- Edit Lyric...
- Edit Lyric...
+
+ Edit Lyric...
+ Edit Lyric...
-
- Insert Cell Before
- Insert Cell Before
+
+ Insert Cell Before
+ Insert Cell Before
-
- Insert Cell After
- Insert Cell After
+
+ Insert Cell After
+ Insert Cell After
-
- Delete Cell
- Delete Cell
+
+ Delete Cell
+ Delete Cell
-
-
- Insert Line Before
- Insert Line Before
+
+
+ Insert Line Before
+ Insert Line Before
-
-
- Insert Line After
- Insert Line After
+
+
+ Insert Line After
+ Insert Line After
-
-
- Delete Line
- Delete Line
+
+
+ Delete Line
+ Delete Line
-
- Lyrics Line %1
- Lyrics Line %1
+
+ Lyrics Line %1
+ Lyrics Line %1
-
- Append Cell
- Append Cell
+
+ Append Cell
+ Append Cell
-
-
+
+
PluginView
-
- Restart %1?
- Restart %1?
+
+ Restart %1?
+ Restart %1?
-
- After restart, plugin changes will be applied.
- After restart, plugin changes will be applied.
+
+ After restart, plugin changes will be applied.
+ After restart, plugin changes will be applied.
-
- Enabling %1 will also enable the following plugins:
- Enabling %1 will also enable the following plugins:
+
+ Enabling %1 will also enable the following plugins:
+ Enabling %1 will also enable the following plugins:
-
-
- Continue?
- Continue?
+
+
+ Continue?
+ Continue?
-
- Disabling %1 will also disable the following plugins:
- Disabling %1 will also disable the following plugins:
+
+ Disabling %1 will also disable the following plugins:
+ Disabling %1 will also disable the following plugins:
-
-
- Restart required
- Restart required
+
+
+ Restart required
+ Restart required
-
- Back
- Back
+
+ Back
+ Back
-
- Plugin name
- Plugin name
+
+ Plugin name
+ Plugin name
-
- Vendor
- Vendor
+
+ Vendor
+ Vendor
-
- Version
- Version
+
+ Version
+ Version
-
- Visit plugin homepage
- Visit plugin homepage
+
+ Visit plugin homepage
+ Visit plugin homepage
-
- Description
- Description
+
+ Description
+ Description
-
- Required
- Required
+
+ Required
+ Required
-
- Enabled
- Enabled
+
+ Enabled
+ Enabled
-
- Disabled
- Disabled
+
+ Disabled
+ Disabled
-
- Plugin status: Error
- Plugin status: Error
+
+ Plugin status: Error
+ Plugin status: Error
-
- Plugin status: Not loaded
- Plugin status: Not loaded
+
+ Plugin status: Not loaded
+ Plugin status: Not loaded
-
- Plugin status: Loaded
- Plugin status: Loaded
+
+ Plugin status: Loaded
+ Plugin status: Loaded
-
- Error details
- Error details
+
+ Error details
+ Error details
-
- Details
- Details
+
+ Details
+ Details
-
- Dependencies
- Dependencies
+
+ Dependencies
+ Dependencies
-
- Plugins required by this plugin, including indirect dependencies
- Plugins required by this plugin, including indirect dependencies
+
+ Plugins required by this plugin, including indirect dependencies
+ Plugins required by this plugin, including indirect dependencies
-
- Dependents
- Dependents
+
+ Dependents
+ Dependents
-
- Plugins that require this plugin, including indirect dependants
- Plugins that require this plugin, including indirect dependants
+
+ Plugins that require this plugin, including indirect dependants
+ Plugins that require this plugin, including indirect dependants
-
- Additional Info
- Additional Info
+
+ Additional Info
+ Additional Info
-
- Identifier
- Identifier
+
+ Identifier
+ Identifier
-
- Category
- Category
+
+ Category
+ Category
-
- Path
- Path
+
+ Path
+ Path
-
- Reveal in %1
- Reveal in %1
+
+ Reveal in %1
+ Reveal in %1
- Finder
- Finder
+ Finder
+ Finder
- File Explorer
- File Explorer
+ File Explorer
+ File Explorer
-
- Compat version
- Compat version
+
+ Compat version
+ Compat version
-
- Copyright
- Copyright
+
+ Copyright
+ Copyright
-
- License
- License
+
+ License
+ License
-
- This plugin does not require other plugins.
- This plugin does not require other plugins.
+
+ This plugin does not require other plugins.
+ This plugin does not require other plugins.
-
- No plugins require this plugin.
- No plugins require this plugin.
+
+ No plugins require this plugin.
+ No plugins require this plugin.
-
- Plugin is not available on this platform.
- Plugin is not available on this platform.
+
+ Plugin is not available on this platform.
+ Plugin is not available on this platform.
-
- Plugin is enabled as dependency of an enabled plugin.
- Plugin is enabled as dependency of an enabled plugin.
+
+ Plugin is enabled as dependency of an enabled plugin.
+ Plugin is enabled as dependency of an enabled plugin.
-
- Plugin is enabled by command line argument.
- Plugin is enabled by command line argument.
+
+ Plugin is enabled by command line argument.
+ Plugin is enabled by command line argument.
-
- Plugin is disabled by command line argument.
- Plugin is disabled by command line argument.
+
+ Plugin is disabled by command line argument.
+ Plugin is disabled by command line argument.
-
- Search
- Search
+
+ Search
+ Search
-
- No result found
- No result found
+
+ No result found
+ No result found
-
-
+
+
ProjectWindow
-
- Empty
- Empty
+
+ Empty
+ Empty
-
- Left Docking View
- Left Docking View
+
+ Left Docking View
+ Left Docking View
-
- Top Docking View
- Top Docking View
+
+ Top Docking View
+ Top Docking View
-
- Bottom Docking View
- Bottom Docking View
+
+ Bottom Docking View
+ Bottom Docking View
-
- Right Docking View
- Right Docking View
+
+ Right Docking View
+ Right Docking View
-
-
+
+
SettingDialog
-
- Settings
- Settings
+
+ Settings
+ Settings
+
+
+
+
+ Search
+ Search
+
+
+
+ No result found
+ No result found
-
-
- Search
- Search
+
+ This page is in compatibility mode
+ This page is in compatibility mode
-
- No result found
- No result found
+
+ This settings page cannot be displayed because its type is not supported.
+ This settings page cannot be displayed because its type is not supported.
-
- This page is in compatibility mode
- This page is in compatibility mode
+
+ Cannot Apply Settings
+ Cannot Apply Settings
-
- This settings page cannot be displayed because its type is not supported.
- This settings page cannot be displayed because its type is not supported.
+
+ Failed to apply "%1"
+ Failed to apply "%1"
-
- Cannot Apply Settings
- Cannot Apply Settings
+
+ OK
+ OK
-
- Failed to apply "%1"
- Failed to apply "%1"
+
+ Cancel
+ Cancel
-
- OK
- OK
+
+ Apply
+ Apply
+
+
+ TempoTimeSignatureIndicator
-
- Cancel
- Cancel
+
+ Tempo
+
-
- Apply
- Apply
+
+ Time Signature
+
-
-
+
+
WelcomeWizardDialog
-
-
- Welcome
- Welcome
+
+
+ Welcome
+ Welcome
-
- Logo of %1
- Logo of %1
+
+ Logo of %1
+ Logo of %1
-
- This wizard will help you complete the initial configuration
- This wizard will help you complete the initial configuration
+
+ This wizard will help you complete the initial configuration
+ This wizard will help you complete the initial configuration
-
- Skip
- Skip
+
+ Skip
+ Skip
-
- Previous
- Previous
+
+ Previous
+ Previous
-
- Continue
- Continue
+
+ Continue
+ Continue
-
- Next
- Next
+
+ Next
+ Next
-
- Finish
- Finish
+
+ Finish
+ Finish
-
+
diff --git a/src/libs/application/uishell/share/translations/uishell_ja_JP.ts b/src/libs/application/uishell/share/translations/uishell_ja_JP.ts
index 7eb0d3a0..94f96677 100644
--- a/src/libs/application/uishell/share/translations/uishell_ja_JP.ts
+++ b/src/libs/application/uishell/share/translations/uishell_ja_JP.ts
@@ -4,27 +4,27 @@
ActionLayoutsEditor
-
+
Action
Action
-
+
Menu
Menu
-
+
Action group
Action group
-
+
Separator
Separator
-
+
Stretch
Stretch
@@ -32,22 +32,22 @@
BubbleNotification
-
+
Do Not Show Again
Do Not Show Again
-
+
Collapse to Notifications Panel
Collapse to Notifications Panel
-
+
Clear
Clear
-
+
Abort
Abort
@@ -60,15 +60,27 @@
Digital clock
+
+ FileView
+
+
+ New project
+ New project
+
+
+
+ No result found
+ No result found
+
+
HomeWindow
-
+
Empty
Empty
-
Open
Open
@@ -77,58 +89,46 @@
Open File Location
-
Reveal in %1
Reveal in %1
-
Remove from "Recovery Files"
Remove from "Recovery Files"
-
Remove from "Recent Files"
Remove from "Recent Files"
-
Recent Files
Recent Files
-
Recovery Files
Recovery Files
-
New project
New project
-
-
Search
Search
-
Grid view
Grid view
-
List view
List view
-
No result found
No result found
-
No recovery file
If %1 crashes, automatic recovery files will be displayed here.
No recovery file
@@ -258,123 +258,123 @@ If %1 crashes, automatic recovery files will be displayed here.
Disabling %1 will also disable the following plugins:
-
-
+
+
Restart required
Restart required
-
+
Back
Back
-
+
Plugin name
Plugin name
-
+
Vendor
Vendor
-
+
Version
Version
-
+
Visit plugin homepage
Visit plugin homepage
-
+
Description
Description
-
+
Required
Required
-
+
Enabled
Enabled
-
+
Disabled
Disabled
-
+
Plugin status: Error
Plugin status: Error
-
+
Plugin status: Not loaded
Plugin status: Not loaded
-
+
Plugin status: Loaded
Plugin status: Loaded
-
+
Error details
Error details
-
+
Details
Details
-
+
Dependencies
Dependencies
-
+
Plugins required by this plugin, including indirect dependencies
Plugins required by this plugin, including indirect dependencies
-
+
Dependents
Dependents
-
+
Plugins that require this plugin, including indirect dependants
Plugins that require this plugin, including indirect dependants
-
+
Additional Info
Additional Info
-
+
Identifier
Identifier
-
+
Category
Category
-
+
Path
Path
-
+
Reveal in %1
Reveal in %1
@@ -387,57 +387,57 @@ If %1 crashes, automatic recovery files will be displayed here.
File Explorer
-
+
Compat version
Compat version
-
+
Copyright
Copyright
-
+
License
License
-
+
This plugin does not require other plugins.
This plugin does not require other plugins.
-
+
No plugins require this plugin.
No plugins require this plugin.
-
+
Plugin is not available on this platform.
Plugin is not available on this platform.
-
+
Plugin is enabled as dependency of an enabled plugin.
Plugin is enabled as dependency of an enabled plugin.
-
+
Plugin is enabled by command line argument.
Plugin is enabled by command line argument.
-
+
Plugin is disabled by command line argument.
Plugin is disabled by command line argument.
-
+
Search
Search
-
+
No result found
No result found
@@ -445,27 +445,27 @@ If %1 crashes, automatic recovery files will be displayed here.
ProjectWindow
-
+
Empty
Empty
-
+
Left Docking View
Left Docking View
-
+
Top Docking View
Top Docking View
-
+
Bottom Docking View
Bottom Docking View
-
+
Right Docking View
Right Docking View
@@ -478,52 +478,65 @@ If %1 crashes, automatic recovery files will be displayed here.
Settings
-
+
Search
Search
-
+
No result found
No result found
-
+
This page is in compatibility mode
This page is in compatibility mode
-
+
This settings page cannot be displayed because its type is not supported.
This settings page cannot be displayed because its type is not supported.
-
+
Cannot Apply Settings
Cannot Apply Settings
-
+
Failed to apply "%1"
Failed to apply "%1"
-
+
OK
OK
-
+
Cancel
Cancel
-
+
Apply
Apply
+
+ TempoTimeSignatureIndicator
+
+
+ Tempo
+ Tempo
+
+
+
+ Time Signature
+ Time Signature
+
+
WelcomeWizardDialog
diff --git a/src/libs/application/uishell/share/translations/uishell_zh_CN.ts b/src/libs/application/uishell/share/translations/uishell_zh_CN.ts
index 87eb5532..8d8bea39 100644
--- a/src/libs/application/uishell/share/translations/uishell_zh_CN.ts
+++ b/src/libs/application/uishell/share/translations/uishell_zh_CN.ts
@@ -4,27 +4,27 @@
ActionLayoutsEditor
-
+
Action
操作
-
+
Menu
菜单
-
+
Action group
操作组
-
+
Separator
分隔线
-
+
Stretch
拉伸
@@ -32,22 +32,22 @@
BubbleNotification
-
+
Do Not Show Again
不再显示
-
+
Collapse to Notifications Panel
折叠到通知面板
-
+
Clear
清除
-
+
Abort
中止
@@ -60,15 +60,27 @@
数字时钟
+
+ FileView
+
+
+ New project
+ 新建工程
+
+
+
+ No result found
+ 未找到结果
+
+
HomeWindow
-
+
Empty
空
-
Open
打开
@@ -77,58 +89,46 @@
打开文件位置
-
Reveal in %1
在 %1 中显示
-
Remove from "Recovery Files"
从“恢复文件”移除
-
Remove from "Recent Files"
从“最近文件”移除
-
Recent Files
最近文件
-
Recovery Files
恢复文件
-
New project
新建工程
-
-
Search
搜索
-
Grid view
网格视图
-
List view
列表视图
-
No result found
未找到结果
-
No recovery file
If %1 crashes, automatic recovery files will be displayed here.
无恢复文件
@@ -258,123 +258,123 @@ If %1 crashes, automatic recovery files will be displayed here.
禁用 %1 还会禁用以下插件:
-
-
+
+
Restart required
需要重新启动
-
+
Back
返回
-
+
Plugin name
插件名
-
+
Vendor
供应商
-
+
Version
版本
-
+
Visit plugin homepage
访问插件主页
-
+
Description
描述
-
+
Required
必需
-
+
Enabled
已启用
-
+
Disabled
已禁用
-
+
Plugin status: Error
插件状态:错误
-
+
Plugin status: Not loaded
插件状态:未加载
-
+
Plugin status: Loaded
插件状态:已加载
-
+
Error details
错误详情
-
+
Details
详情
-
+
Dependencies
依赖项
-
+
Plugins required by this plugin, including indirect dependencies
此插件需要的其他插件,包括间接依赖
-
+
Dependents
被依赖项
-
+
Plugins that require this plugin, including indirect dependants
需要此插件的其他插件,包括间接依赖
-
+
Additional Info
附加信息
-
+
Identifier
标识符
-
+
Category
类别
-
+
Path
路径
-
+
Reveal in %1
在 %1 中显示
@@ -387,57 +387,57 @@ If %1 crashes, automatic recovery files will be displayed here.
文件资源管理器
-
+
Compat version
兼容版本
-
+
Copyright
版权
-
+
License
许可证
-
+
This plugin does not require other plugins.
此插件不需要其他插件。
-
+
No plugins require this plugin.
没有插件需要此插件。
-
+
Plugin is not available on this platform.
插件在当前平台上不可用。
-
+
Plugin is enabled as dependency of an enabled plugin.
插件作为一个已启用的插件的依赖项而启用。
-
+
Plugin is enabled by command line argument.
插件被命令行参数启用。
-
+
Plugin is disabled by command line argument.
插件被命令行参数禁用。
-
+
Search
搜索
-
+
No result found
未找到结果
@@ -445,27 +445,27 @@ If %1 crashes, automatic recovery files will be displayed here.
ProjectWindow
-
+
Empty
空
-
+
Left Docking View
左侧停靠视图
-
+
Top Docking View
顶部停靠视图
-
+
Bottom Docking View
底部停靠视图
-
+
Right Docking View
右侧停靠视图
@@ -478,52 +478,65 @@ If %1 crashes, automatic recovery files will be displayed here.
设置
-
+
Search
搜索
-
+
No result found
未找到结果
-
+
This page is in compatibility mode
此页面处于兼容模式
-
+
This settings page cannot be displayed because its type is not supported.
此设置页面无法被显示,因为其类型不受支持。
-
+
Cannot Apply Settings
无法应用设置
-
+
Failed to apply "%1"
应用“%1”失败
-
+
OK
确定
-
+
Cancel
取消
-
+
Apply
应用
+
+ TempoTimeSignatureIndicator
+
+
+ Tempo
+ 曲速
+
+
+
+ Time Signature
+ 拍号
+
+
WelcomeWizardDialog
diff --git a/src/libs/application/uishell/share/translations/uishell_zh_TW.ts b/src/libs/application/uishell/share/translations/uishell_zh_TW.ts
index 4880c73c..d0a04747 100644
--- a/src/libs/application/uishell/share/translations/uishell_zh_TW.ts
+++ b/src/libs/application/uishell/share/translations/uishell_zh_TW.ts
@@ -4,27 +4,27 @@
ActionLayoutsEditor
-
+
Action
Action
-
+
Menu
Menu
-
+
Action group
Action group
-
+
Separator
Separator
-
+
Stretch
Stretch
@@ -32,22 +32,22 @@
BubbleNotification
-
+
Do Not Show Again
Do Not Show Again
-
+
Collapse to Notifications Panel
Collapse to Notifications Panel
-
+
Clear
Clear
-
+
Abort
Abort
@@ -60,15 +60,27 @@
Digital clock
+
+ FileView
+
+
+ New project
+ New project
+
+
+
+ No result found
+ No result found
+
+
HomeWindow
-
+
Empty
Empty
-
Open
Open
@@ -77,58 +89,46 @@
Open File Location
-
Reveal in %1
Reveal in %1
-
Remove from "Recovery Files"
Remove from "Recovery Files"
-
Remove from "Recent Files"
Remove from "Recent Files"
-
Recent Files
Recent Files
-
Recovery Files
Recovery Files
-
New project
New project
-
-
Search
Search
-
Grid view
Grid view
-
List view
List view
-
No result found
No result found
-
No recovery file
If %1 crashes, automatic recovery files will be displayed here.
No recovery file
@@ -258,123 +258,123 @@ If %1 crashes, automatic recovery files will be displayed here.
Disabling %1 will also disable the following plugins:
-
-
+
+
Restart required
Restart required
-
+
Back
Back
-
+
Plugin name
Plugin name
-
+
Vendor
Vendor
-
+
Version
Version
-
+
Visit plugin homepage
Visit plugin homepage
-
+
Description
Description
-
+
Required
Required
-
+
Enabled
Enabled
-
+
Disabled
Disabled
-
+
Plugin status: Error
Plugin status: Error
-
+
Plugin status: Not loaded
Plugin status: Not loaded
-
+
Plugin status: Loaded
Plugin status: Loaded
-
+
Error details
Error details
-
+
Details
Details
-
+
Dependencies
Dependencies
-
+
Plugins required by this plugin, including indirect dependencies
Plugins required by this plugin, including indirect dependencies
-
+
Dependents
Dependents
-
+
Plugins that require this plugin, including indirect dependants
Plugins that require this plugin, including indirect dependants
-
+
Additional Info
Additional Info
-
+
Identifier
Identifier
-
+
Category
Category
-
+
Path
Path
-
+
Reveal in %1
Reveal in %1
@@ -387,57 +387,57 @@ If %1 crashes, automatic recovery files will be displayed here.
File Explorer
-
+
Compat version
Compat version
-
+
Copyright
Copyright
-
+
License
License
-
+
This plugin does not require other plugins.
This plugin does not require other plugins.
-
+
No plugins require this plugin.
No plugins require this plugin.
-
+
Plugin is not available on this platform.
Plugin is not available on this platform.
-
+
Plugin is enabled as dependency of an enabled plugin.
Plugin is enabled as dependency of an enabled plugin.
-
+
Plugin is enabled by command line argument.
Plugin is enabled by command line argument.
-
+
Plugin is disabled by command line argument.
Plugin is disabled by command line argument.
-
+
Search
Search
-
+
No result found
No result found
@@ -445,27 +445,27 @@ If %1 crashes, automatic recovery files will be displayed here.
ProjectWindow
-
+
Empty
Empty
-
+
Left Docking View
Left Docking View
-
+
Top Docking View
Top Docking View
-
+
Bottom Docking View
Bottom Docking View
-
+
Right Docking View
Right Docking View
@@ -478,52 +478,65 @@ If %1 crashes, automatic recovery files will be displayed here.
Settings
-
+
Search
Search
-
+
No result found
No result found
-
+
This page is in compatibility mode
This page is in compatibility mode
-
+
This settings page cannot be displayed because its type is not supported.
This settings page cannot be displayed because its type is not supported.
-
+
Cannot Apply Settings
Cannot Apply Settings
-
+
Failed to apply "%1"
Failed to apply "%1"
-
+
OK
OK
-
+
Cancel
Cancel
-
+
Apply
Apply
+
+ TempoTimeSignatureIndicator
+
+
+ Tempo
+ Tempo
+
+
+
+ Time Signature
+ Time Signature
+
+
WelcomeWizardDialog
diff --git a/src/libs/application/uishell/src/PlatformWindowModifiedHelper.cpp b/src/libs/application/uishell/src/PlatformWindowModifiedHelper.cpp
new file mode 100644
index 00000000..333ed534
--- /dev/null
+++ b/src/libs/application/uishell/src/PlatformWindowModifiedHelper.cpp
@@ -0,0 +1,53 @@
+#include "PlatformWindowModifiedHelper_p.h"
+
+#include
+
+namespace UIShell {
+
+ PlatformWindowModifiedHelper::PlatformWindowModifiedHelper(QObject *parent) : QObject(parent) {
+ }
+
+ PlatformWindowModifiedHelper::~PlatformWindowModifiedHelper() = default;
+
+ QWindow *PlatformWindowModifiedHelper::window() const {
+ return m_window;
+ }
+
+ void PlatformWindowModifiedHelper::setWindow(QWindow *window) {
+ if (m_window == window)
+ return;
+
+ m_window = window;
+ Q_EMIT windowChanged();
+
+ // Update platform window modified state when window changes
+ updatePlatformWindowModified();
+ }
+
+ bool PlatformWindowModifiedHelper::windowModified() const {
+ return m_windowModified;
+ }
+
+ void PlatformWindowModifiedHelper::setWindowModified(bool modified) {
+ if (m_windowModified == modified)
+ return;
+
+ m_windowModified = modified;
+ Q_EMIT windowModifiedChanged();
+
+ // Update platform window modified state when modified flag changes
+ updatePlatformWindowModified();
+ }
+
+ void PlatformWindowModifiedHelper::updatePlatformWindowModified() {
+ if (!m_window)
+ return;
+
+ QPlatformWindow *platformWindow = m_window->handle();
+ if (!platformWindow)
+ return;
+
+ platformWindow->setWindowModified(m_windowModified);
+ }
+
+}
diff --git a/src/libs/application/uishell/src/PlatformWindowModifiedHelper_p.h b/src/libs/application/uishell/src/PlatformWindowModifiedHelper_p.h
new file mode 100644
index 00000000..aa7e0f69
--- /dev/null
+++ b/src/libs/application/uishell/src/PlatformWindowModifiedHelper_p.h
@@ -0,0 +1,40 @@
+#ifndef UISHELL_PLATFORMWINDOWMODIFIEDHELPER_P_H
+#define UISHELL_PLATFORMWINDOWMODIFIEDHELPER_P_H
+
+#include
+#include
+#include
+
+namespace UIShell {
+
+ class PlatformWindowModifiedHelper : public QObject {
+ Q_OBJECT
+ QML_ELEMENT
+
+ Q_PROPERTY(QWindow *window READ window WRITE setWindow NOTIFY windowChanged)
+ Q_PROPERTY(bool windowModified READ windowModified WRITE setWindowModified NOTIFY windowModifiedChanged)
+
+ public:
+ explicit PlatformWindowModifiedHelper(QObject *parent = nullptr);
+ ~PlatformWindowModifiedHelper() override;
+
+ QWindow *window() const;
+ void setWindow(QWindow *window);
+
+ bool windowModified() const;
+ void setWindowModified(bool modified);
+
+ Q_SIGNALS:
+ void windowChanged();
+ void windowModifiedChanged();
+
+ private:
+ void updatePlatformWindowModified();
+
+ QWindow *m_window = nullptr;
+ bool m_windowModified = false;
+ };
+
+}
+
+#endif // UISHELL_PLATFORMWINDOWMODIFIEDHELPER_P_H
diff --git a/src/libs/application/uishell/src/qml/ProjectWindow.qml b/src/libs/application/uishell/src/qml/ProjectWindow.qml
index 8bffa724..64075618 100644
--- a/src/libs/application/uishell/src/qml/ProjectWindow.qml
+++ b/src/libs/application/uishell/src/qml/ProjectWindow.qml
@@ -176,7 +176,7 @@ Window {
id: titleBarArea
Layout.fillWidth: true
Layout.fillHeight: !window.isMacOS
- Layout.preferredHeight: window.isMacOS ? titleBar.height + toolBar.height : 0
+ Layout.preferredHeight: window.isMacOS ? titleBar.height + (toolBar.visible ? toolBar.height : 0) : 0
RowLayout {
anchors.right: parent.right
visible: !window.isMacOS
@@ -238,7 +238,7 @@ Window {
}
}
PaneSeparator {
- visible: !window.isMacOS
+ visible: !window.isMacOS && ((separatedMenuParent.visible && menuBar.visualVisible) || toolBar.visible)
}
Rectangle {
id: separatedMenuParent
@@ -249,7 +249,7 @@ Window {
// FIXME remove spacing when visual invisible
}
PaneSeparator {
- visible: separatedMenuParent.visible && menuBar.visualVisible
+ visible: separatedMenuParent.visible && menuBar.visualVisible && toolBar.visible
}
ToolBar {
id: toolBar
@@ -317,7 +317,9 @@ Window {
}
}
}
- PaneSeparator {}
+ PaneSeparator {
+
+ }
Item {
id: mainPane
readonly property double minimumPanelSize: 64
@@ -429,7 +431,9 @@ Window {
}
}
}
- PaneSeparator {}
+ PaneSeparator {
+ visible: statusBar.visible
+ }
ToolBar {
id: statusBar
Accessible.role: Accessible.StatusBar
diff --git a/src/plugins/audio/res/translations/org.diffscope.audio.ts b/src/plugins/audio/res/translations/org.diffscope.audio.ts
new file mode 100644
index 00000000..db57ea97
--- /dev/null
+++ b/src/plugins/audio/res/translations/org.diffscope.audio.ts
@@ -0,0 +1,511 @@
+
+
+
+
+
+
+
+ Main Menu
+ Main Menu
+
+
+
+ Application
+
+
+ Version %1
+ Version %1
+
+
+
+ Copyright © %1-%2 %3. All rights reserved.
+ Copyright © %1-%2 %3. All rights reserved.
+
+
+
+ Application::ActionText
+
+ Main Menu
+ Main Menu
+
+
+
+ Audio::Internal::AudioAndMidiPage
+
+
+ Audio and MIDI
+ Audio and MIDI
+
+
+
+ Configure audio and MIDI preferences
+ Configure audio and MIDI preferences
+
+
+
+ Audio::Internal::AudioOutputPage
+
+
+ Audio Output
+ Audio Output
+
+
+
+ Configure the audio driver and device for output
+ Configure the audio driver and device for output
+
+
+
+ Audio::Internal::AudioOutputSettingsHelper
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (Not working)
+ (Not working)
+
+
+
+ Cannot initialize %1 driver
+ Cannot initialize %1 driver
+
+
+
+
+
+
+
+
+
+ Default device
+ Default device
+
+
+
+ Audio device %1 is not available
+ Audio device %1 is not available
+
+
+
+ Cannot set sample rate to %1
+ Cannot set sample rate to %1
+
+
+
+ Cannot set buffer size to %1
+ Cannot set buffer size to %1
+
+
+
+ Audio::Internal::AudioPlugin
+
+
+ Initializing audio plugin...
+ Initializing audio plugin...
+
+
+
+ Failed to initialize audio output system
+ Failed to initialize audio output system
+
+
+
+ %1 will not play sound because no available audio output device found.
+
+Please go to Settings > Audio and MIDI > Audio Output to check the device status.
+ %1 will not play sound because no available audio output device found.
+
+Please go to Settings > Audio and MIDI > Audio Output to check the device status.
+
+
+
+ Audio::Internal::AudioTroubleshootingDialog
+
+
+ Audio Output Troubleshooting Wizard
+ Audio Output Troubleshooting Wizard
+
+
+
+ Audio::Internal::ConfigurePage
+
+
+ <h3>Configure Audio Device</h3>
+ <h3>Configure Audio Device</h3>
+
+
+
+ Please select a working audio driver and device.
+ Please select a working audio driver and device.
+
+
+
+ <p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
+ <p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
+
+
+
+ Audio d&river
+ Audio d&river
+
+
+
+ Audio &device
+ Audio &device
+
+
+
+ &Sample rate
+ &Sample rate
+
+
+
+ &Buffer size
+ &Buffer size
+
+
+
+ &Test
+ &Test
+
+
+
+ <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
+ <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
+
+
+
+ Have you selected a working audio device which plays sound after clicking the "Test" button?
+ Have you selected a working audio device which plays sound after clicking the "Test" button?
+
+
+
+ &Yes
+ &Yes
+
+
+
+ I have selected a working audio device
+ I have selected a working audio device
+
+
+
+ &No
+ &No
+
+
+
+ The device is either not available or not able to play sound
+ The device is either not available or not able to play sound
+
+
+
+ Audio::Internal::ExternalCheckPage
+
+
+ Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
+ Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
+
+
+
+ &Open System Settings
+ &Open System Settings
+
+
+
+ &Open Control Panel
+ &Open Control Panel
+
+
+
+ <p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
+ <p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
+
+
+
+ Are audio devices configured properly and able to be played by other applications?
+ Are audio devices configured properly and able to be played by other applications?
+
+
+
+ &Yes
+ &Yes
+
+
+
+ The audio device work well on my system. I want to retry configuring it in %1
+ The audio device work well on my system. I want to retry configuring it in %1
+
+
+
+ Not &exactly
+ Not &exactly
+
+
+
+ Even though other applications can play sound, I fail to configure the audio device in %1
+ Even though other applications can play sound, I fail to configure the audio device in %1
+
+
+
+ &No
+ &No
+
+
+
+ Other applications also cannot play sound
+ Other applications also cannot play sound
+
+
+
+ &I'm not sure
+ &I'm not sure
+
+
+
+ %1 cannot open the control panel on your system. Please open it manually
+ %1 cannot open the control panel on your system. Please open it manually
+
+
+
+ Audio::Internal::ResultFailPage
+
+
+ Please send us a feedback.
+ Please send us a feedback.
+
+
+
+ <p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
+ <p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
+
+
+
+ Audio::Internal::ResultOkPage
+
+
+ <h3>Everything Is OK</h3>
+ <h3>Everything Is OK</h3>
+
+
+
+ There are no problems with audio output at the moment.
+ There are no problems with audio output at the moment.
+
+
+
+ <p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
+ <p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
+
+
+
+ Audio::Internal::TestPage
+
+
+ <h3>Test Audio Device</h3>
+ <h3>Test Audio Device</h3>
+
+
+
+ The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
+ The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
+
+
+
+ &Test
+ &Test
+
+
+
+ <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
+ <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
+
+
+
+ Is any sound played after clicking the "Test" button?
+ Is any sound played after clicking the "Test" button?
+
+
+
+ &Yes
+ &Yes
+
+
+
+ I can hear the test sound played by the audio device
+ I can hear the test sound played by the audio device
+
+
+
+ &No
+ &No
+
+
+
+ I cannot hear any sound played by the audio device
+ I cannot hear any sound played by the audio device
+
+
+
+ Audio::Internal::WelcomePage
+
+
+ <h3>Audio Output Troubleshooting Wizard</h3>
+ <h3>Audio Output Troubleshooting Wizard</h3>
+
+
+
+ This wizard will help you diagnose and resolve problems with audio output.
+ This wizard will help you diagnose and resolve problems with audio output.
+
+
+
+ &Continue
+ &Continue
+
+
+
+ AudioOutputPage
+
+
+ Device Parameters
+ Device Parameters
+
+
+
+ Audio driver
+ Audio driver
+
+
+
+ Audio device
+ Audio device
+
+
+
+ Sample rate
+ Sample rate
+
+
+
+ Buffer size
+ Buffer size
+
+
+
+ Troubleshoot...
+ Troubleshoot...
+
+
+
+ Test
+ Test
+
+
+
+ Open Control Panel
+ Open Control Panel
+
+
+
+ Mixer
+ Mixer
+
+
+
+ Device gain
+ Device gain
+
+
+
+ Device pan
+ Device pan
+
+
+
+ Hot Plug
+ Hot Plug
+
+
+
+ When device change detected
+ When device change detected
+
+
+
+ Always show notification
+ Always show notification
+
+
+
+ Show notification only when the current device is removed
+ Show notification only when the current device is removed
+
+
+
+ Do not show notification
+ Do not show notification
+
+
+
+ AudioOutputWelcomeWizardPage
+
+
+ Audio Output
+ Audio Output
+
+
+
+ Configure audio output device parameters
+ Configure audio output device parameters
+
+
+
+ Audio driver
+ Audio driver
+
+
+
+ Audio device
+ Audio device
+
+
+
+ Sample rate
+ Sample rate
+
+
+
+ Buffer size
+ Buffer size
+
+
+
+ Test
+ Test
+
+
+
+ Open Control Panel
+ Open Control Panel
+
+
+
+ Click "Test" button to check whether audio output is configured correctly
+ Click "Test" button to check whether audio output is configured correctly
+
+
+
diff --git a/src/plugins/audio/res/translations/org.diffscope.audio_en_US.ts b/src/plugins/audio/res/translations/org.diffscope.audio_en_US.ts
index af6d958b..526c8321 100644
--- a/src/plugins/audio/res/translations/org.diffscope.audio_en_US.ts
+++ b/src/plugins/audio/res/translations/org.diffscope.audio_en_US.ts
@@ -1,494 +1,511 @@
-
+
+
+
+
+ Main Menu
+ Main Menu
+
+
+
+ Application
+
+
+ Version %1
+
+
+
+
+ Copyright © %1-%2 %3. All rights reserved.
+
+
+
+
Application::ActionText
-
- Main Menu
- Main Menu
+ Main Menu
+ Main Menu
-
-
+
+
Audio::Internal::AudioAndMidiPage
-
- Audio and MIDI
- Audio and MIDI
+
+ Audio and MIDI
+ Audio and MIDI
-
- Configure audio and MIDI preferences
- Configure audio and MIDI preferences
+
+ Configure audio and MIDI preferences
+ Configure audio and MIDI preferences
-
-
+
+
Audio::Internal::AudioOutputPage
-
- Audio Output
- Audio Output
+
+ Audio Output
+ Audio Output
-
- Configure the audio driver and device for output
- Configure the audio driver and device for output
+
+ Configure the audio driver and device for output
+ Configure the audio driver and device for output
-
-
+
+
Audio::Internal::AudioOutputSettingsHelper
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- (Not working)
- (Not working)
-
-
-
- Cannot initialize %1 driver
- Cannot initialize %1 driver
-
-
-
-
-
-
-
-
-
- Default device
- Default device
-
-
-
-
- Audio device %1 is not available
- Audio device %1 is not available
-
-
-
- Cannot set sample rate to %1
- Cannot set sample rate to %1
-
-
-
- Cannot set buffer size to %1
- Cannot set buffer size to %1
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ (Not working)
+ (Not working)
+
+
+
+ Cannot initialize %1 driver
+ Cannot initialize %1 driver
+
+
+
+
+
+
+
+
+
+ Default device
+ Default device
+
+
+
+ Audio device %1 is not available
+ Audio device %1 is not available
+
+
+
+ Cannot set sample rate to %1
+ Cannot set sample rate to %1
+
+
+
+ Cannot set buffer size to %1
+ Cannot set buffer size to %1
+
+
+
Audio::Internal::AudioPlugin
-
- Initializing audio plugin...
- Initializing audio plugin...
+
+ Initializing audio plugin...
+ Initializing audio plugin...
-
- Failed to initialize audio output system
- Failed to initialize audio output system
+
+ Failed to initialize audio output system
+ Failed to initialize audio output system
-
- %1 will not play sound because no available audio output device found.
+
+ %1 will not play sound because no available audio output device found.
Please go to Settings > Audio and MIDI > Audio Output to check the device status.
- %1 will not play sound because no available audio output device found.
+ %1 will not play sound because no available audio output device found.
Please go to Settings > Audio and MIDI > Audio Output to check the device status.
-
-
+
+
Audio::Internal::AudioTroubleshootingDialog
-
- Audio Output Troubleshooting Wizard
- Audio Output Troubleshooting Wizard
+
+ Audio Output Troubleshooting Wizard
+ Audio Output Troubleshooting Wizard
-
-
+
+
Audio::Internal::ConfigurePage
-
- <h3>Configure Audio Device</h3>
- <h3>Configure Audio Device</h3>
+
+ <h3>Configure Audio Device</h3>
+ <h3>Configure Audio Device</h3>
-
- Please select a working audio driver and device.
- Please select a working audio driver and device.
+
+ Please select a working audio driver and device.
+ Please select a working audio driver and device.
-
- <p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
- <p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
+
+ <p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
+ <p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
-
- Audio d&river
- Audio d&river
+
+ Audio d&river
+ Audio d&river
-
- Audio &device
- Audio &device
+
+ Audio &device
+ Audio &device
-
- &Sample rate
- &Sample rate
+
+ &Sample rate
+ &Sample rate
-
- &Buffer size
- &Buffer size
+
+ &Buffer size
+ &Buffer size
-
- &Test
- &Test
+
+ &Test
+ &Test
-
- <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
- <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
+
+ <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
+ <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
-
- Have you selected a working audio device which plays sound after clicking the "Test" button?
- Have you selected a working audio device which plays sound after clicking the "Test" button?
+
+ Have you selected a working audio device which plays sound after clicking the "Test" button?
+ Have you selected a working audio device which plays sound after clicking the "Test" button?
-
- &Yes
- &Yes
+
+ &Yes
+ &Yes
-
- I have selected a working audio device
- I have selected a working audio device
+
+ I have selected a working audio device
+ I have selected a working audio device
-
- &No
- &No
+
+ &No
+ &No
-
- The device is either not available or not able to play sound
- The device is either not available or not able to play sound
+
+ The device is either not available or not able to play sound
+ The device is either not available or not able to play sound
-
-
+
+
Audio::Internal::ExternalCheckPage
-
- Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
- Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
+
+ Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
+ Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
-
- &Open System Settings
- &Open System Settings
+
+ &Open System Settings
+ &Open System Settings
-
- &Open Control Panel
- &Open Control Panel
+
+ &Open Control Panel
+ &Open Control Panel
-
- <p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
- <p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
+
+ <p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
+ <p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
-
- Are audio devices configured properly and able to be played by other applications?
- Are audio devices configured properly and able to be played by other applications?
+
+ Are audio devices configured properly and able to be played by other applications?
+ Are audio devices configured properly and able to be played by other applications?
-
- &Yes
- &Yes
+
+ &Yes
+ &Yes
-
- The audio device work well on my system. I want to retry configuring it in %1
- The audio device work well on my system. I want to retry configuring it in %1
+
+ The audio device work well on my system. I want to retry configuring it in %1
+ The audio device work well on my system. I want to retry configuring it in %1
-
- Not &exactly
- Not &exactly
+
+ Not &exactly
+ Not &exactly
-
- Even though other applications can play sound, I fail to configure the audio device in %1
- Even though other applications can play sound, I fail to configure the audio device in %1
+
+ Even though other applications can play sound, I fail to configure the audio device in %1
+ Even though other applications can play sound, I fail to configure the audio device in %1
-
- &No
- &No
+
+ &No
+ &No
-
- Other applications also cannot play sound
- Other applications also cannot play sound
+
+ Other applications also cannot play sound
+ Other applications also cannot play sound
-
- &I'm not sure
- &I'm not sure
+
+ &I'm not sure
+ &I'm not sure
-
- %1 cannot open the control panel on your system. Please open it manually
- %1 cannot open the control panel on your system. Please open it manually
+
+ %1 cannot open the control panel on your system. Please open it manually
+ %1 cannot open the control panel on your system. Please open it manually
-
-
+
+
Audio::Internal::ResultFailPage
-
- Please send us a feedback.
- Please send us a feedback.
+
+ Please send us a feedback.
+ Please send us a feedback.
-
- <p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
- <p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
+
+ <p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
+ <p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
-
-
+
+
Audio::Internal::ResultOkPage
-
- <h3>Everything Is OK</h3>
- <h3>Everything Is OK</h3>
+
+ <h3>Everything Is OK</h3>
+ <h3>Everything Is OK</h3>
-
- There are no problems with audio output at the moment.
- There are no problems with audio output at the moment.
+
+ There are no problems with audio output at the moment.
+ There are no problems with audio output at the moment.
-
- <p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
- <p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
+
+ <p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
+ <p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
-
-
+
+
Audio::Internal::TestPage
-
- <h3>Test Audio Device</h3>
- <h3>Test Audio Device</h3>
+
+ <h3>Test Audio Device</h3>
+ <h3>Test Audio Device</h3>
-
- The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
- The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
+
+ The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
+ The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
-
- &Test
- &Test
+
+ &Test
+ &Test
-
- <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
- <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
+
+ <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
+ <p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
-
- Is any sound played after clicking the "Test" button?
- Is any sound played after clicking the "Test" button?
+
+ Is any sound played after clicking the "Test" button?
+ Is any sound played after clicking the "Test" button?
-
- &Yes
- &Yes
+
+ &Yes
+ &Yes
-
- I can hear the test sound played by the audio device
- I can hear the test sound played by the audio device
+
+ I can hear the test sound played by the audio device
+ I can hear the test sound played by the audio device
-
- &No
- &No
+
+ &No
+ &No
-
- I cannot hear any sound played by the audio device
- I cannot hear any sound played by the audio device
+
+ I cannot hear any sound played by the audio device
+ I cannot hear any sound played by the audio device
-
-
+
+
Audio::Internal::WelcomePage
-
- <h3>Audio Output Troubleshooting Wizard</h3>
- <h3>Audio Output Troubleshooting Wizard</h3>
+
+ <h3>Audio Output Troubleshooting Wizard</h3>
+ <h3>Audio Output Troubleshooting Wizard</h3>
-
- This wizard will help you diagnose and resolve problems with audio output.
- This wizard will help you diagnose and resolve problems with audio output.
+
+ This wizard will help you diagnose and resolve problems with audio output.
+ This wizard will help you diagnose and resolve problems with audio output.
-
- &Continue
- &Continue
+
+ &Continue
+ &Continue
-
-
+
+
AudioOutputPage
-
- Device Parameters
- Device Parameters
+
+ Device Parameters
+ Device Parameters
-
- Audio driver
- Audio driver
+
+ Audio driver
+ Audio driver
-
- Audio device
- Audio device
+
+ Audio device
+ Audio device
-
- Sample rate
- Sample rate
+
+ Sample rate
+ Sample rate
-
- Buffer size
- Buffer size
+
+ Buffer size
+ Buffer size
-
- Troubleshoot...
- Troubleshoot...
+
+ Troubleshoot...
+ Troubleshoot...
-
- Test
- Test
+
+ Test
+ Test
-
- Open Control Panel
- Open Control Panel
+
+ Open Control Panel
+ Open Control Panel
-
- Mixer
- Mixer
+
+ Mixer
+ Mixer
-
- Device gain
- Device gain
+
+ Device gain
+ Device gain
-
- Device pan
- Device pan
+
+ Device pan
+ Device pan
-
- Hot Plug
- Hot Plug
+
+ Hot Plug
+ Hot Plug
-
- When device change detected
- When device change detected
+
+ When device change detected
+ When device change detected
-
- Always show notification
- Always show notification
+
+ Always show notification
+ Always show notification
-
- Show notification only when the current device is removed
- Show notification only when the current device is removed
+
+ Show notification only when the current device is removed
+ Show notification only when the current device is removed
-
- Do not show notification
- Do not show notification
+
+ Do not show notification
+ Do not show notification
-
-
+
+
AudioOutputWelcomeWizardPage
-
- Audio Output
- Audio Output
+
+ Audio Output
+ Audio Output
-
- Configure audio output device parameters
- Configure audio output device parameters
+
+ Configure audio output device parameters
+ Configure audio output device parameters
-
- Audio driver
- Audio driver
+
+ Audio driver
+ Audio driver
-
- Audio device
- Audio device
+
+ Audio device
+ Audio device
-
- Sample rate
- Sample rate
+
+ Sample rate
+ Sample rate
-
- Buffer size
- Buffer size
+
+ Buffer size
+ Buffer size
-
- Test
- Test
+
+ Test
+ Test
-
- Open Control Panel
- Open Control Panel
+
+ Open Control Panel
+ Open Control Panel
-
- Click "Test" button to check whether audio output is configured correctly
- Click "Test" button to check whether audio output is configured correctly
+
+ Click "Test" button to check whether audio output is configured correctly
+ Click "Test" button to check whether audio output is configured correctly
-
+
diff --git a/src/plugins/audio/res/translations/org.diffscope.audio_ja_JP.ts b/src/plugins/audio/res/translations/org.diffscope.audio_ja_JP.ts
index f703f905..09543cd8 100644
--- a/src/plugins/audio/res/translations/org.diffscope.audio_ja_JP.ts
+++ b/src/plugins/audio/res/translations/org.diffscope.audio_ja_JP.ts
@@ -1,10 +1,30 @@
+
+
+
+
+ Main Menu
+ Main Menu
+
+
+
+ Application
+
+
+ Version %1
+ Version %1
+
+
+
+ Copyright © %1-%2 %3. All rights reserved.
+ Copyright © %1-%2 %3. All rights reserved.
+
+
Application::ActionText
-
Main Menu
Main Menu
@@ -12,12 +32,12 @@
Audio::Internal::AudioAndMidiPage
-
+
Audio and MIDI
Audio and MIDI
-
+
Configure audio and MIDI preferences
Configure audio and MIDI preferences
@@ -25,12 +45,12 @@
Audio::Internal::AudioOutputPage
-
+
Audio Output
Audio Output
-
+
Configure the audio driver and device for output
Configure the audio driver and device for output
@@ -38,56 +58,53 @@
Audio::Internal::AudioOutputSettingsHelper
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(Not working)
(Not working)
-
+
Cannot initialize %1 driver
Cannot initialize %1 driver
-
-
-
-
-
-
-
+
+
+
+
+
+
+
Default device
Default device
-
-
+
Audio device %1 is not available
Audio device %1 is not available
-
+
Cannot set sample rate to %1
Cannot set sample rate to %1
-
+
Cannot set buffer size to %1
Cannot set buffer size to %1
@@ -95,17 +112,17 @@
Audio::Internal::AudioPlugin
-
+
Initializing audio plugin...
Initializing audio plugin...
-
+
Failed to initialize audio output system
Failed to initialize audio output system
-
+
%1 will not play sound because no available audio output device found.
Please go to Settings > Audio and MIDI > Audio Output to check the device status.
@@ -117,7 +134,7 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::AudioTroubleshootingDialog
-
+
Audio Output Troubleshooting Wizard
Audio Output Troubleshooting Wizard
@@ -125,72 +142,72 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ConfigurePage
-
+
<h3>Configure Audio Device</h3>
<h3>Configure Audio Device</h3>
-
+
Please select a working audio driver and device.
Please select a working audio driver and device.
-
+
<p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
<p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
-
+
Audio d&river
Audio d&river
-
+
Audio &device
Audio &device
-
+
&Sample rate
&Sample rate
-
+
&Buffer size
&Buffer size
-
+
&Test
&Test
-
+
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
-
+
Have you selected a working audio device which plays sound after clicking the "Test" button?
Have you selected a working audio device which plays sound after clicking the "Test" button?
-
+
&Yes
&Yes
-
+
I have selected a working audio device
I have selected a working audio device
-
+
&No
&No
-
+
The device is either not available or not able to play sound
The device is either not available or not able to play sound
@@ -198,67 +215,67 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ExternalCheckPage
-
+
Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
-
+
&Open System Settings
&Open System Settings
-
+
&Open Control Panel
&Open Control Panel
-
+
<p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
<p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
-
+
Are audio devices configured properly and able to be played by other applications?
Are audio devices configured properly and able to be played by other applications?
-
+
&Yes
&Yes
-
+
The audio device work well on my system. I want to retry configuring it in %1
The audio device work well on my system. I want to retry configuring it in %1
-
+
Not &exactly
Not &exactly
-
+
Even though other applications can play sound, I fail to configure the audio device in %1
Even though other applications can play sound, I fail to configure the audio device in %1
-
+
&No
&No
-
+
Other applications also cannot play sound
Other applications also cannot play sound
-
+
&I'm not sure
&I'm not sure
-
+
%1 cannot open the control panel on your system. Please open it manually
%1 cannot open the control panel on your system. Please open it manually
@@ -266,12 +283,12 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ResultFailPage
-
+
Please send us a feedback.
Please send us a feedback.
-
+
<p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
<p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
@@ -279,17 +296,17 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ResultOkPage
-
+
<h3>Everything Is OK</h3>
<h3>Everything Is OK</h3>
-
+
There are no problems with audio output at the moment.
There are no problems with audio output at the moment.
-
+
<p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
<p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
@@ -297,47 +314,47 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::TestPage
-
+
<h3>Test Audio Device</h3>
<h3>Test Audio Device</h3>
-
+
The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
-
+
&Test
&Test
-
+
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
-
+
Is any sound played after clicking the "Test" button?
Is any sound played after clicking the "Test" button?
-
+
&Yes
&Yes
-
+
I can hear the test sound played by the audio device
I can hear the test sound played by the audio device
-
+
&No
&No
-
+
I cannot hear any sound played by the audio device
I cannot hear any sound played by the audio device
@@ -345,17 +362,17 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::WelcomePage
-
+
<h3>Audio Output Troubleshooting Wizard</h3>
<h3>Audio Output Troubleshooting Wizard</h3>
-
+
This wizard will help you diagnose and resolve problems with audio output.
This wizard will help you diagnose and resolve problems with audio output.
-
+
&Continue
&Continue
diff --git a/src/plugins/audio/res/translations/org.diffscope.audio_zh_CN.ts b/src/plugins/audio/res/translations/org.diffscope.audio_zh_CN.ts
index e1c26314..c17c0764 100644
--- a/src/plugins/audio/res/translations/org.diffscope.audio_zh_CN.ts
+++ b/src/plugins/audio/res/translations/org.diffscope.audio_zh_CN.ts
@@ -1,10 +1,30 @@
+
+
+
+
+ Main Menu
+ 主菜单
+
+
+
+ Application
+
+
+ Version %1
+ Version %1
+
+
+
+ Copyright © %1-%2 %3. All rights reserved.
+ Copyright © %1-%2 %3. All rights reserved.
+
+
Application::ActionText
-
Main Menu
主菜单
@@ -12,12 +32,12 @@
Audio::Internal::AudioAndMidiPage
-
+
Audio and MIDI
音频与 MIDI
-
+
Configure audio and MIDI preferences
配置音频和 MIDI 首选项
@@ -25,12 +45,12 @@
Audio::Internal::AudioOutputPage
-
+
Audio Output
音频输出
-
+
Configure the audio driver and device for output
配置用于输出的音频设备
@@ -38,56 +58,53 @@
Audio::Internal::AudioOutputSettingsHelper
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(Not working)
(不工作)
-
+
Cannot initialize %1 driver
无法初始化 %1 驱动
-
-
-
-
-
-
-
+
+
+
+
+
+
+
Default device
默认设备
-
-
+
Audio device %1 is not available
音频设备 %1 不可用
-
+
Cannot set sample rate to %1
无法设置采样率为 %1
-
+
Cannot set buffer size to %1
无法设置缓冲区大小为 %1
@@ -95,17 +112,17 @@
Audio::Internal::AudioPlugin
-
+
Initializing audio plugin...
正在初始化音频插件...
-
+
Failed to initialize audio output system
初始化音频输出系统失败
-
+
%1 will not play sound because no available audio output device found.
Please go to Settings > Audio and MIDI > Audio Output to check the device status.
@@ -117,7 +134,7 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::AudioTroubleshootingDialog
-
+
Audio Output Troubleshooting Wizard
Audio Output Troubleshooting Wizard
@@ -125,72 +142,72 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ConfigurePage
-
+
<h3>Configure Audio Device</h3>
<h3>Configure Audio Device</h3>
-
+
Please select a working audio driver and device.
Please select a working audio driver and device.
-
+
<p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
<p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
-
+
Audio d&river
Audio d&river
-
+
Audio &device
Audio &device
-
+
&Sample rate
&Sample rate
-
+
&Buffer size
&Buffer size
-
+
&Test
&Test
-
+
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
-
+
Have you selected a working audio device which plays sound after clicking the "Test" button?
Have you selected a working audio device which plays sound after clicking the "Test" button?
-
+
&Yes
&Yes
-
+
I have selected a working audio device
I have selected a working audio device
-
+
&No
&No
-
+
The device is either not available or not able to play sound
The device is either not available or not able to play sound
@@ -198,67 +215,67 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ExternalCheckPage
-
+
Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
-
+
&Open System Settings
&Open System Settings
-
+
&Open Control Panel
&Open Control Panel
-
+
<p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
<p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
-
+
Are audio devices configured properly and able to be played by other applications?
Are audio devices configured properly and able to be played by other applications?
-
+
&Yes
&Yes
-
+
The audio device work well on my system. I want to retry configuring it in %1
The audio device work well on my system. I want to retry configuring it in %1
-
+
Not &exactly
Not &exactly
-
+
Even though other applications can play sound, I fail to configure the audio device in %1
Even though other applications can play sound, I fail to configure the audio device in %1
-
+
&No
&No
-
+
Other applications also cannot play sound
Other applications also cannot play sound
-
+
&I'm not sure
&I'm not sure
-
+
%1 cannot open the control panel on your system. Please open it manually
%1 cannot open the control panel on your system. Please open it manually
@@ -266,12 +283,12 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ResultFailPage
-
+
Please send us a feedback.
Please send us a feedback.
-
+
<p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
<p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
@@ -279,17 +296,17 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ResultOkPage
-
+
<h3>Everything Is OK</h3>
<h3>Everything Is OK</h3>
-
+
There are no problems with audio output at the moment.
There are no problems with audio output at the moment.
-
+
<p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
<p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
@@ -297,47 +314,47 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::TestPage
-
+
<h3>Test Audio Device</h3>
<h3>Test Audio Device</h3>
-
+
The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
-
+
&Test
&Test
-
+
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
-
+
Is any sound played after clicking the "Test" button?
Is any sound played after clicking the "Test" button?
-
+
&Yes
&Yes
-
+
I can hear the test sound played by the audio device
I can hear the test sound played by the audio device
-
+
&No
&No
-
+
I cannot hear any sound played by the audio device
I cannot hear any sound played by the audio device
@@ -345,17 +362,17 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::WelcomePage
-
+
<h3>Audio Output Troubleshooting Wizard</h3>
<h3>Audio Output Troubleshooting Wizard</h3>
-
+
This wizard will help you diagnose and resolve problems with audio output.
This wizard will help you diagnose and resolve problems with audio output.
-
+
&Continue
&Continue
diff --git a/src/plugins/audio/res/translations/org.diffscope.audio_zh_TW.ts b/src/plugins/audio/res/translations/org.diffscope.audio_zh_TW.ts
index b2a0bea4..ebb39df3 100644
--- a/src/plugins/audio/res/translations/org.diffscope.audio_zh_TW.ts
+++ b/src/plugins/audio/res/translations/org.diffscope.audio_zh_TW.ts
@@ -1,10 +1,30 @@
+
+
+
+
+ Main Menu
+ Main Menu
+
+
+
+ Application
+
+
+ Version %1
+ Version %1
+
+
+
+ Copyright © %1-%2 %3. All rights reserved.
+ Copyright © %1-%2 %3. All rights reserved.
+
+
Application::ActionText
-
Main Menu
Main Menu
@@ -12,12 +32,12 @@
Audio::Internal::AudioAndMidiPage
-
+
Audio and MIDI
Audio and MIDI
-
+
Configure audio and MIDI preferences
Configure audio and MIDI preferences
@@ -25,12 +45,12 @@
Audio::Internal::AudioOutputPage
-
+
Audio Output
Audio Output
-
+
Configure the audio driver and device for output
Configure the audio driver and device for output
@@ -38,56 +58,53 @@
Audio::Internal::AudioOutputSettingsHelper
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
(Not working)
(Not working)
-
+
Cannot initialize %1 driver
Cannot initialize %1 driver
-
-
-
-
-
-
-
+
+
+
+
+
+
+
Default device
Default device
-
-
+
Audio device %1 is not available
Audio device %1 is not available
-
+
Cannot set sample rate to %1
Cannot set sample rate to %1
-
+
Cannot set buffer size to %1
Cannot set buffer size to %1
@@ -95,17 +112,17 @@
Audio::Internal::AudioPlugin
-
+
Initializing audio plugin...
Initializing audio plugin...
-
+
Failed to initialize audio output system
Failed to initialize audio output system
-
+
%1 will not play sound because no available audio output device found.
Please go to Settings > Audio and MIDI > Audio Output to check the device status.
@@ -117,7 +134,7 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::AudioTroubleshootingDialog
-
+
Audio Output Troubleshooting Wizard
Audio Output Troubleshooting Wizard
@@ -125,72 +142,72 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ConfigurePage
-
+
<h3>Configure Audio Device</h3>
<h3>Configure Audio Device</h3>
-
+
Please select a working audio driver and device.
Please select a working audio driver and device.
-
+
<p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
<p>Please test all audio drivers and devices one by one, and try different sample rates and buffer sizes.</p><p>Some devices listed on your computer may be virtual devices and may not output sound to physical hardware.</p>
-
+
Audio d&river
Audio d&river
-
+
Audio &device
Audio &device
-
+
&Sample rate
&Sample rate
-
+
&Buffer size
&Buffer size
-
+
&Test
&Test
-
+
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
-
+
Have you selected a working audio device which plays sound after clicking the "Test" button?
Have you selected a working audio device which plays sound after clicking the "Test" button?
-
+
&Yes
&Yes
-
+
I have selected a working audio device
I have selected a working audio device
-
+
&No
&No
-
+
The device is either not available or not able to play sound
The device is either not available or not able to play sound
@@ -198,67 +215,67 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ExternalCheckPage
-
+
Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
Please ensure that your audio devices are properly connected to your computer and configured in your system settings.
-
+
&Open System Settings
&Open System Settings
-
+
&Open Control Panel
&Open Control Panel
-
+
<p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
<p>Also please check whether other applications can play sound.</p><p>If another audio application (e.g., a DAW) can play sound normally, please review that application’s settings. It may be using "exclusive mode", which allows only that program to access the audio device.</p>
-
+
Are audio devices configured properly and able to be played by other applications?
Are audio devices configured properly and able to be played by other applications?
-
+
&Yes
&Yes
-
+
The audio device work well on my system. I want to retry configuring it in %1
The audio device work well on my system. I want to retry configuring it in %1
-
+
Not &exactly
Not &exactly
-
+
Even though other applications can play sound, I fail to configure the audio device in %1
Even though other applications can play sound, I fail to configure the audio device in %1
-
+
&No
&No
-
+
Other applications also cannot play sound
Other applications also cannot play sound
-
+
&I'm not sure
&I'm not sure
-
+
%1 cannot open the control panel on your system. Please open it manually
%1 cannot open the control panel on your system. Please open it manually
@@ -266,12 +283,12 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ResultFailPage
-
+
Please send us a feedback.
Please send us a feedback.
-
+
<p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
<p>When sending feedback, please include the following information (if possible): <ul><li>A screenshot of the "Audio Output" settings page</li><li>A screenshot of your system audio settings</li><li>The audio output configurations you have tried and any error messages</li><li>The log of application</li></ul></p>
@@ -279,17 +296,17 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::ResultOkPage
-
+
<h3>Everything Is OK</h3>
<h3>Everything Is OK</h3>
-
+
There are no problems with audio output at the moment.
There are no problems with audio output at the moment.
-
+
<p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
<p>If you still cannot hear sound when playing back your project, please check for issues within the project itself (e.g., muted tracks or gain set to negative infinity).</p>
@@ -297,47 +314,47 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::TestPage
-
+
<h3>Test Audio Device</h3>
<h3>Test Audio Device</h3>
-
+
The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
The audio device appears to be working. Please click the "Test" button to check whether it can play sound.
-
+
&Test
&Test
-
+
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
<p>Before testing, please make sure the device you are monitoring is the one you selected, especially if your computer has multiple audio devices (e.g., speakers and headphones), and the device has been properly connected to your computer.</p><p>Also please check whether the device is muted or the volume is set to zero.</p>
-
+
Is any sound played after clicking the "Test" button?
Is any sound played after clicking the "Test" button?
-
+
&Yes
&Yes
-
+
I can hear the test sound played by the audio device
I can hear the test sound played by the audio device
-
+
&No
&No
-
+
I cannot hear any sound played by the audio device
I cannot hear any sound played by the audio device
@@ -345,17 +362,17 @@ Please go to Settings > Audio and MIDI > Audio Output to check the device
Audio::Internal::WelcomePage
-
+
<h3>Audio Output Troubleshooting Wizard</h3>
<h3>Audio Output Troubleshooting Wizard</h3>
-
+
This wizard will help you diagnose and resolve problems with audio output.
This wizard will help you diagnose and resolve problems with audio output.
-
+
&Continue
&Continue
diff --git a/src/plugins/coreplugin/core/CoreInterface.cpp b/src/plugins/coreplugin/core/CoreInterface.cpp
index a44ea4d5..5c920fc2 100644
--- a/src/plugins/coreplugin/core/CoreInterface.cpp
+++ b/src/plugins/coreplugin/core/CoreInterface.cpp
@@ -253,23 +253,23 @@ namespace Core {
.version = QDspx::Model::V1,
.content = {
.global = {},
- .master = {
- .control = {
- .gain = 1,
- .pan = 0,
- .mute = false,
- }
- },
.timeline = {
.labels = {},
.tempos = {{0, 120}},
.timeSignatures = {{0, 4, 4}}
+ },
+ .tracks = {
+ QDspx::Track{
+ .name = tr("Unnamed track")
+ }
}
}
};
qCInfo(lcCoreInterface) << "New file";
auto projectDocumentContext = std::make_unique();
- projectDocumentContext->newFile(defaultModel, false);
+ if (!projectDocumentContext->newFile(defaultModel, false)) {
+ return nullptr;
+ }
auto windowInterface = createProjectWindow(projectDocumentContext.release());
return windowInterface;
}
diff --git a/src/plugins/coreplugin/internal/BehaviorPreference.cpp b/src/plugins/coreplugin/internal/BehaviorPreference.cpp
index 102e40f1..ab0f5de1 100644
--- a/src/plugins/coreplugin/internal/BehaviorPreference.cpp
+++ b/src/plugins/coreplugin/internal/BehaviorPreference.cpp
@@ -58,7 +58,7 @@ namespace Core::Internal {
Q_D(BehaviorPreference);
auto settings = RuntimeInterface::settings();
settings->beginGroup(staticMetaObject.className());
- d->startupBehavior = settings->value("startupBehavior", QVariant::fromValue(SB_CloseHomeWindowAfterOpeningProject)).value();
+ d->startupBehavior = settings->value("startupBehavior", QVariant::fromValue(SB_CloseHomeWindowAfterOpeningProject | SB_OpenHomeWindowWhenLastProjectClosed)).value();
emit startupBehaviorChanged();
d->useSystemLanguage = settings->value("useSystemLanguage", true).toBool();
emit useSystemLanguageChanged();
diff --git a/src/plugins/coreplugin/internal/BehaviorPreference.h b/src/plugins/coreplugin/internal/BehaviorPreference.h
index aecc332d..08dc4c89 100644
--- a/src/plugins/coreplugin/internal/BehaviorPreference.h
+++ b/src/plugins/coreplugin/internal/BehaviorPreference.h
@@ -62,6 +62,7 @@ namespace Core::Internal {
enum StartupBehaviorFlag {
SB_CreateNewProject = 0x01,
SB_CloseHomeWindowAfterOpeningProject = 0x02,
+ SB_OpenHomeWindowWhenLastProjectClosed = 0x04,
};
Q_ENUM(StartupBehaviorFlag)
Q_DECLARE_FLAGS(StartupBehavior, StartupBehaviorFlag)
diff --git a/src/plugins/coreplugin/internal/CorePlugin.cpp b/src/plugins/coreplugin/internal/CorePlugin.cpp
index d7566c55..13364250 100644
--- a/src/plugins/coreplugin/internal/CorePlugin.cpp
+++ b/src/plugins/coreplugin/internal/CorePlugin.cpp
@@ -1,13 +1,5 @@
#include "CorePlugin.h"
-#ifdef Q_OS_WIN
-# include
-# include
-# include
-# include
-# include
-#endif
-
#include
#include
@@ -37,6 +29,7 @@
#include
#include
+#include
#include
@@ -51,6 +44,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -66,6 +60,9 @@
#include
#include
#include
+#include
+#include
+#include
static auto getCoreActionExtension() {
return QAK_STATIC_ACTION_EXTENSION(coreplugin);
@@ -131,6 +128,9 @@ namespace Core::Internal {
static constexpr char kOpenSettingsArg[] = "--open-settings";
static constexpr char kNewProjectArg[] = "--new";
+ static constexpr char kNoWarningLastRun[] = "--no-warning-last-run";
+ static constexpr char kFatalWithoutPlugins[] = "--fatal-without-plugins";
+ static constexpr char kNoWarningPluginError[] = "--no-warning-plugin-error";
static ActionWindowInterfaceBase *initializeGui(const QStringList &options, const QString &workingDirectory, const QStringList &args) {
qCDebug(lcCorePlugin) << "Initializing GUI" << options << args;
@@ -197,8 +197,12 @@ namespace Core::Internal {
}
void CorePlugin::extensionsInitialized() {
- auto settings = RuntimeInterface::settings();
- settings->setValue("lastInitializationAbortedFlag", false);
+ RuntimeInterface::splash()->showMessage(tr("Plugins loading complete, preparing for subsequent initialization..."));
+ for (auto plugin : ExtensionSystem::PluginManager::plugins()) {
+ qCInfo(lcCorePlugin) << "Plugin" << plugin->name() << "enabled =" << plugin->isEffectivelyEnabled() << "enabledBySettings =" << plugin->isEnabledBySettings() << "hasError =" << plugin->hasError();
+ }
+ checkLastRun();
+ checkPlugins();
}
bool CorePlugin::delayedInitialize() {
@@ -237,85 +241,15 @@ namespace Core::Internal {
return QObject::eventFilter(obj, event);
}
-#ifdef Q_OS_WIN
- static void initializeWindowsJumpList() {
- CoInitialize(nullptr);
-
- CComPtr pcdl;
- HRESULT hr = pcdl.CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER);
- if (FAILED(hr)) {
- CoUninitialize();
- return;
- }
-
- UINT cMinSlots;
- CComPtr poaRemoved;
- hr = pcdl->BeginList(&cMinSlots, IID_PPV_ARGS(&poaRemoved));
- if (FAILED(hr)) {
- CoUninitialize();
- return;
- }
-
- CComPtr poc;
- hr = poc.CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr, CLSCTX_INPROC_SERVER);
- if (FAILED(hr)) {
- CoUninitialize();
- return;
- }
-
- CComPtr psl;
- hr = psl.CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER);
- if (FAILED(hr)) {
- CoUninitialize();
- return;
- }
-
- auto appPath = QApplication::applicationFilePath().toStdWString();
- psl->SetPath(appPath.c_str());
- psl->SetArguments(L"--new");
-
- CComPtr pps;
- hr = psl->QueryInterface(IID_PPV_ARGS(&pps));
- if (SUCCEEDED(hr)) {
- PROPVARIANT propvar;
- InitPropVariantFromString(L"New Project", &propvar);
- pps->SetValue(PKEY_Title, propvar);
- PropVariantClear(&propvar);
- pps->Commit();
- }
-
- poc->AddObject(psl);
-
- CComPtr poa;
- hr = poc->QueryInterface(IID_PPV_ARGS(&poa));
- if (SUCCEEDED(hr)) {
- pcdl->AddUserTasks(poa);
- }
-
- pcdl->CommitList();
- CoUninitialize();
- }
-#endif
-
-#ifdef Q_OS_MACOS
- static void initializeMacOSJumpList() {
- }
-#endif
-
void CorePlugin::initializeSingletons() {
new CoreInterface(this);
new BehaviorPreference(this);
+ new DspxClipboard(this);
}
void CorePlugin::initializeActions() {
CoreInterface::actionRegistry()->addExtension(::getCoreActionExtension());
CoreInterface::actionRegistry()->addIconManifest(":/diffscope/coreplugin/icons/config.json");
- // TODO: move to icon manifest later
- const auto addIcon = [&](const QString &id, const QString &iconName) {
- QAK::ActionIcon icon;
- icon.addUrl("image://fluent-system-icons/" + iconName);
- CoreInterface::actionRegistry()->addIcon("", id, icon);
- };
}
void CorePlugin::initializeSettings() const {
@@ -341,6 +275,7 @@ namespace Core::Internal {
HomeWindowInterfaceRegistry::instance()->attach();
ProjectWindowInterfaceRegistry::instance()->attach();
ProjectWindowInterfaceRegistry::instance()->attach();
+ ProjectWindowInterfaceRegistry::instance()->attach();
ProjectWindowInterfaceRegistry::instance()->attach();
ProjectWindowInterfaceRegistry::instance()->attach();
ProjectWindowInterfaceRegistry::instance()->attach();
@@ -350,6 +285,30 @@ namespace Core::Internal {
HomeWindowInterfaceRegistry::instance()->attach();
ProjectWindowInterfaceRegistry::instance()->attach();
ProjectWindowInterfaceRegistry::instance()->attach();
+ ProjectWindowInterfaceRegistry::instance()->attach();
+
+ auto windowSystem = CoreInterface::windowSystem();
+ connect(windowSystem, &WindowSystem::windowAboutToDestroy, this, [](WindowInterface *windowInterface) {
+ if (!qobject_cast(windowInterface)) {
+ return;
+ }
+
+ const auto startupBehavior = BehaviorPreference::startupBehavior();
+ const bool closeHomeAfterOpening = startupBehavior & BehaviorPreference::SB_CloseHomeWindowAfterOpeningProject;
+ const bool reopenHomeOnLastProjectClosed = startupBehavior & BehaviorPreference::SB_OpenHomeWindowWhenLastProjectClosed;
+
+ if (closeHomeAfterOpening && !reopenHomeOnLastProjectClosed) {
+ return;
+ }
+
+ const bool hasOtherProjectWindow = std::ranges::any_of(CoreInterface::windowSystem()->windows(), [](auto w) {
+ return qobject_cast(w);
+ });
+
+ if (!hasOtherProjectWindow) {
+ CoreInterface::showHome();
+ }
+ });
}
void CorePlugin::initializeBehaviorPreference() {
@@ -402,11 +361,7 @@ namespace Core::Internal {
}
void CorePlugin::initializeJumpList() {
-#ifdef Q_OS_WIN
- initializeWindowsJumpList();
-#elif defined(Q_OS_MACOS)
- initializeMacOSJumpList();
-#endif
+ PlatformJumpListHelper::initializePlatformJumpList();
}
void CorePlugin::initializeHelpContents() {
@@ -419,4 +374,64 @@ namespace Core::Internal {
}
}
+ void CorePlugin::checkLastRun() {
+ auto settings = RuntimeInterface::settings();
+ settings->setValue("lastInitializationAbortedFlag", false);
+ bool lastRunWarningSuppressed = QApplication::arguments().contains(kNoWarningLastRun);
+ if (settings->value("lastRunTerminatedAbnormally").toBool() && !lastRunWarningSuppressed) {
+ qCWarning(lcCorePlugin) << "Last run terminated abnormally";
+ SVS::MessageBox::warning(RuntimeInterface::qmlEngine(), nullptr, tr("Last run terminated abnormally"), tr("%1 did not exit normally during its last run.\n\nTo check for unsaved files, please go to Recovery Files.").arg(QApplication::applicationDisplayName()));
+ }
+ settings->setValue("lastRunTerminatedAbnormally", true);
+ RuntimeInterface::addExitCallback([](int exitCode) {
+ if (exitCode == 0) {
+ RuntimeInterface::settings()->setValue("lastRunTerminatedAbnormally", false);
+ }
+ });
+ }
+
+ void CorePlugin::checkPlugins() {
+ auto args = QApplication::arguments();
+ if (auto i = args.indexOf(kFatalWithoutPlugins); i != -1) {
+ QList pluginIdList;
+ for (auto j = i + 1; j < args.size(); ++j) {
+ if (args[j].startsWith('-'))
+ break;
+ pluginIdList.append(args[j]);
+ }
+ QList requiredPluginsWithError;
+ for (auto plugin : ExtensionSystem::PluginManager::plugins()) {
+ if (pluginIdList.contains(plugin->name())) {
+ pluginIdList.removeAll(plugin->name());
+ if (plugin->hasError()) {
+ requiredPluginsWithError.append(plugin->name());
+ }
+ }
+ }
+ if (!pluginIdList.isEmpty()) {
+ qFatal() << "Missing plugins specified by" << kFatalWithoutPlugins << ":" << pluginIdList;
+ }
+ if (!requiredPluginsWithError.isEmpty()) {
+ qFatal() << "Plugins specified by" << kFatalWithoutPlugins << "have errors:" << requiredPluginsWithError;
+ }
+ }
+
+ QList errorPlugins;
+ std::ranges::copy(
+ ExtensionSystem::PluginManager::plugins() | std::views::filter([](auto *plugin) {
+ return plugin->hasError();
+ }),
+ std::back_inserter(errorPlugins)
+ );
+ bool isPluginErrorSuppressed = QApplication::arguments().contains(kNoWarningPluginError);
+ if (!errorPlugins.isEmpty() && !isPluginErrorSuppressed) {
+ static auto errorMessage = tr("Errors occurred while loading some plugins:\n\n%1\n\nPlease go to Plugins to see more details.");
+ QStringList pluginErrorMessages;
+ std::ranges::transform(errorPlugins, std::back_inserter(pluginErrorMessages), [](auto plugin) {
+ return tr("%1 (%2)").arg(plugin->displayName(), plugin->name());
+ });
+ SVS::MessageBox::critical(RuntimeInterface::qmlEngine(), nullptr, tr("Plugin Error"), errorMessage.arg(pluginErrorMessages.join("\n")));
+ }
+ }
+
}
diff --git a/src/plugins/coreplugin/internal/CorePlugin.h b/src/plugins/coreplugin/internal/CorePlugin.h
index 4af66ca3..04e96d5e 100644
--- a/src/plugins/coreplugin/internal/CorePlugin.h
+++ b/src/plugins/coreplugin/internal/CorePlugin.h
@@ -25,11 +25,15 @@ namespace Core::Internal {
void initializeSingletons();
static void initializeActions();
void initializeSettings() const;
- static void initializeWindows();
+ void initializeWindows();
static void initializeBehaviorPreference();
static void initializeColorScheme();
static void initializeJumpList();
void initializeHelpContents();
+
+ static void checkLastRun();
+ static void checkPlugins();
+
};
}
diff --git a/src/plugins/coreplugin/internal/PlatformJumpListHelper.cpp b/src/plugins/coreplugin/internal/PlatformJumpListHelper.cpp
new file mode 100644
index 00000000..a98558ce
--- /dev/null
+++ b/src/plugins/coreplugin/internal/PlatformJumpListHelper.cpp
@@ -0,0 +1,79 @@
+#include "PlatformJumpListHelper.h"
+
+#include
+
+#ifdef Q_OS_WIN
+# include
+# include
+# include
+# include
+# include
+#elif defined(Q_OS_MACOS)
+// TODO: Add macOS jump list (dock menu) implementation when available
+#endif
+
+namespace Core::Internal {
+
+ void PlatformJumpListHelper::initializePlatformJumpList() {
+#ifdef Q_OS_WIN
+ CoInitialize(nullptr);
+
+ CComPtr pcdl;
+ HRESULT hr = pcdl.CoCreateInstance(CLSID_DestinationList, nullptr, CLSCTX_INPROC_SERVER);
+ if (FAILED(hr)) {
+ CoUninitialize();
+ return;
+ }
+
+ UINT cMinSlots;
+ CComPtr poaRemoved;
+ hr = pcdl->BeginList(&cMinSlots, IID_PPV_ARGS(&poaRemoved));
+ if (FAILED(hr)) {
+ CoUninitialize();
+ return;
+ }
+
+ CComPtr poc;
+ hr = poc.CoCreateInstance(CLSID_EnumerableObjectCollection, nullptr, CLSCTX_INPROC_SERVER);
+ if (FAILED(hr)) {
+ CoUninitialize();
+ return;
+ }
+
+ CComPtr psl;
+ hr = psl.CoCreateInstance(CLSID_ShellLink, nullptr, CLSCTX_INPROC_SERVER);
+ if (FAILED(hr)) {
+ CoUninitialize();
+ return;
+ }
+
+ auto appPath = QApplication::applicationFilePath().toStdWString();
+ psl->SetPath(appPath.c_str());
+ psl->SetArguments(L"--new");
+
+ CComPtr pps;
+ hr = psl->QueryInterface(IID_PPV_ARGS(&pps));
+ if (SUCCEEDED(hr)) {
+ PROPVARIANT propvar;
+ InitPropVariantFromString(L"New Project", &propvar);
+ pps->SetValue(PKEY_Title, propvar);
+ PropVariantClear(&propvar);
+ pps->Commit();
+ }
+
+ poc->AddObject(psl);
+
+ CComPtr poa;
+ hr = poc->QueryInterface(IID_PPV_ARGS(&poa));
+ if (SUCCEEDED(hr)) {
+ pcdl->AddUserTasks(poa);
+ }
+
+ pcdl->CommitList();
+ CoUninitialize();
+#elif defined(Q_OS_MACOS)
+ // TODO: Add macOS jump list (dock menu) implementation when available
+#endif
+ }
+
+}
diff --git a/src/plugins/coreplugin/internal/PlatformJumpListHelper.h b/src/plugins/coreplugin/internal/PlatformJumpListHelper.h
new file mode 100644
index 00000000..2d361a80
--- /dev/null
+++ b/src/plugins/coreplugin/internal/PlatformJumpListHelper.h
@@ -0,0 +1,13 @@
+#ifndef DIFFSCOPE_COREPLUGIN_PLATFORMJUMPLISTHELPER_H
+#define DIFFSCOPE_COREPLUGIN_PLATFORMJUMPLISTHELPER_H
+
+namespace Core::Internal {
+
+ class PlatformJumpListHelper {
+ public:
+ static void initializePlatformJumpList();
+ };
+
+}
+
+#endif // DIFFSCOPE_COREPLUGIN_PLATFORMJUMPLISTHELPER_H
diff --git a/src/plugins/coreplugin/internal/addon/CloseSaveCheckAddOn.cpp b/src/plugins/coreplugin/internal/addon/CloseSaveCheckAddOn.cpp
new file mode 100644
index 00000000..b82d8e32
--- /dev/null
+++ b/src/plugins/coreplugin/internal/addon/CloseSaveCheckAddOn.cpp
@@ -0,0 +1,77 @@
+#include "CloseSaveCheckAddOn.h"
+
+#include
+
+#include
+#include
+#include
+
+#include
+
+#include
+
+#include
+#include
+#include
+
+namespace Core::Internal {
+
+ CloseSaveCheckAddOn::CloseSaveCheckAddOn(QObject *parent) : WindowInterfaceAddOn(parent) {
+ }
+
+ CloseSaveCheckAddOn::~CloseSaveCheckAddOn() = default;
+
+ void CloseSaveCheckAddOn::initialize() {
+ auto windowInterface = windowHandle()->cast();
+ windowInterface->addCloseCallback([this] {
+ return handleCloseRequest();
+ });
+ }
+
+ void CloseSaveCheckAddOn::extensionsInitialized() {
+ }
+
+ bool CloseSaveCheckAddOn::delayedInitialize() {
+ return WindowInterfaceAddOn::delayedInitialize();
+ }
+
+ bool CloseSaveCheckAddOn::handleCloseRequest() const {
+ auto windowInterface = windowHandle()->cast();
+ auto projectContext = windowInterface->projectDocumentContext();
+ auto document = projectContext->document();
+ auto transactionController = document->transactionController();
+ auto fileLocker = projectContext->fileLocker();
+ if (!fileLocker) {
+ return true;
+ }
+
+ const bool isClean = transactionController->cleanStep() == transactionController->currentStep();
+ const bool notModifiedExternally = !fileLocker->isFileModifiedSinceLastSave();
+ const bool isSaved = isClean && notModifiedExternally;
+
+ if (isSaved) {
+ return true;
+ }
+
+ auto button = SVS::MessageBox::warning(
+ RuntimeInterface::qmlEngine(),
+ windowInterface->window(),
+ tr("Do you want to save before closing?"),
+ tr("If you choose not to save, a copy of the current project file will be created to help recover your work in case of accidental incorrect operation."),
+ SVS::SVSCraft::Yes | SVS::SVSCraft::No | SVS::SVSCraft::Cancel,
+ SVS::SVSCraft::Yes
+ );
+
+ if (button == SVS::SVSCraft::Yes) {
+ return windowInterface->save();
+ }
+ if (button == SVS::SVSCraft::No) {
+ QDir runtimeDataDir(ApplicationInfo::applicationLocation(ApplicationInfo::RuntimeData));
+ auto tempPath = runtimeDataDir.filePath(QStringLiteral("latest_unsaved_project.dspx"));
+ return projectContext->saveCopy(tempPath);
+ }
+
+ return false;
+ }
+
+}
diff --git a/src/plugins/coreplugin/internal/addon/CloseSaveCheckAddOn.h b/src/plugins/coreplugin/internal/addon/CloseSaveCheckAddOn.h
new file mode 100644
index 00000000..40817074
--- /dev/null
+++ b/src/plugins/coreplugin/internal/addon/CloseSaveCheckAddOn.h
@@ -0,0 +1,24 @@
+#ifndef DIFFSCOPE_COREPLUGIN_CLOSESAVECHECKADDON_H
+#define DIFFSCOPE_COREPLUGIN_CLOSESAVECHECKADDON_H
+
+#include
+
+namespace Core::Internal {
+
+ class CloseSaveCheckAddOn : public WindowInterfaceAddOn {
+ Q_OBJECT
+ public:
+ explicit CloseSaveCheckAddOn(QObject *parent = nullptr);
+ ~CloseSaveCheckAddOn() override;
+
+ void initialize() override;
+ void extensionsInitialized() override;
+ bool delayedInitialize() override;
+
+ private:
+ bool handleCloseRequest() const;
+ };
+
+}
+
+#endif //DIFFSCOPE_COREPLUGIN_CLOSESAVECHECKADDON_H
diff --git a/src/plugins/coreplugin/internal/addon/InsertItemAddOn.cpp b/src/plugins/coreplugin/internal/addon/InsertItemAddOn.cpp
new file mode 100644
index 00000000..b07dc669
--- /dev/null
+++ b/src/plugins/coreplugin/internal/addon/InsertItemAddOn.cpp
@@ -0,0 +1,38 @@
+#include "InsertItemAddOn.h"
+
+#include
+
+#include
+
+#include
+
+#include
+
+namespace Core::Internal {
+
+ InsertItemAddOn::InsertItemAddOn(QObject *parent) : WindowInterfaceAddOn(parent) {
+ }
+
+ InsertItemAddOn::~InsertItemAddOn() = default;
+
+ void InsertItemAddOn::initialize() {
+ auto windowInterface = windowHandle()->cast();
+ QQmlComponent component(RuntimeInterface::qmlEngine(), "DiffScope.Core", "InsertItemAddOnActions");
+ if (component.isError()) {
+ qFatal() << component.errorString();
+ }
+ auto o = component.createWithInitialProperties({
+ {"addOn", QVariant::fromValue(this)},
+ });
+ o->setParent(this);
+ QMetaObject::invokeMethod(o, "registerToContext", windowInterface->actionContext());
+ }
+
+ void InsertItemAddOn::extensionsInitialized() {
+ }
+
+ bool InsertItemAddOn::delayedInitialize() {
+ return WindowInterfaceAddOn::delayedInitialize();
+ }
+
+}
diff --git a/src/plugins/coreplugin/internal/addon/InsertItemAddOn.h b/src/plugins/coreplugin/internal/addon/InsertItemAddOn.h
new file mode 100644
index 00000000..e87aff51
--- /dev/null
+++ b/src/plugins/coreplugin/internal/addon/InsertItemAddOn.h
@@ -0,0 +1,25 @@
+#ifndef DIFFSCOPE_COREPLUGIN_INSERTITEMADDON_H
+#define DIFFSCOPE_COREPLUGIN_INSERTITEMADDON_H
+
+#include
+
+#include
+
+namespace Core::Internal {
+
+ class InsertItemAddOn : public WindowInterfaceAddOn {
+ Q_OBJECT
+ QML_ELEMENT
+ QML_UNCREATABLE("")
+ public:
+ explicit InsertItemAddOn(QObject *parent = nullptr);
+ ~InsertItemAddOn() override;
+
+ void initialize() override;
+ void extensionsInitialized() override;
+ bool delayedInitialize() override;
+ };
+
+}
+
+#endif //DIFFSCOPE_COREPLUGIN_INSERTITEMADDON_H
\ No newline at end of file
diff --git a/src/plugins/coreplugin/internal/addon/MetadataAddOn.cpp b/src/plugins/coreplugin/internal/addon/MetadataAddOn.cpp
index fc5ec98d..04d9a243 100644
--- a/src/plugins/coreplugin/internal/addon/MetadataAddOn.cpp
+++ b/src/plugins/coreplugin/internal/addon/MetadataAddOn.cpp
@@ -2,6 +2,7 @@
#include
#include
+#include
#include
@@ -20,16 +21,31 @@ namespace Core::Internal {
auto windowInterface = windowHandle()->cast();
// Create MetadataPanel component and add it to action context
- QQmlComponent component(RuntimeInterface::qmlEngine(), "DiffScope.Core", "MetadataPanel", this);
- if (component.isError()) {
- qFatal() << component.errorString();
+ {
+ QQmlComponent component(RuntimeInterface::qmlEngine(), "DiffScope.Core", "MetadataPanel", this);
+ if (component.isError()) {
+ qFatal() << component.errorString();
+ }
+ auto o = component.createWithInitialProperties({
+ {"addOn", QVariant::fromValue(this)},
+ },
+ RuntimeInterface::qmlEngine()->rootContext());
+ o->setParent(this);
+ windowInterface->actionContext()->addAction("org.diffscope.core.panel.metadata", o->property("metadataPanelComponent").value());
+ }
+
+ // Register metadata actions defined in QML
+ {
+ QQmlComponent component(RuntimeInterface::qmlEngine(), "DiffScope.Core", "MetadataAddOnActions");
+ if (component.isError()) {
+ qFatal() << component.errorString();
+ }
+ auto o = component.createWithInitialProperties({
+ {"addOn", QVariant::fromValue(this)},
+ });
+ o->setParent(this);
+ QMetaObject::invokeMethod(o, "registerToContext", windowInterface->actionContext());
}
- auto o = component.createWithInitialProperties({
- {"addOn", QVariant::fromValue(this)},
- },
- RuntimeInterface::qmlEngine()->rootContext());
- o->setParent(this);
- windowInterface->actionContext()->addAction("org.diffscope.core.panel.metadata", o->property("metadataPanelComponent").value());
}
void MetadataAddOn::extensionsInitialized() {
diff --git a/src/plugins/coreplugin/internal/addon/TimelineAddOn.cpp b/src/plugins/coreplugin/internal/addon/TimelineAddOn.cpp
index dbf6e2d8..ea3ffc06 100644
--- a/src/plugins/coreplugin/internal/addon/TimelineAddOn.cpp
+++ b/src/plugins/coreplugin/internal/addon/TimelineAddOn.cpp
@@ -4,6 +4,7 @@
#include
#include
+#include
#include
@@ -13,11 +14,22 @@
#include
#include
#include
+
+#include
+#include
+
+#include
+
#include
#include
#include
+#include
+#include
namespace Core::Internal {
+
+ Q_STATIC_LOGGING_CATEGORY(lcTimelineAddOn, "diffscope.core.timelineaddon")
+
TimelineAddOn::TimelineAddOn(QObject *parent) : WindowInterfaceAddOn(parent) {
}
TimelineAddOn::~TimelineAddOn() = default;
@@ -44,6 +56,7 @@ namespace Core::Internal {
Q_EMIT tempoTextChanged();
Q_EMIT timeSignatureTextChanged();
});
+ connect(windowInterface->projectDocumentContext()->document()->model()->timeline(), &dspx::Timeline::loopEnabledChanged, this, &TimelineAddOn::loopEnabledChanged);
}
void TimelineAddOn::extensionsInitialized() {
}
@@ -86,6 +99,24 @@ namespace Core::Internal {
return QApplication::doubleClickInterval();
}
+ bool TimelineAddOn::isLoopEnabled() const {
+ auto windowInterface = windowHandle()->cast();
+ return windowInterface->projectDocumentContext()->document()->model()->timeline()->isLoopEnabled();
+ }
+
+ void TimelineAddOn::setLoopEnabled(bool enabled) {
+ auto windowInterface = windowHandle()->cast();
+ qCInfo(lcTimelineAddOn) << "Toggle loop:" << enabled;
+ windowInterface->projectDocumentContext()->document()->transactionController()->beginScopedTransaction(enabled ? tr("Enabling loop") : tr("Disabling loop"), [=] {
+ auto dspxTimeline = windowInterface->projectDocumentContext()->document()->model()->timeline();
+ dspxTimeline->setLoopEnabled(enabled);
+ return true;
+ }, [=, this] {
+ qCCritical(lcTimelineAddOn()) << "Failed to edit loop in exclusive transaction";
+ Q_EMIT loopEnabledChanged();
+ });
+ }
+
static inline QString absoluteMusicTimePromptText(const SVS::MusicTime &t) {
if (t.tick() == 0) {
return Core::Internal::TimelineAddOn::tr("measure %L1, beat %L2").arg(t.measure() + 1).arg(t.beat() + 1);
diff --git a/src/plugins/coreplugin/internal/addon/TimelineAddOn.h b/src/plugins/coreplugin/internal/addon/TimelineAddOn.h
index 60c47375..f747ddf3 100644
--- a/src/plugins/coreplugin/internal/addon/TimelineAddOn.h
+++ b/src/plugins/coreplugin/internal/addon/TimelineAddOn.h
@@ -19,6 +19,7 @@ namespace Core::Internal {
Q_PROPERTY(bool showMusicTime READ showMusicTime WRITE setShowMusicTime NOTIFY showMusicTimeChanged)
Q_PROPERTY(bool showAbsoluteTime READ showAbsoluteTime WRITE setShowAbsoluteTime NOTIFY showMusicTimeChanged)
Q_PROPERTY(int doubleClickInterval READ doubleClickInterval)
+ Q_PROPERTY(bool loopEnabled READ isLoopEnabled WRITE setLoopEnabled NOTIFY loopEnabledChanged)
public:
explicit TimelineAddOn(QObject *parent = nullptr);
~TimelineAddOn() override;
@@ -44,6 +45,9 @@ namespace Core::Internal {
static int doubleClickInterval();
+ bool isLoopEnabled() const;
+ void setLoopEnabled(bool enabled);
+
Q_INVOKABLE void execQuickJump(const QString &initialText = {}) const;
Q_INVOKABLE void goToStart() const;
@@ -63,6 +67,7 @@ namespace Core::Internal {
void tempoTextChanged();
void timeSignatureTextChanged();
void showMusicTimeChanged();
+ void loopEnabledChanged();
private:
bool m_showMusicTime{true};
diff --git a/src/plugins/coreplugin/internal/addon/ViewVisibilityAddOn.cpp b/src/plugins/coreplugin/internal/addon/ViewVisibilityAddOn.cpp
index df217462..3dcc2ee1 100644
--- a/src/plugins/coreplugin/internal/addon/ViewVisibilityAddOn.cpp
+++ b/src/plugins/coreplugin/internal/addon/ViewVisibilityAddOn.cpp
@@ -53,21 +53,25 @@ namespace Core::Internal {
qCDebug(lcViewVisibilityAddOn) << "Left side bar" << leftSideBarVisible;
auto leftDockingView = window->property("leftDockingView").value();
leftDockingView->setProperty("barSize", leftSideBarVisible ? 32 : 0);
+ leftDockingView->setProperty("barVisible", leftSideBarVisible);
auto rightSideBarVisible = !settings->value(QString::number(RightSideBar)).value();
qCDebug(lcViewVisibilityAddOn) << "Right side bar" << rightSideBarVisible;
auto rightDockingView = window->property("rightDockingView").value();
rightDockingView->setProperty("barSize", rightSideBarVisible ? 32 : 0);
+ rightDockingView->setProperty("barVisible", rightSideBarVisible);
auto topSideBarVisible = !settings->value(QString::number(TopSideBar)).value();
qCDebug(lcViewVisibilityAddOn) << "Top side bar" << topSideBarVisible;
auto topDockingView = window->property("topDockingView").value();
topDockingView->setProperty("barSize", topSideBarVisible ? 32 : 0);
+ topDockingView->setProperty("barVisible", topSideBarVisible);
auto bottomSideBarVisible = !settings->value(QString::number(BottomSideBar)).value();
qCDebug(lcViewVisibilityAddOn) << "Bottom side bar" << bottomSideBarVisible;
auto bottomDockingView = window->property("bottomDockingView").value();
bottomDockingView->setProperty("barSize", bottomSideBarVisible ? 32 : 0);
+ bottomDockingView->setProperty("barVisible", bottomSideBarVisible);
auto statusBarVisible = !settings->value(QString::number(StatusBar)).value();
qCDebug(lcViewVisibilityAddOn) << "Status bar" << statusBarVisible;
@@ -97,18 +101,22 @@ namespace Core::Internal {
} else if (option == LeftSideBar) {
auto leftDockingView = window->property("leftDockingView").value();
qCInfo(lcViewVisibilityAddOn) << "Left side bar" << visible;
+ leftDockingView->setProperty("barVisible", visible);
leftDockingView->setProperty("barSize", visible ? 32 : 0);
} else if (option == RightSideBar) {
auto rightDockingView = window->property("rightDockingView").value();
qCInfo(lcViewVisibilityAddOn) << "Right side bar" << visible;
+ rightDockingView->setProperty("barVisible", visible);
rightDockingView->setProperty("barSize", visible ? 32 : 0);
} else if (option == TopSideBar) {
auto topDockingView = window->property("topDockingView").value();
qCInfo(lcViewVisibilityAddOn) << "Top side bar" << visible;
+ topDockingView->setProperty("barVisible", visible);
topDockingView->setProperty("barSize", visible ? 32 : 0);
} else if (option == BottomSideBar) {
auto bottomDockingView = window->property("bottomDockingView").value();
qCInfo(lcViewVisibilityAddOn) << "Bottom side bar" << visible;
+ bottomDockingView->setProperty("barVisible", visible);
bottomDockingView->setProperty("barSize", visible ? 32 : 0);
} else if (option == StatusBar) {
auto statusBar = window->property("statusBar").value();
diff --git a/src/plugins/coreplugin/internal/settings/GeneralPage.cpp b/src/plugins/coreplugin/internal/settings/GeneralPage.cpp
index 8f5e14d9..4997b984 100644
--- a/src/plugins/coreplugin/internal/settings/GeneralPage.cpp
+++ b/src/plugins/coreplugin/internal/settings/GeneralPage.cpp
@@ -121,7 +121,7 @@ namespace Core::Internal {
title.arg(QApplication::applicationDisplayName()),
text.arg(QApplication::applicationDisplayName())
) == SVS::SVSCraft::Yes) {
- CoreInterface::restartApplication();
+ RuntimeInterface::restartApplication();
}
}
return ISettingPage::accept();
diff --git a/src/plugins/coreplugin/plugin.json.in b/src/plugins/coreplugin/plugin.json.in
index 644f551f..85ef86bf 100644
--- a/src/plugins/coreplugin/plugin.json.in
+++ b/src/plugins/coreplugin/plugin.json.in
@@ -12,12 +12,25 @@
],
"Arguments" : [
{
- "Name" : "--open-settings",
- "Description" : "Open settings on startup"
+ "Name": "--open-settings",
+ "Description": "Open settings on startup"
},
{
- "Name" : "--new",
- "Description" : "Create a new project on startup, ignoring default startup behavior"
+ "Name": "--new",
+ "Description": "Create a new project on startup, ignoring default startup behavior"
+ },
+ {
+ "Name": "--no-warning-last-run",
+ "Description": "Suppress warning about 'Last run terminated abnormally'"
+ },
+ {
+ "Name": "--fatal-without-plugins",
+ "Parameter": "plugin_list",
+ "Description": "Fatal if any of the specified plugins are not loaded"
+ },
+ {
+ "Name": "--no-warning-plugin-error",
+ "Description": "Suppress warning about plugin errors"
}
],
"Category": "Core",
diff --git a/src/plugins/coreplugin/project/DspxDocument.cpp b/src/plugins/coreplugin/project/DspxDocument.cpp
deleted file mode 100644
index c9cc2044..00000000
--- a/src/plugins/coreplugin/project/DspxDocument.cpp
+++ /dev/null
@@ -1,71 +0,0 @@
-#include "DspxDocument.h"
-#include "DspxDocument_p.h"
-
-#include
-
-#include
-#include
-#include
-
-#include
-#include
-
-namespace Core {
-
- class TransactionalModelStrategy : public TransactionalStrategy {
- public:
- explicit TransactionalModelStrategy(dspx::UndoableModelStrategy *undoableModelStrategy, QObject *parent = nullptr)
- : TransactionalStrategy(parent), m_strategy(undoableModelStrategy) {
- }
-
- void beginTransaction() override {
- m_strategy->undoStack()->beginMacro("");
- }
- void abortTransaction() override {
- m_strategy->undoStack()->endMacro();
- m_strategy->undoStack()->undo();
- }
- void commitTransaction() override {
- m_strategy->undoStack()->endMacro();
- }
- void moveCurrentStepBy(int count) override {
- m_strategy->undoStack()->setIndex(m_strategy->undoStack()->index() + count);
- }
-
- private:
- dspx::UndoableModelStrategy *m_strategy;
-
- };
-
- DspxDocument::DspxDocument(QObject *parent) : QObject(parent), d_ptr(new DspxDocumentPrivate) {
- Q_D(DspxDocument);
- d->q_ptr = this;
- auto modelStrategy = new dspx::UndoableModelStrategy; // TODO use substate in future
- d->model = new dspx::Model(modelStrategy, this);
- modelStrategy->setParent(d->model);
- d->selectionModel = new dspx::SelectionModel(d->model, this);
- auto transactionalStrategy = new TransactionalModelStrategy(modelStrategy);
- d->transactionController = new TransactionController(transactionalStrategy, this);
- transactionalStrategy->setParent(d->transactionController);
- }
-
- DspxDocument::~DspxDocument() = default;
-
- dspx::Model *DspxDocument::model() const {
- Q_D(const DspxDocument);
- return d->model;
- }
-
- dspx::SelectionModel *DspxDocument::selectionModel() const {
- Q_D(const DspxDocument);
- return d->selectionModel;
- }
-
- TransactionController *DspxDocument::transactionController() const {
- Q_D(const DspxDocument);
- return d->transactionController;
- }
-
-}
-
-#include "moc_DspxDocument.cpp"
diff --git a/src/plugins/coreplugin/project/DspxDocument_p.h b/src/plugins/coreplugin/project/DspxDocument_p.h
deleted file mode 100644
index b92d6bc7..00000000
--- a/src/plugins/coreplugin/project/DspxDocument_p.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef DIFFSCOPE_COREPLUGIN_DSPXDOCUMENT_P_H
-#define DIFFSCOPE_COREPLUGIN_DSPXDOCUMENT_P_H
-
-#include
-
-namespace Core {
- class DspxDocumentPrivate {
- Q_DECLARE_PUBLIC(DspxDocument)
- public:
- DspxDocument *q_ptr;
- dspx::Model *model;
- dspx::SelectionModel *selectionModel;
- TransactionController *transactionController;
- };
-}
-
-#endif //DIFFSCOPE_COREPLUGIN_DSPXDOCUMENT_P_H
diff --git a/src/plugins/coreplugin/project/clipboard/DspxClipboard.cpp b/src/plugins/coreplugin/project/clipboard/DspxClipboard.cpp
new file mode 100644
index 00000000..e5293c1d
--- /dev/null
+++ b/src/plugins/coreplugin/project/clipboard/DspxClipboard.cpp
@@ -0,0 +1,137 @@
+#include "DspxClipboard.h"
+#include "DspxClipboard_p.h"
+
+#include
+#include
+#include
+
+namespace Core {
+
+ void DspxClipboardPrivate::handleClipboardChanged() {
+ Q_Q(DspxClipboard);
+ if (mode == DspxClipboard::Global)
+ Q_EMIT q->changed();
+ }
+
+ static QList supportedTypes() {
+ static const QList types = {
+ DspxClipboardData::Tempo,
+ DspxClipboardData::Label,
+ DspxClipboardData::Track,
+ DspxClipboardData::Clip,
+ DspxClipboardData::Note
+ };
+ return types;
+ }
+
+ static DspxClipboard *m_instance = nullptr;
+
+ DspxClipboard::DspxClipboard(QObject *parent) : QObject(parent), d_ptr(new DspxClipboardPrivate) {
+ Q_D(DspxClipboard);
+ Q_ASSERT(!m_instance);
+ m_instance = this;
+ d->q_ptr = this;
+ auto *clipboard = QGuiApplication::clipboard();
+ connect(clipboard, &QClipboard::dataChanged, this, [this] {
+ Q_D(DspxClipboard);
+ d->handleClipboardChanged();
+ });
+ }
+
+ DspxClipboard::~DspxClipboard() {
+ m_instance = nullptr;
+ }
+
+ DspxClipboard *DspxClipboard::instance() {
+ return m_instance;
+ }
+
+ DspxClipboard::Mode DspxClipboard::mode() const {
+ Q_D(const DspxClipboard);
+ return d->mode;
+ }
+
+ void DspxClipboard::setMode(Mode mode) {
+ Q_D(DspxClipboard);
+ if (d->mode == mode)
+ return;
+ d->mode = mode;
+ Q_EMIT changed();
+ }
+
+ void DspxClipboard::copy(const QList &data, QMimeData *additionalMimeData) {
+ Q_D(DspxClipboard);
+ if (d->mode == Internal) {
+ d->internalData.clear();
+ for (const auto &item : data) {
+ auto type = item.type();
+ if (d->internalData.contains(type))
+ continue;
+ d->internalData.insert(type, item);
+ }
+ Q_EMIT changed();
+ return;
+ }
+
+ auto *mimeData = additionalMimeData ? additionalMimeData : new QMimeData;
+
+ for (const auto &item : data) {
+ const auto type = item.type();
+ const auto mimeType = DspxClipboardData::mimeType(type);
+ if (mimeType.isEmpty() || mimeData->hasFormat(mimeType))
+ continue;
+ mimeData->setData(mimeType, item.toData());
+ }
+
+ QGuiApplication::clipboard()->setMimeData(mimeData);
+ }
+
+ DspxClipboardData DspxClipboard::paste(DspxClipboardData::Type expectedType, bool *ok) {
+ if (ok)
+ *ok = false;
+
+ Q_D(DspxClipboard);
+
+ if (d->mode == Internal) {
+ const auto it = d->internalData.constFind(expectedType);
+ if (it != d->internalData.cend() && it->has_value()) {
+ if (ok)
+ *ok = true;
+ return it->value();
+ }
+ return {};
+ }
+
+ const auto mimeType = DspxClipboardData::mimeType(expectedType);
+ const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData();
+ if (!mimeData || mimeType.isEmpty() || !mimeData->hasFormat(mimeType))
+ return {};
+
+ return DspxClipboardData::fromData(mimeData->data(mimeType), expectedType, ok);
+ }
+
+ QList DspxClipboard::availablePasteTypes() const {
+ QList types;
+ Q_D(const DspxClipboard);
+
+ if (d->mode == Internal) {
+ for (auto it = d->internalData.cbegin(); it != d->internalData.cend(); ++it) {
+ if (it.value().has_value())
+ types.append(it.key());
+ }
+ return types;
+ }
+
+ const QMimeData *mimeData = QGuiApplication::clipboard()->mimeData();
+ if (!mimeData)
+ return types;
+
+ for (const auto type : supportedTypes()) {
+ const auto mimeType = DspxClipboardData::mimeType(type);
+ if (!mimeType.isEmpty() && mimeData->hasFormat(mimeType))
+ types.append(type);
+ }
+ return types;
+ }
+
+}
diff --git a/src/plugins/coreplugin/project/clipboard/DspxClipboard.h b/src/plugins/coreplugin/project/clipboard/DspxClipboard.h
new file mode 100644
index 00000000..8b5af649
--- /dev/null
+++ b/src/plugins/coreplugin/project/clipboard/DspxClipboard.h
@@ -0,0 +1,47 @@
+#ifndef DIFFSCOPE_COREPLUGIN_DSPXCLIPBOARD_H
+#define DIFFSCOPE_COREPLUGIN_DSPXCLIPBOARD_H
+
+#include
+
+#include
+
+class QMimeData;
+
+namespace Core {
+
+ class DspxClipboardPrivate;
+
+ class CORE_EXPORT DspxClipboard : public QObject {
+ Q_OBJECT
+ Q_PROPERTY(Mode mode READ mode WRITE setMode NOTIFY changed)
+ Q_DECLARE_PRIVATE(DspxClipboard)
+
+ public:
+ enum Mode {
+ Global,
+ Internal
+ };
+ Q_ENUM(Mode)
+
+ explicit DspxClipboard(QObject *parent = nullptr);
+ ~DspxClipboard() override;
+
+ static DspxClipboard *instance();
+
+ Mode mode() const;
+ void setMode(Mode mode);
+
+ void copy(const QList &data, QMimeData *additionalMimeData);
+ DspxClipboardData paste(DspxClipboardData::Type expectedType, bool *ok = nullptr);
+ QList availablePasteTypes() const;
+
+ Q_SIGNALS:
+ void changed();
+
+ private:
+ QScopedPointer d_ptr;
+ };
+
+}
+
+#endif //DIFFSCOPE_COREPLUGIN_DSPXCLIPBOARD_H
diff --git a/src/plugins/coreplugin/project/clipboard/DspxClipboardData.cpp b/src/plugins/coreplugin/project/clipboard/DspxClipboardData.cpp
new file mode 100644
index 00000000..99b0302a
--- /dev/null
+++ b/src/plugins/coreplugin/project/clipboard/DspxClipboardData.cpp
@@ -0,0 +1,150 @@
+#include "DspxClipboardData.h"
+
+#include
+#include
+#include
+
+#include
+#include
+
+namespace Core {
+
+ QString DspxClipboardData::mimeType(Type type) {
+ switch (type) {
+ case Tempo:
+ return "application/x.diffscope.clipboard.tempo+json";
+ case Label:
+ return "application/x.diffscope.clipboard.label+json";
+ case Track:
+ return "application/x.diffscope.clipboard.track+json";
+ case Clip:
+ return "application/x.diffscope.clipboard.clip+json";
+ case Note:
+ return "application/x.diffscope.clipboard.note+json";
+ default:
+ return {};
+ }
+ }
+
+ DspxClipboardData::Type DspxClipboardData::typeFromMimeType(const QString &mimeType, bool *ok) {
+ if (ok)
+ *ok = true;
+ if (mimeType == "application/x.diffscope.clipboard.tempo+json") {
+ return Tempo;
+ }
+ if (mimeType == "application/x.diffscope.clipboard.label+json") {
+ return Label;
+ }
+ if (mimeType == "application/x.diffscope.clipboard.track+json") {
+ return Track;
+ }
+ if (mimeType == "application/x.diffscope.clipboard.clip+json") {
+ return Clip;
+ }
+ if (mimeType == "application/x.diffscope.clipboard.note+json") {
+ return Note;
+ }
+ if (ok)
+ *ok = false;
+ return {};
+ }
+
+ QByteArray DspxClipboardData::toData() const {
+ QJsonObject json;
+ json.insert("version", QDspx::Serializer::versionToText(QDspx::Model::V1));
+ json.insert("playhead", m_playhead);
+ json.insert("absolute", m_absolute);
+ json.insert("track", m_track);
+ QJsonArray dataArray;
+ QDspx::SerializationErrorList errors;
+ auto toJsonArray = [&] {
+ for (const auto &item : std::get(m_data)) {
+ dataArray.append(QDspx::JsonConverterV1::toJson(item, errors, {}));
+ }
+ };
+ switch (type()) {
+ case Tempo:
+ toJsonArray.operator()();
+ break;
+ case Label:
+ toJsonArray.operator()