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()