LCOV - code coverage report
Current view: top level - src/notation/internal - masternotation.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 453 0
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "masternotation.h"
      24              : 
      25              : #include <QFileInfo>
      26              : 
      27              : #include "log.h"
      28              : #include "realfn.h"
      29              : #include "translation.h"
      30              : 
      31              : #include "engraving/style/defaultstyle.h"
      32              : #include "engraving/style/pagestyle.h"
      33              : 
      34              : #include "engraving/dom/factory.h"
      35              : #include "engraving/dom/masterscore.h"
      36              : #include "engraving/dom/part.h"
      37              : #include "engraving/dom/staff.h"
      38              : #include "engraving/dom/excerpt.h"
      39              : #include "engraving/dom/measure.h"
      40              : #include "engraving/dom/box.h"
      41              : #include "engraving/dom/keysig.h"
      42              : #include "engraving/dom/sig.h"
      43              : #include "engraving/dom/tempotext.h"
      44              : 
      45              : #include "engraving/editing/autospatium.h"
      46              : #include "engraving/editing/editkeysig.h"
      47              : #include "engraving/editing/edittimesig.h"
      48              : #include "engraving/editing/transaction/transaction.h"
      49              : 
      50              : #include "inotationelements.h" // IWYU pragma: keep
      51              : #include "inotationsolomutestate.h"
      52              : #include "excerptnotation.h"
      53              : #include "masternotationparts.h"
      54              : #include "notationautomation.h"
      55              : #include "types/scorecreateoptions.h"
      56              : 
      57              : #ifdef MUE_BUILD_ENGRAVING_PLAYBACK
      58              : #include "notationplayback.h"
      59              : #else
      60              : #include "notationplaybackstub.h"
      61              : #endif
      62              : 
      63              : #include "../notationerrors.h"
      64              : 
      65              : using namespace mu::notation;
      66              : using namespace mu::engraving;
      67              : using namespace muse;
      68              : using namespace muse::async;
      69              : 
      70            0 : static ExcerptNotation* get_impl(const IExcerptNotationPtr& excerpt)
      71              : {
      72            0 :     return static_cast<ExcerptNotation*>(excerpt.get());
      73              : }
      74              : 
      75            0 : static IExcerptNotationPtr createAndInitExcerptNotation(MasterNotation* master, mu::engraving::Excerpt* excerpt,
      76              :                                                         const muse::modularity::ContextPtr& iocCtx)
      77              : {
      78            0 :     auto excerptNotation = std::make_shared<ExcerptNotation>(master, excerpt, iocCtx);
      79            0 :     excerptNotation->init();
      80              : 
      81            0 :     return excerptNotation;
      82            0 : }
      83              : 
      84            0 : MasterNotation::MasterNotation(project::INotationProject* project, const muse::modularity::ContextPtr& iocCtx)
      85            0 :     : Notation(this, iocCtx), m_project(project)
      86              : {
      87            0 :     m_parts = std::make_shared<MasterNotationParts>(this, interaction(), undoStack(), style());
      88              : 
      89              : #ifdef MUE_BUILD_ENGRAVING_PLAYBACK
      90            0 :     m_notationPlayback = std::make_shared<NotationPlayback>(this, m_notationChanged, iocCtx);
      91              : #else
      92              :     m_notationPlayback = std::make_shared<NotationPlaybackStub>();
      93              : #endif
      94              : 
      95            0 :     m_notationAutomation = std::make_shared<NotationAutomation>(undoStack());
      96              : 
      97            0 :     m_parts->partsChanged().onNotify(this, [this]() {
      98            0 :         notifyAboutNotationChanged();
      99            0 :     });
     100              : 
     101            0 :     async::NotifyList<const Part*> partList = m_parts->partList();
     102              : 
     103            0 :     partList.onChanged(this, [this]() {
     104            0 :         onPartsChanged();
     105            0 :     });
     106              : 
     107            0 :     partList.onItemAdded(this, [this](const Part*) {
     108            0 :         onPartsChanged();
     109            0 :     });
     110              : 
     111            0 :     partList.onItemRemoved(this, [this](const Part*) {
     112            0 :         onPartsChanged();
     113            0 :     });
     114            0 : }
     115              : 
     116            0 : MasterNotation::~MasterNotation()
     117              : {
     118            0 :     m_parts = nullptr;
     119              : 
     120            0 :     unloadExcerpts(m_potentialExcerpts);
     121            0 : }
     122              : 
     123            0 : mu::project::INotationProject* MasterNotation::project() const
     124              : {
     125            0 :     return m_project;
     126              : }
     127              : 
     128            0 : int MasterNotation::mscVersion() const
     129              : {
     130            0 :     if (!masterScore()) {
     131            0 :         return 0;
     132              :     }
     133              : 
     134            0 :     return masterScore()->mscVersion();
     135              : }
     136              : 
     137            0 : INotationPtr MasterNotation::notation()
     138              : {
     139            0 :     return shared_from_this();
     140              : }
     141              : 
     142            0 : void MasterNotation::initAfterSettingScore(const MasterScore* score, bool disablePlayback)
     143              : {
     144            0 :     IF_ASSERT_FAILED(score) {
     145            0 :         return;
     146              :     }
     147              : 
     148            0 :     TRACEFUNC;
     149              : 
     150            0 :     score->changesChannel().onReceive(this, [this](const ScoreChanges& changes) {
     151            0 :         if (!changes.isTextEditing) {
     152            0 :             updateExcerpts();
     153              :         }
     154            0 :     });
     155              : 
     156            0 :     if (!disablePlayback) {
     157            0 :         m_notationPlayback->init();
     158              :     }
     159              : 
     160            0 :     initExcerptNotations(score->excerpts());
     161            0 : }
     162              : 
     163            0 : void MasterNotation::setMasterScore(mu::engraving::MasterScore* score, bool disablePlayback)
     164              : {
     165            0 :     if (masterScore() == score) {
     166            0 :         return;
     167              :     }
     168              : 
     169            0 :     TRACEFUNC;
     170              : 
     171            0 :     setScore(score);
     172            0 :     std::static_pointer_cast<NotationAutomation>(m_notationAutomation)->setMasterScore(score);
     173              : 
     174            0 :     score->updateSwing();
     175              : 
     176            0 :     initAfterSettingScore(score, disablePlayback);
     177            0 : }
     178              : 
     179            0 : mu::engraving::MasterScore* MasterNotation::masterScore() const
     180              : {
     181            0 :     return dynamic_cast<mu::engraving::MasterScore*>(score());
     182              : }
     183              : 
     184            0 : static void clearMeasures(mu::engraving::MasterScore* masterScore)
     185              : {
     186            0 :     TRACEFUNC;
     187              : 
     188            0 :     for (mu::engraving::Score* score : masterScore->scoreList()) {
     189            0 :         for (Part* part : score->parts()) {
     190            0 :             part->removeNonPrimaryInstruments();
     191              :         }
     192              : 
     193            0 :         mu::engraving::MeasureBaseList* measures = score->measures();
     194            0 :         for (mu::engraving::MeasureBase* measure = measures->first(); measure; measure = measure->next()) {
     195            0 :             measure->deleteLater();
     196              :         }
     197              : 
     198            0 :         auto spanners = score->spanner();
     199            0 :         for (auto spanner = spanners.begin(); spanner != spanners.end(); spanner = ++spanner) {
     200            0 :             score->removeSpanner(spanner->second);
     201              :         }
     202              : 
     203            0 :         measures->clear();
     204            0 :     }
     205              : 
     206            0 :     masterScore->invalidateRepeatList();
     207            0 :     masterScore->updateRepeatList();
     208            0 : }
     209              : 
     210            0 : static void createMeasures(MasterScore* masterScore, const ScoreCreateOptions& scoreOptions)
     211              : {
     212            0 :     TRACEFUNC;
     213              : 
     214            0 :     masterScore->sigmap()->add(0, scoreOptions.globalTimesig);
     215              : 
     216            0 :     KeySigEvent keySigEvent;
     217            0 :     if (scoreOptions.key == Key::INVALID) {
     218              :         // Make atonal key signature
     219            0 :         keySigEvent.setCustom(true);
     220            0 :         keySigEvent.setMode(KeyMode::NONE);
     221              :     } else {
     222            0 :         keySigEvent.setConcertKey(scoreOptions.key);
     223              :     }
     224              : 
     225              :     // Ensure all key sigs that may have been in the template file are cleared
     226            0 :     for (Staff* staff : masterScore->staves()) {
     227            0 :         KeyList* keys = staff->keyList();
     228            0 :         keys->clear();
     229              :     }
     230              : 
     231            0 :     const int totalMeasures = scoreOptions.withPickupMeasure ? scoreOptions.totalMeasures + 1 : scoreOptions.totalMeasures;
     232            0 :     for (int i = 0; i < totalMeasures; ++i) {
     233            0 :         MeasureBase* measureBase = masterScore->insertMeasure();
     234            0 :         Measure* measure = measureBase && measureBase->isMeasure() ? toMeasure(measureBase) : nullptr;
     235            0 :         IF_ASSERT_FAILED(measure) {
     236            0 :             break;
     237              :         }
     238              : 
     239            0 :         measure->setTimesig(scoreOptions.globalTimesig);
     240              : 
     241            0 :         if (i > 0) {
     242            0 :             measure->setTicks(scoreOptions.globalTimesig);
     243            0 :             continue;
     244              :         }
     245              : 
     246              :         // Special handling for first measure (apply pickups, timesigs, and keysigs)...
     247              : 
     248            0 :         measure->setExcludeFromNumbering(scoreOptions.withPickupMeasure);
     249            0 :         measure->adjustToLen(scoreOptions.withPickupMeasure ? scoreOptions.pickupTimesig : scoreOptions.globalTimesig);
     250              : 
     251              :         // Add timesigs...
     252            0 :         TimeSig* timesig = Factory::createTimeSig(masterScore->dummy());
     253            0 :         timesig->setSig(scoreOptions.globalTimesig, scoreOptions.timesigType);
     254            0 :         Transaction& tx = masterScore->transactionManager()->currentOrDummyTransaction();
     255            0 :         EditTimeSig::addTimeSig(tx, masterScore, measure, /*staffIdx*/ 0, timesig, /*local*/ false);
     256              : 
     257            0 :         for (Staff* staff : masterScore->staves()) {
     258              :             // Add keysig for each staff...
     259            0 :             mu::engraving::EditKeySig::undoChangeKeySig(tx, masterScore, staff, measure->tick(), keySigEvent);
     260              :         }
     261              :     }
     262            0 : }
     263              : 
     264              : //! NOTE: this method with all of its dependencies was copied from MU3
     265              : //! source: file.cpp, MuseScore::getNewFile()
     266            0 : Ret MasterNotation::setupNewScore(mu::engraving::MasterScore* score, const ScoreCreateOptions& scoreOptions)
     267              : {
     268            0 :     TRACEFUNC;
     269              : 
     270            0 :     setScore(score);
     271            0 :     std::static_pointer_cast<NotationAutomation>(m_notationAutomation)->setMasterScore(score);
     272              : 
     273            0 :     undoStack()->lock();
     274              : 
     275            0 :     parts()->setParts(scoreOptions.parts, scoreOptions.order);
     276              : 
     277            0 :     score->checkChordList();
     278            0 :     score->updateSwing();
     279            0 :     score->updateCapo();
     280              : 
     281            0 :     applyOptions(score, scoreOptions);
     282              : 
     283            0 :     score->initAutomation();
     284              : 
     285            0 :     initAfterSettingScore(score);
     286            0 :     addExcerptsToMasterScore(score->excerpts());
     287              : 
     288            0 :     undoStack()->unlock();
     289              : 
     290            0 :     return make_ret(Err::NoError);
     291            0 : }
     292              : 
     293            0 : void MasterNotation::applyOptions(mu::engraving::MasterScore* score, const ScoreCreateOptions& scoreOptions, bool createdFromTemplate)
     294              : {
     295            0 :     TRACEFUNC;
     296              : 
     297            0 :     mu::engraving::VBox* nvb = nullptr;
     298              : 
     299            0 :     if (createdFromTemplate) {
     300            0 :         mu::engraving::MeasureBase* mb = score->first();
     301            0 :         if (mb && mb->isVBox()) {
     302            0 :             mu::engraving::VBox* tvb = toVBox(mb);
     303            0 :             nvb = Factory::createTitleVBox(score);
     304            0 :             nvb->setBoxHeight(tvb->boxHeight());
     305            0 :             nvb->setBoxWidth(tvb->boxWidth());
     306            0 :             nvb->setTopGap(tvb->topGap());
     307            0 :             nvb->setBottomGap(tvb->bottomGap());
     308            0 :             nvb->setTopMargin(tvb->topMargin());
     309            0 :             nvb->setBottomMargin(tvb->bottomMargin());
     310            0 :             nvb->setLeftMargin(tvb->leftMargin());
     311            0 :             nvb->setRightMargin(tvb->rightMargin());
     312            0 :             nvb->setAutoSizeEnabled(tvb->isAutoSizeEnabled());
     313              :         }
     314              : 
     315            0 :         for (mu::engraving::Score* s : score->scoreList()) {
     316            0 :             s->clearSystemLocks();
     317            0 :         }
     318            0 :         clearMeasures(score);
     319              : 
     320              :         // for templates using built-in base page style, set score page style to default (may be user-defined)
     321            0 :         for (auto st : pageStyles()) {
     322            0 :             if (st != Sid::pageTwosided && RealIsEqual(score->style().styleD(st), DefaultStyle::baseStyle().styleD(st))) {
     323            0 :                 score->style().set(st, DefaultStyle::defaultStyle().value(st));
     324              :             }
     325              :         }
     326              :     }
     327              : 
     328            0 :     score->checkChordList();
     329              : 
     330            0 :     createMeasures(score, scoreOptions);
     331              : 
     332              :     {
     333            0 :         const QString title = score->metaTag(u"workTitle");
     334            0 :         const QString subtitle = score->metaTag(u"subtitle");
     335            0 :         const QString composer = score->metaTag(u"composer");
     336            0 :         const QString lyricist = score->metaTag(u"lyricist");
     337              : 
     338            0 :         if (!title.isEmpty() || !subtitle.isEmpty() || !composer.isEmpty() || !lyricist.isEmpty()) {
     339            0 :             mu::engraving::MeasureBase* measure = score->measures()->first();
     340            0 :             if (!measure->isVBox()) {
     341            0 :                 if (!nvb) {
     342            0 :                     nvb = Factory::createTitleVBox(score);
     343              :                 }
     344            0 :                 nvb->setTick(mu::engraving::Fraction(0, 1));
     345            0 :                 nvb->setNext(measure);
     346            0 :                 score->measures()->add(nvb);
     347            0 :             } else if (nvb) {
     348            0 :                 delete nvb;
     349            0 :                 nvb = nullptr;
     350              :             }
     351              : 
     352            0 :             auto setText = [score](mu::engraving::TextStyleType textItemId, const QString& text) {
     353            0 :                 mu::engraving::TextBase* textItem = score->getText(textItemId);
     354              : 
     355            0 :                 if (!textItem) {
     356            0 :                     textItem = score->addText(textItemId);
     357              :                 }
     358              : 
     359            0 :                 if (textItem) {
     360            0 :                     textItem->setPlainText(text);
     361              :                 }
     362            0 :             };
     363              : 
     364            0 :             if (!title.isEmpty()) {
     365            0 :                 setText(mu::engraving::TextStyleType::TITLE, title);
     366              :             }
     367            0 :             if (!subtitle.isEmpty()) {
     368            0 :                 setText(mu::engraving::TextStyleType::SUBTITLE, subtitle);
     369              :             }
     370            0 :             if (!composer.isEmpty()) {
     371            0 :                 setText(mu::engraving::TextStyleType::COMPOSER, composer);
     372              :             }
     373            0 :             if (!lyricist.isEmpty()) {
     374            0 :                 setText(mu::engraving::TextStyleType::LYRICIST, lyricist);
     375              :             }
     376            0 :         } else if (nvb) {
     377            0 :             delete nvb;
     378            0 :             nvb = nullptr;
     379              :         }
     380              : 
     381            0 :         if (nvb) {
     382            0 :             nvb->manageExclusionFromParts(/*exclude*/ false);
     383              :         }
     384            0 :     }
     385              : 
     386            0 :     if (scoreOptions.withTempo) {
     387            0 :         String text { u"<sym>metNoteQuarterUp</sym> = %1" };
     388            0 :         const double bpm = scoreOptions.tempo.valueBpm;
     389            0 :         double qpm = bpm; // internal tempo value is always expressed in quarter notes
     390              : 
     391            0 :         const bool withDot = scoreOptions.tempo.withDot;
     392            0 :         switch (scoreOptions.tempo.duration) {
     393            0 :         case DurationType::V_WHOLE:
     394            0 :             text = "<sym>metNoteWhole</sym> = %1";
     395            0 :             qpm *= 4.0;
     396            0 :             break;
     397            0 :         case DurationType::V_HALF:
     398            0 :             if (withDot) {
     399            0 :                 text = "<sym>metNoteHalfUp</sym><sym>space</sym><sym>metAugmentationDot</sym> = %1";
     400            0 :                 qpm *= 3.0;
     401              :             } else {
     402            0 :                 text = "<sym>metNoteHalfUp</sym> = %1";
     403            0 :                 qpm *= 2.0;
     404              :             }
     405            0 :             break;
     406            0 :         case DurationType::V_QUARTER:
     407            0 :             if (withDot) {
     408            0 :                 text = "<sym>metNoteQuarterUp</sym><sym>space</sym><sym>metAugmentationDot</sym> = %1";
     409            0 :                 qpm *= 1.5;
     410              :             } else {
     411            0 :                 text = "<sym>metNoteQuarterUp</sym> = %1";
     412              :                 //qpm *= 1.0;
     413              :             }
     414            0 :             break;
     415            0 :         case DurationType::V_EIGHTH:
     416            0 :             if (withDot) {
     417            0 :                 text = "<sym>metNote8thUp</sym><sym>space</sym><sym>metAugmentationDot</sym> = %1";
     418            0 :                 qpm *= 0.75;
     419              :             } else {
     420            0 :                 text = "<sym>metNote8thUp</sym> = %1";
     421            0 :                 qpm *= 0.5;
     422              :             }
     423            0 :             break;
     424            0 :         case DurationType::V_16TH:
     425            0 :             if (withDot) {
     426            0 :                 text = "<sym>metNote16thUp</sym><sym>space</sym><sym>metAugmentationDot</sym> = %1";
     427            0 :                 qpm *= 0.375;
     428              :             } else {
     429            0 :                 text = "<sym>metNote16thUp</sym> = %1";
     430            0 :                 qpm *= 0.25;
     431              :             }
     432            0 :             break;
     433            0 :         default:
     434            0 :             break;
     435              :         }
     436              : 
     437            0 :         engraving::Segment* seg = score->firstMeasure()->first(engraving::SegmentType::ChordRest);
     438            0 :         engraving::TempoText* tt = new engraving::TempoText(seg);
     439            0 :         tt->setXmlText(text.arg(bpm));
     440            0 :         tt->setTempo(qpm / 60.0); // qpm -> qps
     441            0 :         tt->setFollowText(true);
     442            0 :         tt->setTrack(0);
     443            0 :         seg->add(tt);
     444            0 :         for (auto staff : score->systemObjectStaves()) {
     445            0 :             TempoText* linkedTt = toTempoText(tt->linkedClone());
     446            0 :             linkedTt->setScore(score);
     447            0 :             linkedTt->setTrack(staff->idx() * VOICES);
     448            0 :             seg->add(linkedTt);
     449              :         }
     450            0 :     }
     451              : 
     452            0 :     score->updateTicksAndTimeSigMap();
     453            0 :     AutoSpatium::update(score);
     454              : 
     455              :     {
     456            0 :         mu::engraving::ScoreLoad sl;
     457            0 :         for (mu::engraving::Score* s : score->scoreList()) {
     458            0 :             s->doLayout();
     459            0 :         }
     460            0 :     }
     461              : 
     462            0 :     if (m_notationPlayback) {
     463            0 :         m_notationPlayback->reload();
     464              :     }
     465            0 : }
     466              : 
     467            0 : void MasterNotation::unloadExcerpts(ExcerptNotationList& excerpts)
     468              : {
     469            0 :     for (const IExcerptNotationPtr& ptr : excerpts) {
     470            0 :         Excerpt* excerpt = get_impl(ptr)->excerpt();
     471            0 :         if (!excerpt) {
     472            0 :             continue;
     473              :         }
     474              : 
     475            0 :         if (Score* score = excerpt->excerptScore()) {
     476            0 :             delete score;
     477            0 :             excerpt->setExcerptScore(nullptr);
     478              :         }
     479              :     }
     480              : 
     481            0 :     excerpts.clear();
     482            0 : }
     483              : 
     484            0 : void MasterNotation::initExcerpts(const ExcerptNotationList& excerpts)
     485              : {
     486            0 :     for (const IExcerptNotationPtr& excerptNotation : excerpts) {
     487            0 :         ExcerptNotation* impl = get_impl(excerptNotation);
     488              : 
     489            0 :         masterScore()->initExcerpt(impl->excerpt());
     490            0 :         impl->init();
     491              : 
     492            0 :         initNotationSoloMuteState(impl->notation());
     493              :     }
     494            0 : }
     495              : 
     496            0 : void MasterNotation::setExcerpts(const ExcerptNotationList& excerpts)
     497              : {
     498            0 :     TRACEFUNC;
     499              : 
     500            0 :     if (m_excerpts == excerpts) {
     501            0 :         return;
     502              :     }
     503              : 
     504            0 :     MasterScore* score = masterScore();
     505            0 :     IF_ASSERT_FAILED(score) {
     506            0 :         return;
     507              :     }
     508              : 
     509            0 :     undoStack()->prepareChanges(TranslatableString("undoableAction", "Add/remove parts"));
     510              : 
     511              :     // Delete old excerpts (that are not included in the new list)
     512            0 :     for (const IExcerptNotationPtr& excerptNotation : m_excerpts) {
     513            0 :         auto it = std::find(excerpts.begin(), excerpts.end(), excerptNotation);
     514            0 :         if (it != excerpts.end()) {
     515            0 :             continue;
     516              :         }
     517              : 
     518            0 :         score->deleteExcerpt(get_impl(excerptNotation)->excerpt());
     519              :     }
     520              : 
     521              :     // Init new excerpts
     522            0 :     for (size_t i = 0; i < excerpts.size(); ++i) {
     523            0 :         const IExcerptNotationPtr& excerptNotation = excerpts.at(i);
     524            0 :         ExcerptNotation* excerptNotationImpl = get_impl(excerptNotation);
     525              : 
     526            0 :         auto it = std::find(m_excerpts.cbegin(), m_excerpts.cend(), excerptNotation);
     527            0 :         if (it != m_excerpts.end()) {
     528            0 :             std::vector<Excerpt*>& msExcerpts = score->excerpts();
     529            0 :             muse::moveItem(msExcerpts, muse::indexOf(msExcerpts, excerptNotationImpl->excerpt()), i);
     530            0 :             continue;
     531            0 :         }
     532              : 
     533            0 :         score->initAndAddExcerpt(excerptNotationImpl->excerpt(), false);
     534            0 :         excerptNotationImpl->init();
     535              : 
     536            0 :         initNotationSoloMuteState(excerptNotationImpl->notation());
     537              :     }
     538              : 
     539            0 :     score->setExcerptsChanged(false);
     540              : 
     541            0 :     undoStack()->commitChanges();
     542              : 
     543            0 :     doSetExcerpts(excerpts);
     544            0 : }
     545              : 
     546            0 : void MasterNotation::resetExcerpt(IExcerptNotationPtr& excerptNotation)
     547              : {
     548            0 :     if (!excerptNotation || !excerptNotation->isInited()) {
     549            0 :         return;
     550              :     }
     551              : 
     552            0 :     TRACEFUNC;
     553              : 
     554            0 :     undoStack()->prepareChanges(TranslatableString("undoableAction", "Reset part"));
     555              : 
     556            0 :     mu::engraving::Excerpt* oldExcerpt = get_impl(excerptNotation)->excerpt();
     557            0 :     masterScore()->deleteExcerpt(oldExcerpt);
     558              : 
     559            0 :     mu::engraving::Excerpt* newExcerpt = new mu::engraving::Excerpt(*oldExcerpt, false);
     560            0 :     masterScore()->initAndAddExcerpt(newExcerpt, false);
     561              : 
     562            0 :     newExcerpt->excerptScore()->setIsOpen(oldExcerpt->excerptScore()->isOpen());
     563              : 
     564            0 :     get_impl(excerptNotation)->reinit(newExcerpt);
     565              : 
     566            0 :     masterScore()->setExcerptsChanged(false);
     567              : 
     568            0 :     undoStack()->commitChanges();
     569            0 : }
     570              : 
     571            0 : void MasterNotation::sortExcerpts(ExcerptNotationList& excerpts)
     572              : {
     573            0 :     TRACEFUNC;
     574              : 
     575            0 :     std::vector<ID> partIdList;
     576            0 :     for (const Part* part : masterScore()->parts()) {
     577            0 :         partIdList.push_back(part->id());
     578              :     }
     579              : 
     580            0 :     std::sort(excerpts.begin(), excerpts.end(), [&partIdList](const IExcerptNotationPtr& f, const IExcerptNotationPtr& s) {
     581              :         //! NOTE: excertps created by users are always at the end of the list in alphabetical order
     582            0 :         if (f->isCustom() && !s->isCustom()) {
     583            0 :             return false;
     584            0 :         } else if (!f->isCustom() && s->isCustom()) {
     585            0 :             return true;
     586            0 :         } else if (f->isCustom() && s->isCustom()) {
     587            0 :             return f->name() < s->name();
     588              :         }
     589              : 
     590              :         //! NOTE: sort standard excerpts in the order of their initial parts in the main score
     591            0 :         const ID& initialPart1 = get_impl(f)->excerpt()->initialPartId();
     592            0 :         const ID& initialPart2 = get_impl(s)->excerpt()->initialPartId();
     593              : 
     594            0 :         size_t index1 = muse::indexOf(partIdList, initialPart1);
     595            0 :         size_t index2 = muse::indexOf(partIdList, initialPart2);
     596              : 
     597            0 :         return index1 < index2;
     598              :     });
     599            0 : }
     600              : 
     601            0 : void MasterNotation::setExcerptIsOpen(const INotationPtr excerptNotation, bool open)
     602              : {
     603            0 :     if (excerptNotation->isOpen() == open) {
     604            0 :         return;
     605              :     }
     606              : 
     607            0 :     excerptNotation->setIsOpen(open);
     608              : 
     609            0 :     if (open) {
     610            0 :         excerptNotation->elements()->msScore()->doLayout();
     611              :     }
     612              : }
     613              : 
     614            0 : void MasterNotation::doSetExcerpts(const ExcerptNotationList& excerpts)
     615              : {
     616            0 :     TRACEFUNC;
     617              : 
     618            0 :     m_excerpts = excerpts;
     619            0 :     m_excerptsChanged.notify();
     620              : 
     621            0 :     static_cast<MasterNotationParts*>(m_parts.get())->setExcerpts(excerpts);
     622              : 
     623            0 :     updatePotentialExcerpts();
     624            0 : }
     625              : 
     626            0 : void MasterNotation::updateExcerpts()
     627              : {
     628            0 :     if (!masterScore()->excerptsChanged()) {
     629            0 :         return;
     630              :     }
     631              : 
     632            0 :     TRACEFUNC;
     633              : 
     634            0 :     ExcerptNotationList updatedExcerpts;
     635              : 
     636            0 :     const std::vector<mu::engraving::Excerpt*>& excerpts = masterScore()->excerpts();
     637              : 
     638              :     // exclude notations for old excerpts
     639            0 :     for (const IExcerptNotationPtr& excerptNotation : m_excerpts) {
     640            0 :         ExcerptNotation* impl = get_impl(excerptNotation);
     641              : 
     642            0 :         if (muse::contains(excerpts, impl->excerpt())) {
     643            0 :             updatedExcerpts.push_back(excerptNotation);
     644            0 :             continue;
     645              :         }
     646              :     }
     647              : 
     648              :     // create notations for new excerpts
     649            0 :     for (mu::engraving::Excerpt* excerpt : excerpts) {
     650            0 :         if (containsExcerpt(excerpt)) {
     651            0 :             continue;
     652              :         }
     653              : 
     654            0 :         IExcerptNotationPtr excerptNotation = createAndInitExcerptNotation(this, excerpt, iocContext());
     655            0 :         bool open = excerpt->excerptScore()->isOpen();
     656            0 :         if (open) {
     657            0 :             excerptNotation->notation()->elements()->msScore()->doLayout();
     658              :         }
     659              : 
     660            0 :         initNotationSoloMuteState(excerptNotation->notation());
     661              : 
     662            0 :         updatedExcerpts.push_back(excerptNotation);
     663            0 :     }
     664              : 
     665            0 :     doSetExcerpts(updatedExcerpts);
     666              : 
     667            0 :     masterScore()->setExcerptsChanged(false);
     668            0 : }
     669              : 
     670            0 : void MasterNotation::updatePotentialExcerpts() const
     671              : {
     672            0 :     TRACEFUNC;
     673              : 
     674            0 :     auto findExcerptByPart = [](const ExcerptNotationList& excerpts, const Part* part) {
     675            0 :         return std::find_if(excerpts.cbegin(), excerpts.cend(), [part](const IExcerptNotationPtr& notation) {
     676            0 :             return get_impl(notation)->excerpt()->initialPartId() == part->id();
     677            0 :         });
     678              :     };
     679              : 
     680            0 :     ExcerptNotationList potentialExcerpts;
     681            0 :     std::vector<Part*> partsWithoutExcerpt;
     682              : 
     683            0 :     for (Part* part : score()->parts()) {
     684            0 :         if (part->isSharedPart() || findExcerptByPart(m_excerpts, part) != m_excerpts.end()) {
     685            0 :             continue;
     686              :         }
     687              : 
     688            0 :         if (!m_potentialExcerptsForcedDirty) {
     689            0 :             auto it = findExcerptByPart(m_potentialExcerpts, part);
     690            0 :             if (it != m_potentialExcerpts.cend()) {
     691            0 :                 potentialExcerpts.push_back(*it);
     692            0 :                 continue;
     693              :             }
     694              :         }
     695              : 
     696            0 :         partsWithoutExcerpt.push_back(part);
     697              :     }
     698              : 
     699            0 :     std::vector<mu::engraving::Excerpt*> excerpts = mu::engraving::Excerpt::createExcerptsFromParts(partsWithoutExcerpt, masterScore());
     700              : 
     701            0 :     for (mu::engraving::Excerpt* excerpt : excerpts) {
     702            0 :         auto excerptNotation = std::make_shared<ExcerptNotation>(const_cast<MasterNotation*>(this), excerpt, iocContext());
     703            0 :         potentialExcerpts.push_back(excerptNotation);
     704            0 :     }
     705              : 
     706            0 :     m_potentialExcerpts = std::move(potentialExcerpts);
     707            0 :     m_potentialExcerptsForcedDirty = false;
     708            0 : }
     709              : 
     710            0 : bool MasterNotation::containsExcerpt(const mu::engraving::Excerpt* excerpt) const
     711              : {
     712            0 :     for (const IExcerptNotationPtr& excerptNotation : m_excerpts) {
     713            0 :         if (get_impl(excerptNotation)->excerpt() == excerpt) {
     714            0 :             return true;
     715              :         }
     716              :     }
     717              : 
     718            0 :     return false;
     719              : }
     720              : 
     721            0 : void MasterNotation::onPartsChanged()
     722              : {
     723            0 :     m_hasPartsChanged.notify();
     724            0 :     m_potentialExcerptsForcedDirty = true;
     725            0 : }
     726              : 
     727            0 : IExcerptNotationPtr MasterNotation::createEmptyExcerpt(const QString& name) const
     728              : {
     729              :     auto excerptNotation
     730            0 :         = std::make_shared<ExcerptNotation>(const_cast<MasterNotation*>(this), new mu::engraving::Excerpt(masterScore()), iocContext());
     731            0 :     excerptNotation->setName(name);
     732              : 
     733            0 :     return excerptNotation;
     734            0 : }
     735              : 
     736            0 : const ExcerptNotationList& MasterNotation::excerpts() const
     737              : {
     738            0 :     return m_excerpts;
     739              : }
     740              : 
     741            0 : muse::async::Notification MasterNotation::excerptsChanged() const
     742              : {
     743            0 :     return m_excerptsChanged;
     744              : }
     745              : 
     746            0 : INotationPartsPtr MasterNotation::parts() const
     747              : {
     748            0 :     return m_parts;
     749              : }
     750              : 
     751            0 : bool MasterNotation::hasParts() const
     752              : {
     753            0 :     return m_parts && m_parts->hasParts();
     754              : }
     755              : 
     756            0 : Notification MasterNotation::hasPartsChanged() const
     757              : {
     758            0 :     return m_hasPartsChanged;
     759              : }
     760              : 
     761            0 : INotationPlaybackPtr MasterNotation::playback() const
     762              : {
     763            0 :     return m_notationPlayback;
     764              : }
     765              : 
     766            0 : INotationAutomationPtr MasterNotation::automation() const
     767              : {
     768            0 :     return m_notationAutomation;
     769              : }
     770              : 
     771            0 : void MasterNotation::initNotationSoloMuteState(const INotationPtr notation)
     772              : {
     773            0 :     IF_ASSERT_FAILED(notation) {
     774            0 :         return;
     775              :     }
     776              : 
     777            0 :     const INotationSoloMuteStatePtr excerptSoloMuteState = notation->soloMuteState();
     778              : 
     779              :     // Iterate over all parts (not just the excerpt parts) - tracks that do exist in the master notation but
     780              :     // not in the excerpt should be muted in the excerpt...
     781            0 :     for (const Part* masterPart : parts()->partList()) {
     782            0 :         const Part* excerptPart = notation->parts()->part(masterPart->id());
     783            0 :         const bool shouldMute = !excerptPart || !excerptPart->isVisible();
     784            0 :         const INotationSoloMuteState::SoloMuteState state = { shouldMute, /*solo*/ false };
     785            0 :         for (const InstrumentTrackId& trackId : masterPart->instrumentTrackIdSet()) {
     786            0 :             excerptSoloMuteState->setTrackSoloMuteState(trackId, state);
     787            0 :         }
     788            0 :         if (masterPart->hasChordSymbol()) {
     789            0 :             const InstrumentTrackId& chordsId = playback()->chordSymbolsTrackId(masterPart->id());
     790            0 :             excerptSoloMuteState->setTrackSoloMuteState(chordsId, state);
     791            0 :         }
     792            0 :     }
     793            0 : }
     794              : 
     795            0 : const ExcerptNotationList& MasterNotation::potentialExcerpts() const
     796              : {
     797            0 :     updatePotentialExcerpts();
     798              : 
     799            0 :     return m_potentialExcerpts;
     800              : }
     801              : 
     802            0 : void MasterNotation::initExcerptNotations(const std::vector<mu::engraving::Excerpt*>& excerpts)
     803              : {
     804            0 :     TRACEFUNC;
     805              : 
     806            0 :     ExcerptNotationList notationExcerpts;
     807              : 
     808            0 :     for (mu::engraving::Excerpt* excerpt : excerpts) {
     809            0 :         if (excerpt->isEmpty()) {
     810            0 :             masterScore()->initEmptyExcerpt(excerpt);
     811              :         }
     812              : 
     813            0 :         IExcerptNotationPtr excerptNotation = createAndInitExcerptNotation(this, excerpt, iocContext());
     814            0 :         notationExcerpts.push_back(excerptNotation);
     815            0 :     }
     816              : 
     817            0 :     masterScore()->setExcerptsChanged(false);
     818              : 
     819            0 :     doSetExcerpts(notationExcerpts);
     820            0 : }
     821              : 
     822            0 : void MasterNotation::addExcerptsToMasterScore(const std::vector<mu::engraving::Excerpt*>& excerpts)
     823              : {
     824            0 :     TRACEFUNC;
     825              : 
     826            0 :     for (mu::engraving::Excerpt* excerpt : excerpts) {
     827            0 :         masterScore()->initAndAddExcerpt(excerpt, false);
     828              :     }
     829              : 
     830            0 :     masterScore()->setExcerptsChanged(false);
     831            0 : }
        

Generated by: LCOV version 2.0-1