LCOV - code coverage report
Current view: top level - src/propertiespanel/qml/MuseScore/PropertiesPanel - propertiespanelabstractmodel.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 418 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 "propertiespanelabstractmodel.h"
      24              : 
      25              : #include "engraving/dom/barline.h"
      26              : #include "engraving/dom/dynamic.h"
      27              : #include "engraving/dom/property.h"
      28              : #include "engraving/dom/score.h"
      29              : #include "engraving/dom/tempotext.h"
      30              : 
      31              : #include "notation/inotationinteraction.h" // IWYU pragma: keep
      32              : #include "notation/inotationstyle.h"
      33              : #include "notation/inotationundostack.h"
      34              : #include "notation/utilities/offsetutilities.h"
      35              : 
      36              : #include "modularity/ioc.h"
      37              : 
      38              : #include "types/texttypes.h"
      39              : 
      40              : #include "log.h"
      41              : 
      42              : using namespace mu::propertiespanel;
      43              : using namespace mu::notation;
      44              : using namespace mu::engraving;
      45              : 
      46              : static const QMap<mu::engraving::ElementType, PropertiesPanelModelType> NOTATION_ELEMENT_MODEL_TYPES = {
      47              :     { mu::engraving::ElementType::NOTE, PropertiesPanelModelType::TYPE_NOTE },
      48              :     { mu::engraving::ElementType::STEM, PropertiesPanelModelType::TYPE_NOTE },
      49              :     { mu::engraving::ElementType::NOTEDOT, PropertiesPanelModelType::TYPE_NOTE },
      50              :     { mu::engraving::ElementType::NOTEHEAD, PropertiesPanelModelType::TYPE_NOTE },
      51              :     { mu::engraving::ElementType::NOTELINE, PropertiesPanelModelType::TYPE_NOTE },
      52              :     { mu::engraving::ElementType::SHADOW_NOTE, PropertiesPanelModelType::TYPE_NOTE },
      53              :     { mu::engraving::ElementType::HOOK, PropertiesPanelModelType::TYPE_NOTE },
      54              :     { mu::engraving::ElementType::BEAM, PropertiesPanelModelType::TYPE_NOTE },
      55              :     { mu::engraving::ElementType::GLISSANDO, PropertiesPanelModelType::TYPE_GLISSANDO },
      56              :     { mu::engraving::ElementType::GLISSANDO_SEGMENT, PropertiesPanelModelType::TYPE_GLISSANDO },
      57              :     { mu::engraving::ElementType::VIBRATO, PropertiesPanelModelType::TYPE_VIBRATO },
      58              :     { mu::engraving::ElementType::VIBRATO_SEGMENT, PropertiesPanelModelType::TYPE_VIBRATO },
      59              :     { mu::engraving::ElementType::SLUR, PropertiesPanelModelType::TYPE_SLUR },
      60              :     { mu::engraving::ElementType::SLUR_SEGMENT, PropertiesPanelModelType::TYPE_SLUR },
      61              :     { mu::engraving::ElementType::HAMMER_ON_PULL_OFF, PropertiesPanelModelType::TYPE_HAMMER_ON_PULL_OFF },
      62              :     { mu::engraving::ElementType::HAMMER_ON_PULL_OFF_SEGMENT, PropertiesPanelModelType::TYPE_HAMMER_ON_PULL_OFF },
      63              :     { mu::engraving::ElementType::TIE, PropertiesPanelModelType::TYPE_TIE },
      64              :     { mu::engraving::ElementType::TIE_SEGMENT, PropertiesPanelModelType::TYPE_TIE },
      65              :     { mu::engraving::ElementType::LAISSEZ_VIB, PropertiesPanelModelType::TYPE_LAISSEZ_VIB },
      66              :     { mu::engraving::ElementType::LAISSEZ_VIB_SEGMENT, PropertiesPanelModelType::TYPE_LAISSEZ_VIB },
      67              :     { mu::engraving::ElementType::PARTIAL_TIE, PropertiesPanelModelType::TYPE_PARTIAL_TIE },
      68              :     { mu::engraving::ElementType::PARTIAL_TIE_SEGMENT, PropertiesPanelModelType::TYPE_PARTIAL_TIE },
      69              :     { mu::engraving::ElementType::TEMPO_TEXT, PropertiesPanelModelType::TYPE_TEMPO },
      70              :     { mu::engraving::ElementType::FERMATA, PropertiesPanelModelType::TYPE_FERMATA },
      71              :     { mu::engraving::ElementType::LAYOUT_BREAK, PropertiesPanelModelType::TYPE_SECTIONBREAK },
      72              :     { mu::engraving::ElementType::BAR_LINE, PropertiesPanelModelType::TYPE_BARLINE },
      73              :     { mu::engraving::ElementType::PLAY_COUNT_TEXT, PropertiesPanelModelType::TYPE_PLAY_COUNT_TEXT },
      74              :     { mu::engraving::ElementType::MARKER, PropertiesPanelModelType::TYPE_MARKER },
      75              :     { mu::engraving::ElementType::JUMP, PropertiesPanelModelType::TYPE_JUMP },
      76              :     { mu::engraving::ElementType::KEYSIG, PropertiesPanelModelType::TYPE_KEYSIGNATURE },
      77              :     { mu::engraving::ElementType::ACCIDENTAL, PropertiesPanelModelType::TYPE_ACCIDENTAL },
      78              :     { mu::engraving::ElementType::FRET_DIAGRAM, PropertiesPanelModelType::TYPE_FRET_DIAGRAM },
      79              :     { mu::engraving::ElementType::PEDAL, PropertiesPanelModelType::TYPE_PEDAL },
      80              :     { mu::engraving::ElementType::PEDAL_SEGMENT, PropertiesPanelModelType::TYPE_PEDAL },
      81              :     { mu::engraving::ElementType::SPACER, PropertiesPanelModelType::TYPE_SPACER },
      82              :     { mu::engraving::ElementType::CLEF, PropertiesPanelModelType::TYPE_CLEF },
      83              :     { mu::engraving::ElementType::HAIRPIN, PropertiesPanelModelType::TYPE_HAIRPIN },
      84              :     { mu::engraving::ElementType::HAIRPIN_SEGMENT, PropertiesPanelModelType::TYPE_HAIRPIN },
      85              :     { mu::engraving::ElementType::OTTAVA, PropertiesPanelModelType::TYPE_OTTAVA },
      86              :     { mu::engraving::ElementType::OTTAVA_SEGMENT, PropertiesPanelModelType::TYPE_OTTAVA },
      87              :     { mu::engraving::ElementType::VOLTA, PropertiesPanelModelType::TYPE_VOLTA },
      88              :     { mu::engraving::ElementType::VOLTA_SEGMENT, PropertiesPanelModelType::TYPE_VOLTA },
      89              :     { mu::engraving::ElementType::STAFFTYPE_CHANGE, PropertiesPanelModelType::TYPE_STAFF_TYPE_CHANGES },
      90              :     { mu::engraving::ElementType::TBOX, PropertiesPanelModelType::TYPE_TEXT_FRAME },// text frame
      91              :     { mu::engraving::ElementType::VBOX, PropertiesPanelModelType::TYPE_VERTICAL_FRAME },// vertical frame
      92              :     { mu::engraving::ElementType::HBOX, PropertiesPanelModelType::TYPE_HORIZONTAL_FRAME },// horizontal frame
      93              :     { mu::engraving::ElementType::FBOX, PropertiesPanelModelType::TYPE_FRET_FRAME },// fret diagram legend
      94              :     { mu::engraving::ElementType::ARTICULATION, PropertiesPanelModelType::TYPE_ARTICULATION },
      95              :     { mu::engraving::ElementType::TAPPING,      PropertiesPanelModelType::TYPE_TAPPING },
      96              :     { mu::engraving::ElementType::TAPPING_HALF_SLUR_SEGMENT, PropertiesPanelModelType::TYPE_TAPPING },
      97              :     { mu::engraving::ElementType::ORNAMENT, PropertiesPanelModelType::TYPE_ORNAMENT },
      98              :     { mu::engraving::ElementType::TRILL, PropertiesPanelModelType::TYPE_ORNAMENT },
      99              :     { mu::engraving::ElementType::TRILL_SEGMENT, PropertiesPanelModelType::TYPE_ORNAMENT },
     100              :     { mu::engraving::ElementType::IMAGE, PropertiesPanelModelType::TYPE_IMAGE },
     101              :     { mu::engraving::ElementType::HARMONY, PropertiesPanelModelType::TYPE_CHORD_SYMBOL },
     102              :     { mu::engraving::ElementType::AMBITUS, PropertiesPanelModelType::TYPE_AMBITUS },
     103              :     { mu::engraving::ElementType::BRACKET, PropertiesPanelModelType::TYPE_BRACKET },
     104              :     { mu::engraving::ElementType::TIMESIG, PropertiesPanelModelType::TYPE_TIME_SIGNATURE },
     105              :     { mu::engraving::ElementType::MMREST, PropertiesPanelModelType::TYPE_MMREST },
     106              :     { mu::engraving::ElementType::BEND, PropertiesPanelModelType::TYPE_BEND },
     107              :     { mu::engraving::ElementType::GUITAR_BEND, PropertiesPanelModelType::TYPE_BEND },
     108              :     { mu::engraving::ElementType::GUITAR_BEND_SEGMENT, PropertiesPanelModelType::TYPE_BEND },
     109              :     { mu::engraving::ElementType::GUITAR_BEND_HOLD, PropertiesPanelModelType::TYPE_BEND },
     110              :     { mu::engraving::ElementType::GUITAR_BEND_HOLD_SEGMENT, PropertiesPanelModelType::TYPE_BEND },
     111              :     { mu::engraving::ElementType::TREMOLOBAR, PropertiesPanelModelType::TYPE_TREMOLOBAR },
     112              :     { mu::engraving::ElementType::TREMOLO_SINGLECHORD, PropertiesPanelModelType::TYPE_TREMOLO },
     113              :     { mu::engraving::ElementType::TREMOLO_TWOCHORD, PropertiesPanelModelType::TYPE_TREMOLO },
     114              :     { mu::engraving::ElementType::MEASURE_REPEAT, PropertiesPanelModelType::TYPE_MEASURE_REPEAT },
     115              :     { mu::engraving::ElementType::TUPLET, PropertiesPanelModelType::TYPE_TUPLET },
     116              :     { mu::engraving::ElementType::TEXTLINE, PropertiesPanelModelType::TYPE_TEXT_LINE },
     117              :     { mu::engraving::ElementType::TEXTLINE_SEGMENT, PropertiesPanelModelType::TYPE_TEXT_LINE },
     118              :     { mu::engraving::ElementType::PALM_MUTE, PropertiesPanelModelType::TYPE_TEXT_LINE },
     119              :     { mu::engraving::ElementType::PALM_MUTE_SEGMENT, PropertiesPanelModelType::TYPE_TEXT_LINE },
     120              :     { mu::engraving::ElementType::LET_RING, PropertiesPanelModelType::TYPE_TEXT_LINE },
     121              :     { mu::engraving::ElementType::LET_RING_SEGMENT, PropertiesPanelModelType::TYPE_TEXT_LINE },
     122              :     { mu::engraving::ElementType::WHAMMY_BAR, PropertiesPanelModelType::TYPE_TEXT_LINE },
     123              :     { mu::engraving::ElementType::WHAMMY_BAR_SEGMENT, PropertiesPanelModelType::TYPE_TEXT_LINE },
     124              :     { mu::engraving::ElementType::NOTELINE, PropertiesPanelModelType::TYPE_NOTELINE },
     125              :     { mu::engraving::ElementType::NOTELINE_SEGMENT, PropertiesPanelModelType::TYPE_NOTELINE },
     126              :     { mu::engraving::ElementType::GRADUAL_TEMPO_CHANGE, PropertiesPanelModelType::TYPE_GRADUAL_TEMPO_CHANGE },
     127              :     { mu::engraving::ElementType::GRADUAL_TEMPO_CHANGE_SEGMENT, PropertiesPanelModelType::TYPE_GRADUAL_TEMPO_CHANGE },
     128              :     { mu::engraving::ElementType::INSTRUMENT_NAME, PropertiesPanelModelType::TYPE_INSTRUMENT_NAME },
     129              :     { mu::engraving::ElementType::LYRICS, PropertiesPanelModelType::TYPE_LYRICS },
     130              :     { mu::engraving::ElementType::LYRICSLINE, PropertiesPanelModelType::TYPE_LYRICS_LINE },
     131              :     { mu::engraving::ElementType::LYRICSLINE_SEGMENT, PropertiesPanelModelType::TYPE_LYRICS_LINE },
     132              :     { mu::engraving::ElementType::PARTIAL_LYRICSLINE, PropertiesPanelModelType::TYPE_PARTIAL_LYRICS_LINE },
     133              :     { mu::engraving::ElementType::PARTIAL_LYRICSLINE_SEGMENT, PropertiesPanelModelType::TYPE_PARTIAL_LYRICS_LINE },
     134              :     { mu::engraving::ElementType::REST, PropertiesPanelModelType::TYPE_REST },
     135              :     { mu::engraving::ElementType::DYNAMIC, PropertiesPanelModelType::TYPE_DYNAMIC },
     136              :     { mu::engraving::ElementType::EXPRESSION, PropertiesPanelModelType::TYPE_EXPRESSION },
     137              :     { mu::engraving::ElementType::STRING_TUNINGS, PropertiesPanelModelType::TYPE_STRING_TUNINGS },
     138              :     { mu::engraving::ElementType::SYMBOL, PropertiesPanelModelType::TYPE_SYMBOL },
     139              :     { mu::engraving::ElementType::SYSTEM_DIVIDER, PropertiesPanelModelType::TYPE_SYMBOL },
     140              :     { mu::engraving::ElementType::CHORD_BRACKET, PropertiesPanelModelType::TYPE_CHORD_BRACKET },
     141              : };
     142              : 
     143              : static const QMap<mu::engraving::HairpinType, PropertiesPanelModelType> HAIRPIN_ELEMENT_MODEL_TYPES = {
     144              :     { mu::engraving::HairpinType::CRESC_HAIRPIN, PropertiesPanelModelType::TYPE_HAIRPIN },
     145              :     { mu::engraving::HairpinType::DIM_HAIRPIN, PropertiesPanelModelType::TYPE_HAIRPIN },
     146              :     { mu::engraving::HairpinType::CRESC_LINE, PropertiesPanelModelType::TYPE_CRESCENDO },
     147              :     { mu::engraving::HairpinType::DIM_LINE, PropertiesPanelModelType::TYPE_DIMINUENDO },
     148              : };
     149              : 
     150              : static const QMap<mu::engraving::LayoutBreakType, PropertiesPanelModelType> LAYOUT_BREAK_ELEMENT_MODEL_TYPES = {
     151              :     { mu::engraving::LayoutBreakType::SECTION, PropertiesPanelModelType::TYPE_SECTIONBREAK }
     152              : };
     153              : 
     154              : static const QMap<mu::engraving::TempoTextType, PropertiesPanelModelType> TEMPO_TEXT_ELEMENT_MODEL_TYPES = {
     155              :     { mu::engraving::TempoTextType::NORMAL, PropertiesPanelModelType::TYPE_TEMPO },
     156              :     { mu::engraving::TempoTextType::A_TEMPO, PropertiesPanelModelType::TYPE_A_TEMPO },
     157              :     { mu::engraving::TempoTextType::TEMPO_PRIMO, PropertiesPanelModelType::TYPE_TEMPO_PRIMO },
     158              : };
     159              : 
     160            0 : QString PropertiesPanelAbstractModel::shortcutsForCommand(const muse::rcommand::Command& command) const
     161              : {
     162            0 :     std::vector<std::string> shortcuts = commandShortcutsRegister()->shortcut(command).sequences;
     163            0 :     return muse::shortcuts::sequencesToNativeText(shortcuts);
     164            0 : }
     165              : 
     166            0 : PropertiesPanelAbstractModel::PropertiesPanelAbstractModel(QObject* parent, const muse::modularity::ContextPtr& iocCtx,
     167              :                                                            IElementRepositoryService* repository,
     168            0 :                                                            mu::engraving::ElementType elementType)
     169            0 :     : QObject(parent), muse::Contextable(iocCtx), m_repository(repository), m_elementType(elementType)
     170              : {
     171            0 :     if (!m_repository) {
     172            0 :         return;
     173              :     }
     174              : 
     175            0 :     m_repository->elementsUpdated().onReceive(this, [this](const QList<mu::engraving::EngravingItem*>&) {
     176            0 :         updateProperties();
     177            0 :     });
     178              : 
     179            0 :     connect(this, &PropertiesPanelAbstractModel::requestReloadPropertyItems, this, &PropertiesPanelAbstractModel::updateProperties);
     180            0 : }
     181              : 
     182            0 : void PropertiesPanelAbstractModel::init()
     183              : {
     184            0 :     onCurrentNotationChanged();
     185            0 : }
     186              : 
     187            0 : bool PropertiesPanelAbstractModel::isSystemObjectBelowBottomStaff() const
     188              : {
     189            0 :     return m_isSystemObjectBelowBottomStaff;
     190              : }
     191              : 
     192            0 : MeasurementUnits PropertiesPanelAbstractModel::measurementUnits() const
     193              : {
     194            0 :     return m_measurementUnits;
     195              : }
     196              : 
     197            0 : bool PropertiesPanelAbstractModel::shouldUpdateOnScoreChange() const
     198              : {
     199            0 :     return m_shouldUpdateOnScoreChange;
     200              : }
     201              : 
     202            0 : bool PropertiesPanelAbstractModel::shouldUpdateWhenEmpty() const
     203              : {
     204            0 :     return false;
     205              : }
     206              : 
     207            0 : bool PropertiesPanelAbstractModel::shouldUpdateOnEmptyPropertyAndStyleIdSets() const
     208              : {
     209            0 :     return false;
     210              : }
     211              : 
     212            0 : void PropertiesPanelAbstractModel::updateIsSystemObjectBelowBottomStaff()
     213              : {
     214            0 :     bool soBelowBottomStaff = false;
     215            0 :     for (EngravingItem* item : m_elementList) {
     216            0 :         if (item->isSystemObjectBelowBottomStaff()) {
     217            0 :             soBelowBottomStaff = true;
     218            0 :             break;
     219              :         }
     220              :     }
     221              : 
     222            0 :     if (m_isSystemObjectBelowBottomStaff != soBelowBottomStaff) {
     223            0 :         m_isSystemObjectBelowBottomStaff = soBelowBottomStaff;
     224            0 :         emit isSystemObjectBelowBottomStaffChanged(m_isSystemObjectBelowBottomStaff);
     225              :     }
     226            0 : }
     227              : 
     228            0 : void PropertiesPanelAbstractModel::updatemeasurementUnits()
     229              : {
     230            0 :     MeasurementUnits result = MeasurementUnits::UNITS_UNKNOWN;
     231              : 
     232            0 :     for (EngravingItem* item : m_elementList) {
     233            0 :         MeasurementUnits itemUnits = item->offsetIsSpatiumDependent() ? MeasurementUnits::UNITS_SPATIUM : MeasurementUnits::UNITS_MM;
     234            0 :         if (result != MeasurementUnits::UNITS_UNKNOWN && itemUnits != result) {
     235            0 :             result = MeasurementUnits::UNITS_UNKNOWN;
     236            0 :             break;
     237              :         } else {
     238            0 :             result = itemUnits;
     239              :         }
     240              :     }
     241              : 
     242            0 :     if (m_measurementUnits != result) {
     243            0 :         m_measurementUnits = result;
     244            0 :         emit measurementUnitsChanged(m_measurementUnits);
     245              :     }
     246            0 : }
     247              : 
     248            0 : QString PropertiesPanelAbstractModel::title() const
     249              : {
     250            0 :     return m_title;
     251              : }
     252              : 
     253            0 : int PropertiesPanelAbstractModel::icon() const
     254              : {
     255            0 :     return static_cast<int>(m_icon);
     256              : }
     257              : 
     258            0 : PropertiesPanelSectionType PropertiesPanelAbstractModel::sectionType() const
     259              : {
     260            0 :     return m_sectionType;
     261              : }
     262              : 
     263            0 : PropertiesPanelModelType PropertiesPanelAbstractModel::modelType() const
     264              : {
     265            0 :     return m_modelType;
     266              : }
     267              : 
     268            0 : ElementKey PropertiesPanelAbstractModel::makeKey(const EngravingItem* item)
     269              : {
     270            0 :     switch (item->type()) {
     271            0 :     case ElementType::TEMPO_TEXT: {
     272            0 :         const auto tempoText = toTempoText(item);
     273            0 :         return ElementKey{ ElementType::TEMPO_TEXT, static_cast<int>(tempoText->tempoTextType()) };
     274              :     }
     275            0 :     default:
     276            0 :         return ElementKey{ item->type(), item->subtype() };
     277              :     }
     278              : }
     279              : 
     280            0 : PropertiesPanelModelType PropertiesPanelAbstractModel::modelTypeByElementKey(const ElementKey& elementKey)
     281              : {
     282            0 :     if (elementKey.type == mu::engraving::ElementType::HAIRPIN || elementKey.type == mu::engraving::ElementType::HAIRPIN_SEGMENT) {
     283            0 :         return HAIRPIN_ELEMENT_MODEL_TYPES.value(static_cast<mu::engraving::HairpinType>(elementKey.subtype),
     284            0 :                                                  PropertiesPanelModelType::TYPE_UNDEFINED);
     285              :     }
     286              : 
     287            0 :     if (elementKey.type == mu::engraving::ElementType::LAYOUT_BREAK) {
     288            0 :         return LAYOUT_BREAK_ELEMENT_MODEL_TYPES.value(static_cast<mu::engraving::LayoutBreakType>(elementKey.subtype),
     289            0 :                                                       PropertiesPanelModelType::TYPE_UNDEFINED);
     290              :     }
     291              : 
     292            0 :     if (elementKey.type == mu::engraving::ElementType::TEMPO_TEXT) {
     293            0 :         return TEMPO_TEXT_ELEMENT_MODEL_TYPES.value(static_cast<mu::engraving::TempoTextType>(elementKey.subtype),
     294            0 :                                                     PropertiesPanelModelType::TYPE_UNDEFINED);
     295              :     }
     296              : 
     297            0 :     return NOTATION_ELEMENT_MODEL_TYPES.value(elementKey.type, PropertiesPanelModelType::TYPE_UNDEFINED);
     298              : }
     299              : 
     300            0 : PropertiesPanelModelTypeSet PropertiesPanelAbstractModel::modelTypesByElementKeys(const ElementKeySet& elementKeySet)
     301              : {
     302            0 :     PropertiesPanelModelTypeSet types;
     303              : 
     304            0 :     for (const ElementKey& key : elementKeySet) {
     305            0 :         types << modelTypeByElementKey(key);
     306              :     }
     307              : 
     308            0 :     return types;
     309            0 : }
     310              : 
     311            0 : static bool isPureDynamics(const QList<mu::engraving::EngravingItem*>& selectedElementList)
     312              : {
     313            0 :     if (selectedElementList.empty()) {
     314            0 :         return false;
     315              :     }
     316              : 
     317            0 :     for (const EngravingItem* item : selectedElementList) {
     318            0 :         if (!item->isTextBase()) {
     319            0 :             continue;
     320              :         }
     321              : 
     322            0 :         if (!item->isDynamic()) {
     323            0 :             return false;
     324              :         }
     325              : 
     326            0 :         const Dynamic* dynamic = toDynamic(item);
     327            0 :         if (dynamic->hasCustomText()) {
     328            0 :             return false;
     329              :         }
     330              :     }
     331              : 
     332            0 :     return true;
     333              : }
     334              : 
     335            0 : static bool barlineWithPlayText(const QList<mu::engraving::EngravingItem*>& selectedElementList)
     336              : {
     337            0 :     if (selectedElementList.empty()) {
     338            0 :         return false;
     339              :     }
     340              : 
     341            0 :     for (const EngravingItem* item : selectedElementList) {
     342            0 :         if (!item->isBarLine()) {
     343            0 :             continue;
     344              :         }
     345              : 
     346            0 :         Segment* seg = toBarLine(item)->segment();
     347            0 :         PlayCountText* playCountText = toPlayCountText(seg->findAnnotation(ElementType::PLAY_COUNT_TEXT, 0, 0));
     348              : 
     349            0 :         if (playCountText) {
     350            0 :             return true;
     351              :         }
     352              :     }
     353              : 
     354            0 :     return false;
     355              : }
     356              : 
     357            0 : static bool hasValidTextLineBaseSegment(const QList<mu::engraving::EngravingItem*>& elementList)
     358              : {
     359            0 :     if (elementList.empty()) {
     360            0 :         return false;
     361              :     }
     362              : 
     363            0 :     for (const EngravingItem* item : elementList) {
     364            0 :         if (!item->isTextLineBaseSegment()) {
     365            0 :             continue;
     366              :         }
     367            0 :         const TextLineBaseSegment* tlbs = toTextLineBaseSegment(item);
     368            0 :         const TextLineBase* tlb = tlbs ? tlbs->textLineBase() : nullptr;
     369            0 :         if (!tlb) {
     370            0 :             continue;
     371              :         }
     372            0 :         if (!tlb->beginText().empty() || !tlb->continueText().empty() || !tlb->endText().empty()) {
     373            0 :             return true;
     374              :         }
     375              :     }
     376              : 
     377            0 :     return false;
     378              : }
     379              : 
     380            0 : PropertiesPanelSectionTypeSet PropertiesPanelAbstractModel::sectionTypesByElementKeys(const ElementKeySet& elementKeySet, bool isRange,
     381              :                                                                                       const QList<mu::engraving::EngravingItem*>& elementList)
     382              : {
     383            0 :     PropertiesPanelSectionTypeSet types;
     384              : 
     385              :     static const std::unordered_set<ElementType> boxTypes {
     386              :         ElementType::HBOX,
     387              :         ElementType::VBOX,
     388              :         ElementType::TBOX,
     389              :         ElementType::FBOX,
     390            0 :     };
     391              : 
     392            0 :     for (const ElementKey& key : elementKeySet) {
     393            0 :         if (NOTATION_ELEMENT_MODEL_TYPES.contains(key.type)
     394            0 :             && (modelTypeByElementKey(key) != PropertiesPanelModelType::TYPE_UNDEFINED)) {
     395            0 :             types << PropertiesPanelSectionType::SECTION_NOTATION;
     396              :         }
     397              : 
     398              :         // Don't show the "Text" propertiespanel panel for "pure" dynamics (i.e. without custom text)
     399            0 :         if ((TEXT_ELEMENT_TYPES.contains(key.type) && !isPureDynamics(elementList)) || barlineWithPlayText(elementList)) {
     400            0 :             types << PropertiesPanelSectionType::SECTION_TEXT;
     401              :         }
     402              : 
     403              :         // Look for a TextLineBaseSegment with begin, continue, or end text...
     404            0 :         if (hasValidTextLineBaseSegment(elementList)) {
     405            0 :             types << PropertiesPanelSectionType::SECTION_TEXT;
     406              :         }
     407              : 
     408            0 :         if (key.type != mu::engraving::ElementType::INSTRUMENT_NAME) {
     409            0 :             types << PropertiesPanelSectionType::SECTION_GENERAL;
     410              :         }
     411              : 
     412            0 :         if (boxTypes.contains(key.type)) {
     413            0 :             types << PropertiesPanelSectionType::SECTION_SYSTEM_PAGE_LAYOUT;
     414              :         }
     415              :     }
     416              : 
     417            0 :     if (isRange) {
     418            0 :         const bool rangeHasNonBoxes = std::any_of(elementList.cbegin(), elementList.cend(), [](const EngravingItem* item) {
     419            0 :             return !item->isBox();
     420              :         });
     421            0 :         if (rangeHasNonBoxes) {
     422            0 :             types << PropertiesPanelSectionType::SECTION_MEASURES;
     423            0 :             types << PropertiesPanelSectionType::SECTION_SYSTEM_PAGE_LAYOUT;
     424            0 :             types << PropertiesPanelSectionType::SECTION_EMPTY_STAVES;
     425              :         }
     426              :     }
     427              : 
     428            0 :     if (showPartsSection(elementList)) {
     429            0 :         types << PropertiesPanelSectionType::SECTION_PARTS;
     430              :     }
     431              : 
     432            0 :     return types;
     433            0 : }
     434              : 
     435            0 : bool PropertiesPanelAbstractModel::showPartsSection(const QList<EngravingItem*>& elementList)
     436              : {
     437              :     static const std::unordered_set<ElementType> noAvailableChangePartsSettingsTypes {
     438              :         ElementType::LAYOUT_BREAK,
     439              :         ElementType::ACCIDENTAL,
     440              :         ElementType::SOUND_FLAG
     441            0 :     };
     442              : 
     443            0 :     for (EngravingItem* element : elementList) {
     444            0 :         if ((!element->score()->isMaster() && !muse::contains(noAvailableChangePartsSettingsTypes, element->type()))
     445            0 :             || element->canBeExcludedFromOtherParts()) {
     446            0 :             return true;
     447              :         }
     448              :     }
     449              : 
     450            0 :     return false;
     451              : }
     452              : 
     453            0 : bool PropertiesPanelAbstractModel::isEmpty() const
     454              : {
     455            0 :     return m_elementList.isEmpty();
     456              : }
     457              : 
     458            0 : void PropertiesPanelAbstractModel::setTitle(QString title)
     459              : {
     460            0 :     if (m_title == title) {
     461            0 :         return;
     462              :     }
     463              : 
     464            0 :     m_title = title;
     465            0 :     emit titleChanged();
     466              : }
     467              : 
     468            0 : void PropertiesPanelAbstractModel::setIcon(muse::ui::IconCode::Code icon)
     469              : {
     470            0 :     m_icon = icon;
     471            0 : }
     472              : 
     473            0 : void PropertiesPanelAbstractModel::setSectionType(PropertiesPanelSectionType sectionType)
     474              : {
     475            0 :     m_sectionType = sectionType;
     476            0 : }
     477              : 
     478            0 : void PropertiesPanelAbstractModel::setModelType(PropertiesPanelModelType modelType)
     479              : {
     480            0 :     m_modelType = modelType;
     481            0 : }
     482              : 
     483            0 : void PropertiesPanelAbstractModel::onPropertyValueChanged(const mu::engraving::Pid pid, const QVariant& newValue)
     484              : {
     485            0 :     setPropertyValue(m_elementList, pid, newValue);
     486            0 :     loadProperties();
     487            0 : }
     488              : 
     489            0 : void PropertiesPanelAbstractModel::setPropertyValue(const QList<engraving::EngravingItem*>& items, const mu::engraving::Pid pid,
     490              :                                                     const QVariant& newValue)
     491              : {
     492            0 :     if (items.empty()) {
     493            0 :         return;
     494              :     }
     495              : 
     496            0 :     beginCommand(TranslatableString("undoableAction", "Edit %1").arg(propertyUserName(pid)));
     497              : 
     498            0 :     for (mu::engraving::EngravingItem* item : items) {
     499            0 :         IF_ASSERT_FAILED(item) {
     500            0 :             continue;
     501              :         }
     502              : 
     503            0 :         mu::engraving::PropertyFlags ps = item->propertyFlags(pid);
     504              : 
     505            0 :         if (ps == mu::engraving::PropertyFlags::STYLED) {
     506            0 :             ps = mu::engraving::PropertyFlags::UNSTYLED;
     507              :         }
     508              : 
     509            0 :         PropertyValue propValue = valueToElementUnits(pid, newValue, item);
     510            0 :         item->undoChangeProperty(pid, propValue, ps);
     511            0 :     }
     512              : 
     513            0 :     updateNotation();
     514            0 :     endCommand();
     515              : }
     516              : 
     517            0 : void PropertiesPanelAbstractModel::onPropertyValueReset(const mu::engraving::Pid pid)
     518              : {
     519            0 :     resetPropertyValue(m_elementList, pid);
     520            0 :     loadProperties();
     521            0 : }
     522              : 
     523            0 : void PropertiesPanelAbstractModel::resetPropertyValue(const QList<engraving::EngravingItem*>& items, const mu::engraving::Pid pid)
     524              : {
     525            0 :     if (items.empty()) {
     526            0 :         return;
     527              :     }
     528              : 
     529            0 :     beginCommand(TranslatableString("undoableAction", "Reset %1").arg(propertyUserName(pid)));
     530              : 
     531            0 :     for (mu::engraving::EngravingItem* item : items) {
     532            0 :         IF_ASSERT_FAILED(item) {
     533            0 :             continue;
     534              :         }
     535              : 
     536            0 :         item->undoResetProperty(pid);
     537              :     }
     538              : 
     539            0 :     updateNotation();
     540            0 :     endCommand();
     541              : }
     542              : 
     543            0 : void PropertiesPanelAbstractModel::updateProperties()
     544              : {
     545            0 :     requestElements();
     546              : 
     547            0 :     emit isEmptyChanged();
     548              : 
     549            0 :     if (!isEmpty()) {
     550            0 :         loadProperties();
     551              :     }
     552            0 : }
     553              : 
     554            0 : void PropertiesPanelAbstractModel::requestElements()
     555              : {
     556            0 :     if (m_elementType != mu::engraving::ElementType::INVALID) {
     557            0 :         m_elementList = m_repository->findElementsByType(m_elementType);
     558              :     }
     559            0 : }
     560              : 
     561            0 : void PropertiesPanelAbstractModel::disconnectAll()
     562              : {
     563            0 :     async_disconnectAll();
     564            0 : }
     565              : 
     566            0 : void PropertiesPanelAbstractModel::onCurrentNotationChanged()
     567              : {
     568            0 : }
     569              : 
     570            0 : void PropertiesPanelAbstractModel::onNotationChanged(const mu::engraving::PropertyIdSet&, const mu::engraving::StyleIdSet&)
     571              : {
     572            0 : }
     573              : 
     574            0 : mu::engraving::Sid PropertiesPanelAbstractModel::styleIdByPropertyId(const mu::engraving::Pid pid) const
     575              : {
     576            0 :     mu::engraving::Sid result = mu::engraving::Sid::NOSTYLE;
     577              : 
     578            0 :     for (const mu::engraving::EngravingItem* element : m_elementList) {
     579            0 :         result = element->getPropertyStyle(pid);
     580              : 
     581            0 :         if (result != mu::engraving::Sid::NOSTYLE) {
     582            0 :             break;
     583              :         }
     584              :     }
     585              : 
     586            0 :     return result;
     587              : }
     588              : 
     589            0 : mu::engraving::PropertyIdSet PropertiesPanelAbstractModel::propertyIdSetFromStyleIdSet(const StyleIdSet& styleIdSet) const
     590              : {
     591            0 :     if (styleIdSet.empty()) {
     592            0 :         return PropertyIdSet();
     593              :     }
     594              : 
     595            0 :     PropertyIdSet result;
     596              : 
     597            0 :     for (const mu::engraving::EngravingItem* element : m_elementList) {
     598            0 :         const mu::engraving::ElementStyle* style = element->styledProperties();
     599            0 :         if (!style) {
     600            0 :             continue;
     601              :         }
     602              : 
     603            0 :         for (const StyledProperty& property : *style) {
     604            0 :             if (muse::contains(styleIdSet, property.sid)) {
     605            0 :                 result.insert(property.pid);
     606              :             }
     607              :         }
     608              :     }
     609              : 
     610            0 :     return result;
     611            0 : }
     612              : 
     613            0 : bool PropertiesPanelAbstractModel::updateStyleValue(const mu::engraving::Sid& sid, const QVariant& newValue)
     614              : {
     615            0 :     PropertyValue newVal = PropertyValue::fromQVariant(newValue, mu::engraving::MStyle::valueType(sid));
     616            0 :     if (style() && style()->styleValue(sid) != newVal) {
     617            0 :         beginCommand(TranslatableString("undoableAction", "Edit style"));
     618            0 :         style()->setStyleValue(sid, newVal);
     619            0 :         endCommand();
     620            0 :         return true;
     621              :     }
     622              : 
     623            0 :     return false;
     624            0 : }
     625              : 
     626            0 : QVariant PropertiesPanelAbstractModel::styleValue(const mu::engraving::Sid& sid) const
     627              : {
     628            0 :     return style() ? style()->styleValue(sid).toQVariant() : QVariant();
     629              : }
     630              : 
     631            0 : PropertyValue PropertiesPanelAbstractModel::valueToElementUnits(const mu::engraving::Pid& pid, const QVariant& value,
     632              :                                                                 const mu::engraving::EngravingItem* element) const
     633              : {
     634            0 :     if (mu::engraving::Pid::VERSE == pid) {
     635            0 :         return value.toInt() - 1;
     636              :     }
     637              : 
     638            0 :     auto toPoint = [](const QVariant& v) {
     639            0 :         return PointF::fromQPointF(v.value<QPointF>());
     640              :     };
     641              : 
     642            0 :     P_TYPE type = mu::engraving::propertyType(pid);
     643            0 :     switch (type) {
     644            0 :     case P_TYPE::POINT: {
     645            0 :         PointF point = toPoint(value);
     646            0 :         if (pid == Pid::OFFSET) {
     647              :             // Displayed: positive = up, negative = down
     648              :             // Internal:  negative = up, positive = down
     649            0 :             point = OffsetUtils::flipYSign(point);
     650              :         }
     651              : 
     652            0 :         if (pid == Pid::OFFSET ? element->offsetIsSpatiumDependent() : element->sizeIsSpatiumDependent()) {
     653            0 :             return point * element->spatium();
     654              :         } else {
     655            0 :             return point * mu::engraving::DPMM;
     656              :         }
     657              :     }
     658              : 
     659            0 :     case P_TYPE::ABSOLUTE:
     660            0 :         return element->absoluteFromSpatium(Spatium(value.toReal()));
     661              : 
     662            0 :     case P_TYPE::SPATIUM:
     663            0 :         return Spatium(value.toReal());
     664              : 
     665            0 :     case P_TYPE::TEMPO:
     666            0 :         return BeatsPerSecond::fromBPM(BeatsPerMinute(value.toReal()));
     667              : 
     668            0 :     case P_TYPE::INT_VEC: {
     669            0 :         bool ok = true;
     670            0 :         std::vector<int> res;
     671              : 
     672            0 :         for (const QString& str : value.toString().split(',', Qt::SkipEmptyParts)) {
     673            0 :             if (int i = str.simplified().toInt(&ok); ok) {
     674            0 :                 res.push_back(i);
     675              :             }
     676            0 :         }
     677              : 
     678            0 :         return res;
     679            0 :     } break;
     680              : 
     681            0 :     case P_TYPE::COLOR:
     682            0 :         return Color::fromQColor(value.value<QColor>());
     683              : 
     684            0 :     default:
     685            0 :         return PropertyValue::fromQVariant(value, type);
     686              :     }
     687              : }
     688              : 
     689            0 : QVariant PropertiesPanelAbstractModel::valueFromElementUnits(const mu::engraving::Pid& pid, const PropertyValue& value,
     690              :                                                              const mu::engraving::EngravingItem* element) const
     691              : {
     692            0 :     if (mu::engraving::Pid::VERSE == pid) {
     693            0 :         return value.toInt() + 1;
     694              :     }
     695              : 
     696            0 :     switch (value.type()) {
     697            0 :     case P_TYPE::POINT: {
     698            0 :         PointF point = value.value<PointF>();
     699            0 :         if (pid == Pid::OFFSET ? element->offsetIsSpatiumDependent() : element->sizeIsSpatiumDependent()) {
     700            0 :             point = point / element->spatium();
     701              :         } else {
     702            0 :             point = point / mu::engraving::DPMM;
     703              :         }
     704              : 
     705            0 :         if (pid == Pid::OFFSET) {
     706              :             // Displayed: positive = up, negative = down
     707              :             // Internal:  negative = up, positive = down
     708            0 :             point = OffsetUtils::flipYSign(point);
     709              :         }
     710              : 
     711            0 :         return point.toQPointF();
     712              :     }
     713              : 
     714            0 :     case P_TYPE::ABSOLUTE:
     715            0 :         return Spatium::fromAbsolute(value.toReal(), element->spatium()).val();
     716              : 
     717            0 :     case P_TYPE::SPATIUM:
     718            0 :         return value.value<Spatium>().val();
     719              : 
     720            0 :     case P_TYPE::TEMPO:
     721            0 :         return value.value<BeatsPerSecond>().toBPM().val;
     722              : 
     723            0 :     case P_TYPE::DIRECTION_V:
     724            0 :         return static_cast<int>(value.value<mu::engraving::DirectionV>());
     725              : 
     726            0 :     case P_TYPE::INT_VEC: {
     727            0 :         QStringList strList;
     728              : 
     729            0 :         for (const int i : value.value<std::vector<int> >()) {
     730            0 :             strList << QString::number(i);
     731            0 :         }
     732              : 
     733            0 :         return strList.join(",");
     734            0 :     }
     735            0 :     case P_TYPE::COLOR:
     736            0 :         return value.value<muse::draw::Color>().toQColor();
     737            0 :     default:
     738            0 :         return value.toQVariant();
     739              :     }
     740              : }
     741              : 
     742            0 : void PropertiesPanelAbstractModel::setElementType(mu::engraving::ElementType type)
     743              : {
     744            0 :     m_elementType = type;
     745            0 : }
     746              : 
     747            0 : PropertyItem* PropertiesPanelAbstractModel::buildPropertyItem(const mu::engraving::Pid& propertyId,
     748              :                                                               std::function<void(const mu::engraving::Pid propertyId,
     749              :                                                                                  const QVariant& newValue)> onPropertyChangedCallBack,
     750              :                                                               std::function<void(const mu::engraving::Sid styleId,
     751              :                                                                                  const QVariant& newValue)> onStyleChangedCallBack,
     752              :                                                               std::function<void(const mu::engraving::Pid propertyId)>
     753              :                                                               onPropertyResetCallBack)
     754              : {
     755            0 :     PropertyItem* newPropertyItem = new PropertyItem(propertyId, this);
     756              : 
     757            0 :     initPropertyItem(newPropertyItem, onPropertyChangedCallBack, onStyleChangedCallBack, onPropertyResetCallBack);
     758              : 
     759            0 :     return newPropertyItem;
     760              : }
     761              : 
     762            0 : PointFPropertyItem* PropertiesPanelAbstractModel::buildPointFPropertyItem(const mu::engraving::Pid& propertyId,
     763              :                                                                           std::function<void(const mu::engraving::Pid propertyId,
     764              :                                                                                              const QVariant& newValue)>
     765              :                                                                           onPropertyChangedCallBack,
     766              :                                                                           std::function<void(const mu::engraving::Pid propertyId)>
     767              :                                                                           onPropertyResetCallBack)
     768              : {
     769            0 :     PointFPropertyItem* newPropertyItem = new PointFPropertyItem(propertyId, this);
     770              : 
     771            0 :     initPropertyItem(newPropertyItem, onPropertyChangedCallBack, nullptr, onPropertyResetCallBack);
     772              : 
     773            0 :     return newPropertyItem;
     774              : }
     775              : 
     776            0 : void PropertiesPanelAbstractModel::initPropertyItem(PropertyItem* propertyItem,
     777              :                                                     std::function<void(const mu::engraving::Pid propertyId,
     778              :                                                                        const QVariant& newValue)> onPropertyChangedCallBack,
     779              :                                                     std::function<void(const mu::engraving::Sid styleId,
     780              :                                                                        const QVariant& newValue)> onStyleChangedCallBack,
     781              :                                                     std::function<void(const mu::engraving::Pid propertyId)> onPropertyResetCallBack)
     782              : {
     783            0 :     auto propertyCallback = onPropertyChangedCallBack;
     784            0 :     if (!propertyCallback) {
     785            0 :         propertyCallback = [this](const mu::engraving::Pid propertyId, const QVariant& newValue) {
     786            0 :             onPropertyValueChanged(propertyId, newValue);
     787            0 :         };
     788              :     }
     789              : 
     790            0 :     auto styleCallback = onStyleChangedCallBack;
     791            0 :     if (!styleCallback) {
     792            0 :         styleCallback = [this](const mu::engraving::Sid styleId, const QVariant& newValue) {
     793            0 :             updateStyleValue(styleId, newValue);
     794              : 
     795            0 :             emit requestReloadPropertyItems();
     796            0 :         };
     797              :     }
     798              : 
     799            0 :     auto resetCallback = onPropertyResetCallBack;
     800            0 :     if (!resetCallback) {
     801            0 :         resetCallback = [this](const mu::engraving::Pid propertyId) {
     802            0 :             onPropertyValueReset(propertyId);
     803            0 :         };
     804              :     }
     805              : 
     806            0 :     connect(propertyItem, &PropertyItem::propertyModified, this, propertyCallback);
     807            0 :     connect(propertyItem, &PropertyItem::resetToDefaultRequested, this, resetCallback);
     808            0 :     connect(propertyItem, &PropertyItem::applyToStyleRequested, this, styleCallback);
     809            0 : }
     810              : 
     811            0 : void PropertiesPanelAbstractModel::loadPropertyItem(PropertyItem* propertyItem, ConvertPropertyValueFunc convertElementPropertyValueFunc)
     812              : {
     813            0 :     loadPropertyItem(propertyItem, m_elementList, convertElementPropertyValueFunc);
     814            0 : }
     815              : 
     816            0 : void PropertiesPanelAbstractModel::loadPropertyItem(PropertyItem* propertyItem, const QList<EngravingItem*>& elements,
     817              :                                                     ConvertPropertyValueFunc convertElementPropertyValueFunc)
     818              : {
     819            0 :     if (!propertyItem) {
     820            0 :         return;
     821              :     }
     822              : 
     823            0 :     if (elements.isEmpty()) {
     824            0 :         propertyItem->setIsEnabled(false);
     825            0 :         return;
     826              :     }
     827              : 
     828            0 :     mu::engraving::Pid pid = propertyItem->propertyId();
     829              : 
     830            0 :     mu::engraving::Sid styleId = styleIdByPropertyId(pid);
     831            0 :     propertyItem->setStyleId(styleId);
     832              : 
     833            0 :     QVariant propertyValue;
     834              : 
     835            0 :     bool isUndefined = false;
     836            0 :     bool isModified = false;
     837              : 
     838            0 :     for (const mu::engraving::EngravingItem* element : elements) {
     839            0 :         IF_ASSERT_FAILED(element) {
     840            0 :             continue;
     841              :         }
     842              : 
     843            0 :         QVariant elementCurrentValue = valueFromElementUnits(pid, element->getProperty(pid), element);
     844            0 :         QVariant elementDefaultValue = valueFromElementUnits(pid, element->propertyDefault(pid), element);
     845              : 
     846            0 :         bool isPropertySupportedByElement = elementCurrentValue.isValid();
     847              : 
     848            0 :         if (!isPropertySupportedByElement) {
     849            0 :             continue;
     850              :         }
     851              : 
     852            0 :         if (convertElementPropertyValueFunc) {
     853            0 :             elementCurrentValue = convertElementPropertyValueFunc(elementCurrentValue);
     854            0 :             elementDefaultValue = convertElementPropertyValueFunc(elementDefaultValue);
     855              :         }
     856              : 
     857            0 :         if (!propertyValue.isValid()) {
     858            0 :             propertyValue = elementCurrentValue;
     859              :         }
     860              : 
     861            0 :         if (!isUndefined && propertyValue != elementCurrentValue) {
     862            0 :             isUndefined = true;
     863              :         }
     864              : 
     865            0 :         if (!isModified) {
     866            0 :             PropertyFlags f = element->propertyFlags(pid);
     867            0 :             if (f == PropertyFlags::UNSTYLED || elementCurrentValue != elementDefaultValue) {
     868            0 :                 isModified = true;
     869              :             }
     870              :         }
     871              : 
     872            0 :         if (isUndefined && isModified) {
     873            0 :             break;
     874              :         }
     875            0 :     }
     876              : 
     877              :     //@note Some elements may support the property, some don't. If element doesn't support property it'll return invalid value.
     878              :     //      So we use that knowledge here
     879            0 :     propertyItem->setIsEnabled(propertyValue.isValid());
     880              : 
     881            0 :     if (isUndefined) {
     882            0 :         propertyValue = QVariant();
     883              :     }
     884              : 
     885            0 :     propertyItem->updateCurrentValue(propertyValue);
     886            0 :     propertyItem->setIsModified(isModified);
     887            0 : }
     888              : 
     889            0 : bool PropertiesPanelAbstractModel::isNotationExisting() const
     890              : {
     891            0 :     return context()->project() != nullptr;
     892              : }
     893              : 
     894            0 : INotationStylePtr PropertiesPanelAbstractModel::style() const
     895              : {
     896            0 :     return currentNotation() ? currentNotation()->style() : nullptr;
     897              : }
     898              : 
     899            0 : INotationUndoStackPtr PropertiesPanelAbstractModel::undoStack() const
     900              : {
     901            0 :     return currentNotation() ? currentNotation()->undoStack() : nullptr;
     902              : }
     903              : 
     904            0 : void PropertiesPanelAbstractModel::beginCommand(const muse::TranslatableString& actionName)
     905              : {
     906            0 :     if (undoStack()) {
     907            0 :         undoStack()->prepareChanges(actionName);
     908              :     }
     909              : 
     910              :     //! NOTE prevents unnecessary updating of properties
     911              :     //! after changing their values in the propertiespanel
     912            0 :     m_shouldUpdateOnScoreChange = false;
     913            0 : }
     914              : 
     915            0 : void PropertiesPanelAbstractModel::endCommand()
     916              : {
     917            0 :     if (undoStack()) {
     918            0 :         undoStack()->commitChanges();
     919              :     }
     920              : 
     921            0 :     m_shouldUpdateOnScoreChange = true;
     922            0 : }
     923              : 
     924            0 : INotationPtr PropertiesPanelAbstractModel::currentNotation() const
     925              : {
     926            0 :     return context()->currentNotation();
     927              : }
     928              : 
     929            0 : bool PropertiesPanelAbstractModel::isMasterNotation() const
     930              : {
     931            0 :     INotationPtr notation = currentNotation();
     932            0 :     if (!notation) {
     933            0 :         return false;
     934              :     }
     935              : 
     936            0 :     return notation->isMaster();
     937            0 : }
     938              : 
     939            0 : INotationSelectionPtr PropertiesPanelAbstractModel::selection() const
     940              : {
     941            0 :     INotationPtr notation = currentNotation();
     942            0 :     return notation ? notation->interaction()->selection() : nullptr;
     943            0 : }
     944              : 
     945            0 : void PropertiesPanelAbstractModel::updateNotation()
     946              : {
     947            0 :     if (!currentNotation()) {
     948            0 :         return;
     949              :     }
     950              : 
     951            0 :     currentNotation()->notationChanged().send(muse::RectF());
     952              : }
        

Generated by: LCOV version 2.0-1