diff --git a/src/appshell/qml/MuseScore/AppShell/aboutmodel.cpp b/src/appshell/qml/MuseScore/AppShell/aboutmodel.cpp
index c391c806343b6..f9c57e57a8944 100644
--- a/src/appshell/qml/MuseScore/AppShell/aboutmodel.cpp
+++ b/src/appshell/qml/MuseScore/AppShell/aboutmodel.cpp
@@ -19,14 +19,15 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#include "aboutmodel.h"
-#include "translation.h"
+#include "aboutmodel.h"
-#include
#include
+#include
#include
+#include "translation.h"
+
using namespace mu::appshell;
AboutModel::AboutModel(QObject* parent)
@@ -85,7 +86,7 @@ QVariantMap AboutModel::musicXMLLicenseDeedUrl() const
void AboutModel::copyRevisionToClipboard() const
{
- QApplication::clipboard()->setText(
+ QGuiApplication::clipboard()->setText(
QString("OS: %1, Arch.: %2, MuseScore Studio version (%3-bit): %4-%5, revision: github-musescore-musescore-%6")
.arg(QSysInfo::prettyProductName()
+ ((QSysInfo::productType() == "windows" && (QSysInfo::productVersion() == "10" || QSysInfo::productVersion() == "11"))
diff --git a/src/engraving/api/tests/CMakeLists.txt b/src/engraving/api/tests/CMakeLists.txt
index cb8230666768b..6bb5be1e0792f 100644
--- a/src/engraving/api/tests/CMakeLists.txt
+++ b/src/engraving/api/tests/CMakeLists.txt
@@ -21,13 +21,20 @@
set(MODULE_TEST engraving_api_tests)
set(MODULE_TEST_SRC
+ ${PROJECT_SOURCE_DIR}/src/engraving/tests/utils/scorerw.cpp
+ ${PROJECT_SOURCE_DIR}/src/engraving/tests/utils/scorerw.h
+
${CMAKE_CURRENT_LIST_DIR}/environment.cpp
${CMAKE_CURRENT_LIST_DIR}/util_tests.cpp
${CMAKE_CURRENT_LIST_DIR}/score_tests.cpp
+ ${CMAKE_CURRENT_LIST_DIR}/spanner_tests.cpp
)
set(MODULE_TEST_LINK
+ Qt::Qml
engraving
)
+set(MODULE_TEST_DATA_ROOT ${CMAKE_CURRENT_LIST_DIR})
+
include(SetupGTest)
diff --git a/src/engraving/api/tests/environment.cpp b/src/engraving/api/tests/environment.cpp
index 190ab777cfac4..e76a30c4a73c5 100644
--- a/src/engraving/api/tests/environment.cpp
+++ b/src/engraving/api/tests/environment.cpp
@@ -28,6 +28,8 @@
#include "engraving/dom/instrtemplate.h"
#include "engraving/dom/mscore.h"
+#include "engraving/tests/utils/scorerw.h"
+
#include "log.h"
static muse::testing::SuiteEnvironment engraving_api_se(
@@ -39,6 +41,8 @@ static muse::testing::SuiteEnvironment engraving_api_se(
[]() {
LOGI() << "engraving API tests suite post init";
+ mu::engraving::ScoreRW::setRootPath(muse::String::fromUtf8(engraving_api_tests_DATA_ROOT));
+
mu::engraving::MScore::testMode = true;
mu::engraving::MScore::noGui = true;
diff --git a/src/engraving/api/tests/spanner_tests.cpp b/src/engraving/api/tests/spanner_tests.cpp
new file mode 100644
index 0000000000000..7085da23dbd53
--- /dev/null
+++ b/src/engraving/api/tests/spanner_tests.cpp
@@ -0,0 +1,76 @@
+/*
+ * SPDX-License-Identifier: GPL-3.0-only
+ * MuseScore-Studio-CLA-applies
+ *
+ * MuseScore Studio
+ * Music Composition & Notation
+ *
+ * Copyright (C) 2026 MuseScore Limited and others
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+
+#include "engraving/api/v1/score.h"
+#include "engraving/api/v1/elements.h"
+
+#include "engraving/tests/utils/scorerw.h"
+
+using namespace muse;
+using namespace mu::engraving;
+
+static const String SPANNERS_DATA_DIR("../../tests/spanners_data/");
+
+/// Test Plugin API score.spanners property
+/// Verify that score.spanners exposes all spanners in the score
+TEST(Engraving_ApiSpannerTests, scoreSpanners)
+{
+ // Load a score file
+ MasterScore* score = ScoreRW::readScore(SPANNERS_DATA_DIR + u"glissando01.mscx");
+ ASSERT_TRUE(score);
+
+ // Create Plugin API wrapper for the score
+ apiv1::Score apiScore(score);
+
+ // Get spanners using Plugin API
+ QQmlListProperty scoreSpanners = apiScore.spanners();
+
+ // Basic sanity checks: the property should return a valid list
+ EXPECT_NE(scoreSpanners.count, nullptr);
+ EXPECT_NE(scoreSpanners.at, nullptr);
+
+ qsizetype spannerCount = scoreSpanners.count(&scoreSpanners);
+ EXPECT_GE(spannerCount, 0) << "Count should be non-negative";
+
+ // Get spanners directly from the score for comparison
+ auto domSpanners = score->spannerList();
+
+ // The Plugin API should expose the same number of spanners
+ EXPECT_EQ(spannerCount, (qsizetype)domSpanners.size())
+ << "Plugin API should expose all spanners from the score";
+
+ // Verify each spanner can be accessed and has valid properties
+ for (int i = 0; i < spannerCount; i++) {
+ auto* item = scoreSpanners.at(&scoreSpanners, i);
+ apiv1::Spanner* apiItem = qobject_cast(item);
+ ASSERT_TRUE(apiItem) << "Spanner " << i << " should be a valid Spanner API object";
+ ASSERT_TRUE(apiItem->spanner()) << "Spanner " << i << " should have a valid underlying Spanner";
+
+ track_idx_t track = apiItem->spanner()->track();
+ EXPECT_LT(track, score->ntracks()) << "Spanner " << i << "'s underlying Spanner should not be garbage";
+ }
+
+ delete score;
+}
diff --git a/src/engraving/tests/spanners_tests.cpp b/src/engraving/tests/spanners_tests.cpp
index 8f75588e57f80..c1c807bd4f731 100644
--- a/src/engraving/tests/spanners_tests.cpp
+++ b/src/engraving/tests/spanners_tests.cpp
@@ -38,9 +38,6 @@
#include "engraving/editing/transaction/transaction.h"
#include "engraving/editing/transaction/undostack.h"
-#include "engraving/api/v1/score.h"
-#include "engraving/api/v1/elements.h"
-
#include "utils/scorerw.h"
#include "utils/scorecomp.h"
@@ -600,51 +597,3 @@ TEST_F(Engraving_SpannersTests, spanners16)
EXPECT_TRUE(ScoreComp::saveCompareScore(score, u"smallstaff01.mscx", SPANNERS_DATA_DIR + u"smallstaff01-ref.mscx"));
delete score;
}
-
-//---------------------------------------------------------
-/// spanners17
-/// Test Plugin API score.spanners property
-/// Verify that score.spanners exposes all spanners in the score
-//---------------------------------------------------------
-
-TEST_F(Engraving_SpannersTests, spanners17_pluginAPI_scoreSpanners)
-{
- // Load a score file
- MasterScore* score = ScoreRW::readScore(SPANNERS_DATA_DIR + u"glissando01.mscx");
- EXPECT_TRUE(score);
-
- // Create Plugin API wrapper for the score
- apiv1::Score apiScore(score);
-
- // Get spanners using Plugin API
- QQmlListProperty scoreSpanners = apiScore.spanners();
-
- // Basic sanity checks: the property should return a valid list
- EXPECT_NE(scoreSpanners.count, nullptr);
- EXPECT_NE(scoreSpanners.at, nullptr);
-
- int spannerCount = scoreSpanners.count(&scoreSpanners);
- EXPECT_GE(spannerCount, 0) << "Count should be non-negative";
-
- // Get spanners directly from the score for comparison
- auto domSpanners = score->spannerList();
-
- // The Plugin API should expose the same number of spanners
- EXPECT_EQ(spannerCount, (int)domSpanners.size())
- << "Plugin API should expose all spanners from the score";
-
- // Verify each spanner can be accessed and has valid properties
- for (int i = 0; i < spannerCount; i++) {
- auto* item = scoreSpanners.at(&scoreSpanners, i);
- apiv1::Spanner* apiItem = qobject_cast(item);
- EXPECT_TRUE(apiItem != nullptr) << "Spanner " << i << " should be a valid Spanner";
-
- if (apiItem && apiItem->spanner()) {
- // Verify we can access the track property (spanners have tracks)
- track_idx_t track = apiItem->spanner()->track();
- EXPECT_GE(track, 0) << "Spanner " << i << " should have a valid track";
- }
- }
-
- delete score;
-}
diff --git a/src/notation/CMakeLists.txt b/src/notation/CMakeLists.txt
index e0d14b95e0903..bd9f192878e23 100644
--- a/src/notation/CMakeLists.txt
+++ b/src/notation/CMakeLists.txt
@@ -136,6 +136,7 @@ if(NOT OS_IS_WASM)
endif()
target_link_libraries(notation PRIVATE
+ Qt::Widgets # for QApplication::cursorFlashTime() in notationinteraction.cpp
muse::draw
engraving
)
diff --git a/src/notation/internal/notationinteraction.cpp b/src/notation/internal/notationinteraction.cpp
index b4bd44c817274..1e8eadf0b0069 100644
--- a/src/notation/internal/notationinteraction.cpp
+++ b/src/notation/internal/notationinteraction.cpp
@@ -26,16 +26,18 @@
#include
#include
-#include
-#include
+
+#include // for QApplication::cursorFlashTime()
#include
-#include
+#include
+#include
+#include
#include
#include
-#include
+#include
+#include
#include
#include
-#include
#include "defer.h"
#include "ptrutils.h"
@@ -5391,7 +5393,7 @@ void NotationInteraction::copySelection()
if (!mimeData) {
return;
}
- QApplication::clipboard()->setMimeData(mimeData);
+ QGuiApplication::clipboard()->setMimeData(mimeData);
}
}
@@ -5494,7 +5496,7 @@ void NotationInteraction::repeatSelection()
void NotationInteraction::copyLyrics()
{
QString text = score()->extractLyrics();
- QApplication::clipboard()->setText(text);
+ QGuiApplication::clipboard()->setText(text);
}
void NotationInteraction::pasteSelection(const Fraction& scale)
@@ -5505,7 +5507,7 @@ void NotationInteraction::pasteSelection(const Fraction& scale)
if (isTextEditingStarted()) {
pasteIntoTextEdit();
} else {
- const QMimeData* mimeData = QApplication::clipboard()->mimeData();
+ const QMimeData* mimeData = QGuiApplication::clipboard()->mimeData();
QMimeDataAdapter ma(mimeData);
succeeded = Paste::paste(score()->transactionManager()->currentOrDummyTransaction(), score(), &ma, nullptr, scale);
m_editData.element = nullptr;
@@ -5525,7 +5527,7 @@ void NotationInteraction::pasteSelection(const Fraction& scale)
void NotationInteraction::pasteIntoTextEdit()
{
- const QMimeData* mimeData = QApplication::clipboard()->mimeData();
+ const QMimeData* mimeData = QGuiApplication::clipboard()->mimeData();
if (mimeData->hasFormat(TextEditData::mimeRichTextFormat)) {
const QString txt = QString::fromUtf8(mimeData->data(TextEditData::mimeRichTextFormat));
toTextBase(m_editData.element)->paste(txt);
@@ -5574,7 +5576,7 @@ void NotationInteraction::swapSelection()
// Save old selection to clipboard...
QMimeData* mimeData = new QMimeData();
mimeData->setData(selection.mimeType(), oldSelection);
- QApplication::clipboard()->setMimeData(mimeData);
+ QGuiApplication::clipboard()->setMimeData(mimeData);
}
void NotationInteraction::deleteSelection()
diff --git a/src/notationscene/qml/MuseScore/NotationScene/CMakeLists.txt b/src/notationscene/qml/MuseScore/NotationScene/CMakeLists.txt
index ab9e05f1004c1..247446b260609 100644
--- a/src/notationscene/qml/MuseScore/NotationScene/CMakeLists.txt
+++ b/src/notationscene/qml/MuseScore/NotationScene/CMakeLists.txt
@@ -321,6 +321,7 @@ target_include_directories(notationscene_qml PRIVATE
)
target_link_libraries(notationscene_qml PRIVATE
+ Qt::Widgets # for QApplication
muse::uicomponents_qml
)
diff --git a/src/notationscene/qml/MuseScore/NotationScene/tests/CMakeLists.txt b/src/notationscene/qml/MuseScore/NotationScene/tests/CMakeLists.txt
index f5a821b804604..e248cb67d3280 100644
--- a/src/notationscene/qml/MuseScore/NotationScene/tests/CMakeLists.txt
+++ b/src/notationscene/qml/MuseScore/NotationScene/tests/CMakeLists.txt
@@ -31,6 +31,7 @@ set(MODULE_TEST_SRC
)
set(MODULE_TEST_LINK
+ Qt::Quick
engraving
notationscene_qml
)
diff --git a/src/preferences/qml/MuseScore/Preferences/preferencesmodel.cpp b/src/preferences/qml/MuseScore/Preferences/preferencesmodel.cpp
index b0ad77d10219d..ae878b57c231b 100644
--- a/src/preferences/qml/MuseScore/Preferences/preferencesmodel.cpp
+++ b/src/preferences/qml/MuseScore/Preferences/preferencesmodel.cpp
@@ -19,7 +19,8 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
-#include
+
+#include
#include "preferencesmodel.h"
@@ -233,15 +234,15 @@ void PreferencesModel::askForConfirmationOfPreferencesReset()
void PreferencesModel::resetFactorySettings()
{
static constexpr bool KEEP_DEFAULT_SETTINGS = true;
- QApplication::setOverrideCursor(Qt::WaitCursor);
- QApplication::processEvents();
+ QGuiApplication::setOverrideCursor(Qt::WaitCursor);
+ QGuiApplication::processEvents();
configuration()->revertToFactorySettings(KEEP_DEFAULT_SETTINGS);
// Unreset the "First Launch Completed" setting so the first-time launch wizard does not appear.
configuration()->setHasCompletedFirstLaunchSetup(true);
configuration()->startEditSettings();
- QApplication::restoreOverrideCursor();
+ QGuiApplication::restoreOverrideCursor();
}
void PreferencesModel::apply()