diff --git a/src/appshell/qml/MuseScore/AppShell/AboutDialog.qml b/src/appshell/qml/MuseScore/AppShell/AboutDialog.qml
index 6d8efdf363f5..49e55519b9fe 100644
--- a/src/appshell/qml/MuseScore/AppShell/AboutDialog.qml
+++ b/src/appshell/qml/MuseScore/AppShell/AboutDialog.qml
@@ -33,134 +33,120 @@ StyledDialogView {
title: qsTrc("appshell/about", "About MuseScore Studio")
- contentHeight: 424
- contentWidth: 480
+ contentHeight: content.implicitHeight
+ contentWidth: 400
+
+ margins: 40
AboutModel {
id: aboutModel
}
ColumnLayout {
- anchors.fill: parent
- spacing: 30
-
- ColumnLayout {
- id: content
-
- Layout.fillWidth: true
- Layout.fillHeight: true
- Layout.topMargin: 36
- Layout.leftMargin: 40
- Layout.rightMargin: 40
+ id: content
- spacing: 32
+ anchors.fill: parent
+ spacing: 32
- Image {
- id: logo
- Layout.alignment: Qt.AlignHCenter
+ Image {
+ id: logo
+ Layout.alignment: Qt.AlignHCenter
- source: "resources/mu_logo.svg"
- sourceSize: Qt.size(100, 100)
+ source: "resources/mu_logo.svg"
+ sourceSize: Qt.size(100, 100)
- MouseArea {
- anchors.fill: parent
+ MouseArea {
+ anchors.fill: parent
- property int clickCount: 0
+ property int clickCount: 0
- onClicked: {
- clickCount++
+ onClicked: {
+ clickCount++
- if (clickCount % 3 == 0) {
- aboutModel.toggleDevMode()
- }
+ if (clickCount % 3 == 0) {
+ aboutModel.toggleDevMode()
}
}
}
+ }
- Column {
- spacing: 8
- Layout.fillWidth: true
+ Column {
+ spacing: 8
+ Layout.fillWidth: true
- StyledTextLabel {
- anchors.horizontalCenter: parent.horizontalCenter
- text: qsTrc("appshell/about", "Version:") + " " + aboutModel.museScoreVersion()
- font: ui.theme.bodyBoldFont
- }
+ StyledTextLabel {
+ anchors.horizontalCenter: parent.horizontalCenter
+ text: qsTrc("appshell/about", "Version: %1").arg(aboutModel.museScoreVersion())
+ font: ui.theme.bodyBoldFont
+ }
- Row {
- spacing: 4
- anchors.horizontalCenter: parent.horizontalCenter
+ Row {
+ spacing: 4
+ anchors.horizontalCenter: parent.horizontalCenter
- StyledTextLabel {
- anchors.verticalCenter: parent.verticalCenter
- text: qsTrc("appshell/about", "Revision:") + " " + aboutModel.museScoreRevision()
- }
+ StyledTextLabel {
+ anchors.verticalCenter: parent.verticalCenter
+ text: qsTrc("appshell/about", "Revision: %1").arg(aboutModel.museScoreRevisionLink())
+ }
- FlatButton {
- anchors.verticalCenter: parent.verticalCenter
- icon: IconCode.COPY
+ FlatButton {
+ anchors.verticalCenter: parent.verticalCenter
+ icon: IconCode.COPY
- onClicked: {
- aboutModel.copyRevisionToClipboard()
- }
+ onClicked: {
+ aboutModel.copyRevisionToClipboard()
}
}
}
+ }
- StyledTextLabel {
- Layout.fillWidth: true
- text: {
- let museScoreUrl = aboutModel.museScoreUrl()
-
- //: %1 will be a link to the MuseScore website
- let line1 = qsTrc("appshell/about", "Visit %1 for new versions and more information.")
- .arg(`${museScoreUrl.displayName}`)
+ StyledTextLabel {
+ Layout.fillWidth: true
- let line2 = qsTrc("appshell/about", "Get help with the program or contribute to its development.")
- .arg(aboutModel.museScoreForumUrl().url)
- .arg(aboutModel.museScoreContributionUrl().url)
+ text: qsTrc("appshell/about", "Build date: %1")
+ .arg(aboutModel.museScoreBuildDateTime())
- return line1 + "
" + line2
- }
- wrapMode: Text.WordWrap
- maximumLineCount: 3
- }
-
- StyledTextLabel {
- Layout.fillWidth: true
+ wrapMode: Text.WordWrap
+ maximumLineCount: 2
+ }
- text: qsTrc("appshell/about", "For privacy information, see our privacy policy.")
- .arg(aboutModel.museScorePrivacyPolicyUrl().url)
+ StyledTextLabel {
+ Layout.fillWidth: true
+ text: {
+ let museScoreUrl = aboutModel.museScoreUrl()
- wrapMode: Text.WordWrap
- maximumLineCount: 3
- }
+ //: %1 will be a link to the MuseScore website
+ let line1 = qsTrc("appshell/about", "Visit %1 for new versions and more information.")
+ .arg(`${museScoreUrl.displayName}`)
- StyledTextLabel {
- Layout.fillWidth: true
- text: qsTrc("appshell/about", "Copyright © 1999-2026 MuseScore Limited and others.\nPublished under the GNU General Public License version 3.")
- .arg("https://www.gnu.org/licenses/gpl-3.0.html")
- .replace("\n", "
")
+ let line2 = qsTrc("appshell/about", "Get help with the program or contribute to its development.")
+ .arg(aboutModel.museScoreForumUrl().url)
+ .arg(aboutModel.museScoreContributionUrl().url)
- wrapMode: Text.WordWrap
- maximumLineCount: 3
+ return line1 + "
" + line2
}
+ wrapMode: Text.WordWrap
+ maximumLineCount: 3
}
- RowLayout {
- Layout.alignment: Qt.AlignRight
- Layout.rightMargin: 16
- Layout.bottomMargin: 16
+ StyledTextLabel {
+ Layout.fillWidth: true
- spacing: 12
+ text: qsTrc("appshell/about", "For privacy information, see our privacy policy.")
+ .arg(aboutModel.museScorePrivacyPolicyUrl().url)
- FlatButton {
- text: qsTrc("global", "OK")
+ wrapMode: Text.WordWrap
+ maximumLineCount: 3
+ }
- onClicked: {
- root.hide()
- }
- }
+ StyledTextLabel {
+ Layout.fillWidth: true
+ text: qsTrc("appshell/about", "Copyright © 1999-2026 MuseScore Limited and others.\nPublished under the GNU General Public License version 3.")
+ .arg("https://www.gnu.org/licenses/gpl-3.0.html")
+ .replace("\n", "
")
+
+ wrapMode: Text.WordWrap
+ maximumLineCount: 3
}
}
}
diff --git a/src/appshell/qml/MuseScore/AppShell/aboutmodel.cpp b/src/appshell/qml/MuseScore/AppShell/aboutmodel.cpp
index f9c57e57a894..cda4783b3073 100644
--- a/src/appshell/qml/MuseScore/AppShell/aboutmodel.cpp
+++ b/src/appshell/qml/MuseScore/AppShell/aboutmodel.cpp
@@ -30,6 +30,9 @@
using namespace mu::appshell;
+//! NOTE: Should match value in projectpropertiesmodel.cpp
+static const QString GITHUB_REVISION_URL("https://github.com/musescore/MuseScore/commit/");
+
AboutModel::AboutModel(QObject* parent)
: QObject(parent), muse::Contextable(muse::iocCtxForQmlObject(this))
{
@@ -43,9 +46,33 @@ QString AboutModel::museScoreVersion() const
: version;
}
-QString AboutModel::museScoreRevision() const
+QString AboutModel::museScoreRevisionLink() const
+{
+ const QString rev = QString::fromStdString(configuration()->museScoreRevision());
+ if (rev.isEmpty()) {
+ return muse::qtrc("global", "Unknown");
+ }
+ const QString revUrl = GITHUB_REVISION_URL + rev;
+ return QString("%2").arg(revUrl, rev);
+}
+
+QString AboutModel::museScoreBuildDateTime() const
{
- return QString::fromStdString(configuration()->museScoreRevision());
+ auto buildDateISO = []() -> QString {
+ // Attempt to convert __DATE__ into ISO 8601 format (YYYY-MM-DD)
+ QDate date = QDate::fromString(__DATE__, "MMM dd yyyy");
+ if (!date.isValid()) {
+ date = QDate::fromString(__DATE__, "MMM d yyyy");
+ }
+ return date.isValid() ? date.toString(Qt::ISODate) : __DATE__;
+ };
+
+ QString dateTime;
+ dateTime += buildDateISO();
+ dateTime += " ";
+ dateTime += __TIME__;
+
+ return dateTime;
}
QVariantMap AboutModel::museScoreUrl() const
@@ -86,16 +113,23 @@ QVariantMap AboutModel::musicXMLLicenseDeedUrl() const
void AboutModel::copyRevisionToClipboard() const
{
- 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"))
- ? " or later" : ""))
- .arg(QSysInfo::currentCpuArchitecture())
- .arg(QSysInfo::WordSize)
- .arg(application()->version().toString())
- .arg(application()->build())
- .arg(application()->revision()));
+ QString osName = QSysInfo::prettyProductName();
+ if (QSysInfo::productType() == "windows" && (QSysInfo::productVersion() == "10" || QSysInfo::productVersion() == "11")) {
+ osName += " or later";
+ }
+
+ QString forClipboard = QString("OS: %1, Arch.: %2, MuseScore Studio version (%3-bit): %4-%5")
+ .arg(osName, QSysInfo::currentCpuArchitecture())
+ .arg(QSysInfo::WordSize)
+ .arg(application()->version().toString(), application()->build());
+
+ const QString rev = QString::fromStdString(configuration()->museScoreRevision());
+ if (!rev.isEmpty()) {
+ const QString revUrl = GITHUB_REVISION_URL + rev;
+ forClipboard += QString(", revision: [%1](%2)").arg(rev, revUrl);
+ }
+
+ QGuiApplication::clipboard()->setText(forClipboard);
}
void AboutModel::toggleDevMode()
diff --git a/src/appshell/qml/MuseScore/AppShell/aboutmodel.h b/src/appshell/qml/MuseScore/AppShell/aboutmodel.h
index 8b0652decc8a..dfe186f59e6a 100644
--- a/src/appshell/qml/MuseScore/AppShell/aboutmodel.h
+++ b/src/appshell/qml/MuseScore/AppShell/aboutmodel.h
@@ -49,7 +49,8 @@ class AboutModel : public QObject, public muse::Contextable
explicit AboutModel(QObject* parent = nullptr);
Q_INVOKABLE QString museScoreVersion() const;
- Q_INVOKABLE QString museScoreRevision() const;
+ Q_INVOKABLE QString museScoreRevisionLink() const;
+ Q_INVOKABLE QString museScoreBuildDateTime() const;
Q_INVOKABLE QVariantMap museScoreUrl() const;
Q_INVOKABLE QVariantMap museScoreForumUrl() const;
Q_INVOKABLE QVariantMap museScoreContributionUrl() const;
diff --git a/src/engraving/rendering/score/headerfooterlayout.cpp b/src/engraving/rendering/score/headerfooterlayout.cpp
index beb823c63bd0..68229050401e 100644
--- a/src/engraving/rendering/score/headerfooterlayout.cpp
+++ b/src/engraving/rendering/score/headerfooterlayout.cpp
@@ -357,14 +357,15 @@ TextBlock HeaderFooterLayout::replaceTextMacros(LayoutContext& ctx, const Page*
break;
case 'r':
if (page->score()->dirty()) {
- static String revision; // FIXME
- newFragments.back().text += revision;
+ newFragments.back().text += application()->revision();
} else {
int rev = page->score()->mscoreRevision();
- if (rev > 99999) { // MuseScore 1.3 is decimal 5702, 2.0 and later uses a 7-digit hex SHA
- newFragments.back().text += String::number(rev, 16);
- } else {
+ if (rev > 0 && rev <= 5709) { // MuseScore 1.x and earlier used decimal numbers, referring to a commit on SourceForge.net, the largest being 5709
newFragments.back().text += String::number(rev, 10);
+ } else if (rev > 0xffffff) { // MuseScore 2.0 and later use a >= 7-digit hex SHA, referring to a commit on GitHub.com
+ newFragments.back().text += String::number(rev, 16);
+ } else { // unknown, like in a self-built development version, or in a very old version of MuseScore before the revision number was tracked
+ newFragments.back().text += String::number(rev, 10); // or "" or "Unknown"?
}
}
break;
diff --git a/src/project/qml/MuseScore/Project/internal/Properties/projectpropertiesmodel.cpp b/src/project/qml/MuseScore/Project/internal/Properties/projectpropertiesmodel.cpp
index 7adf125ed6af..28041627c076 100644
--- a/src/project/qml/MuseScore/Project/internal/Properties/projectpropertiesmodel.cpp
+++ b/src/project/qml/MuseScore/Project/internal/Properties/projectpropertiesmodel.cpp
@@ -32,6 +32,10 @@ using namespace muse::modularity;
using namespace mu::notation;
using namespace mu::project;
+//! NOTE: Should match value in aboutmodel.cpp
+static const QString GITHUB_REVISION_URL("https://github.com/musescore/MuseScore/commit/");
+static const QString SOURCEFORGE_REVISION_URL("https://sourceforge.net/p/mscore/code/");
+
ProjectPropertiesModel::ProjectPropertiesModel(QObject* parent)
: QAbstractListModel(parent), muse::Contextable(muse::iocCtxForQmlObject(this))
{
@@ -159,15 +163,23 @@ QString ProjectPropertiesModel::version() const
QString ProjectPropertiesModel::revision() const
{
- int rev = m_projectMetaInfo.musescoreRevision;
- QString revision;
- if (rev > 99999) { // MuseScore 1.3 is decimal 5702, 2.0 and later uses a 7-digit hex SHA
- revision = QString::number(rev, 16);
- } else {
- revision = QString::number(rev, 10);
+ const int rev = m_projectMetaInfo.musescoreRevision;
+ if (rev > 0 && rev <= 5709) {
+ // MuseScore 1.x and earlier used decimal numbers, referring to a commit on SourceForge.net, the largest being 5709
+ const QString revText = QString::number(rev, 10);
+ const QString revUrl = SOURCEFORGE_REVISION_URL + revText;
+ return QString("%2").arg(revUrl, revText);
+ }
+
+ if (rev > 0xffffff) {
+ // MuseScore 2.0 and later use a >= 7-digit hex SHA, referring to a commit on GitHub.com
+ const QString revText = QString::number(rev, 16);
+ const QString revUrl = GITHUB_REVISION_URL + revText;
+ return QString("%2").arg(revUrl, revText);
}
- return revision;
+ // unknown, like in a self-built development version, or in a very old version of MuseScore before the revision number was tracked
+ return muse::qtrc("global", "Unknown");
}
QString ProjectPropertiesModel::apiLevel() const