LCOV - code coverage report
Current view: top level - src/propertiespanel/internal - elementrepositoryservice.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 237 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              : #include "elementrepositoryservice.h"
      23              : 
      24              : #include "qml/MuseScore/PropertiesPanel/types/texttypes.h"
      25              : 
      26              : #include "engraving/dom/barline.h"
      27              : #include "engraving/dom/beam.h"
      28              : #include "engraving/dom/bracket.h"
      29              : #include "engraving/dom/bracketitem.h"
      30              : #include "engraving/dom/chord.h"
      31              : #include "engraving/dom/durationtype.h"
      32              : #include "engraving/dom/glissando.h"
      33              : #include "engraving/dom/hairpin.h"
      34              : #include "engraving/dom/hook.h"
      35              : #include "engraving/dom/layoutbreak.h"
      36              : #include "engraving/dom/lyrics.h"
      37              : #include "engraving/dom/mscore.h"
      38              : #include "engraving/dom/note.h"
      39              : #include "engraving/dom/note.h"
      40              : #include "engraving/dom/pedal.h"
      41              : #include "engraving/dom/playcounttext.h"
      42              : #include "engraving/dom/segment.h"
      43              : #include "engraving/dom/staff.h"
      44              : #include "engraving/dom/stafftype.h"
      45              : #include "engraving/dom/stem.h"
      46              : #include "engraving/dom/text.h"
      47              : #include "engraving/dom/trill.h"
      48              : #include "engraving/dom/volta.h"
      49              : 
      50              : #include "log.h"
      51              : 
      52              : using namespace mu::propertiespanel;
      53              : using namespace mu::engraving;
      54              : 
      55            0 : bool ElementRepositoryService::needUpdateElementList(const QList<EngravingItem*>& newRawElementList,
      56              :                                                      SelState selectionState) const
      57              : {
      58            0 :     return m_rawElementList != newRawElementList || m_selectionState != selectionState;
      59              : }
      60              : 
      61            0 : void ElementRepositoryService::updateElementList(const QList<EngravingItem*>& newRawElementList,
      62              :                                                  SelState selectionState)
      63              : {
      64            0 :     if (!needUpdateElementList(newRawElementList, selectionState)) {
      65            0 :         return;
      66              :     }
      67              : 
      68            0 :     m_exposedElementList = exposeRawElements(newRawElementList);
      69            0 :     m_rawElementList = newRawElementList;
      70            0 :     m_selectionState = selectionState;
      71              : 
      72            0 :     m_elementsUpdated.send(m_rawElementList);
      73              : }
      74              : 
      75            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findElementsByType(const mu::engraving::ElementType elementType) const
      76              : {
      77            0 :     switch (elementType) {
      78            0 :     case mu::engraving::ElementType::CHORD: return findChords();
      79            0 :     case mu::engraving::ElementType::NOTE: return findNotes();
      80            0 :     case mu::engraving::ElementType::NOTEHEAD: return findNoteHeads();
      81            0 :     case mu::engraving::ElementType::STEM: return findStems();
      82            0 :     case mu::engraving::ElementType::HOOK: return findHooks();
      83            0 :     case mu::engraving::ElementType::BEAM: return findBeams();
      84            0 :     case mu::engraving::ElementType::STAFF: return findStaffs();
      85            0 :     case mu::engraving::ElementType::LAYOUT_BREAK: return findSectionBreaks(); //Page breaks and line breaks are of type LAYOUT_BREAK, but they don't appear in the propertiespanel for now.
      86            0 :     case mu::engraving::ElementType::TEXT: return findTexts();
      87            0 :     case mu::engraving::ElementType::BRACKET: return findBrackets();
      88            0 :     case mu::engraving::ElementType::REST: return findRests();
      89            0 :     case mu::engraving::ElementType::ORNAMENT: return findOrnaments();
      90            0 :     case mu::engraving::ElementType::LYRICS: return findLyrics();
      91            0 :     case mu::engraving::ElementType::PEDAL:
      92              :     case mu::engraving::ElementType::GLISSANDO:
      93              :     case mu::engraving::ElementType::VIBRATO:
      94              :     case mu::engraving::ElementType::HAIRPIN:
      95              :     case mu::engraving::ElementType::VOLTA:
      96              :     case mu::engraving::ElementType::LET_RING:
      97              :     case mu::engraving::ElementType::OTTAVA:
      98              :     case mu::engraving::ElementType::TEXTLINE:
      99              :     case mu::engraving::ElementType::TEXTLINE_BASE:
     100              :     case mu::engraving::ElementType::NOTELINE:
     101              :     case mu::engraving::ElementType::SLUR:
     102              :     case mu::engraving::ElementType::HAMMER_ON_PULL_OFF:
     103              :     case mu::engraving::ElementType::TIE:
     104              :     case mu::engraving::ElementType::LAISSEZ_VIB:
     105              :     case mu::engraving::ElementType::PARTIAL_TIE:
     106              :     case mu::engraving::ElementType::GRADUAL_TEMPO_CHANGE:
     107              :     case mu::engraving::ElementType::LYRICSLINE:
     108              :     case mu::engraving::ElementType::PARTIAL_LYRICSLINE:
     109              :     case mu::engraving::ElementType::WHAMMY_BAR:
     110              :     case mu::engraving::ElementType::PALM_MUTE:
     111            0 :         return findLines(elementType);
     112            0 :     default:
     113            0 :         QList<mu::engraving::EngravingItem*> resultList;
     114              : 
     115            0 :         for (mu::engraving::EngravingItem* element : m_exposedElementList) {
     116            0 :             if (element->type() == elementType) {
     117            0 :                 resultList << element;
     118              :             }
     119              :         }
     120              : 
     121            0 :         return resultList;
     122              :     }
     123              : }
     124              : 
     125            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findElementsByType(const mu::engraving::ElementType elementType,
     126              :                                                                                   std::function<bool(const mu::engraving::EngravingItem*)> filterFunc)
     127              : const
     128              : {
     129            0 :     QList<mu::engraving::EngravingItem*> resultList;
     130              : 
     131            0 :     QList<mu::engraving::EngravingItem*> unfilteredList = findElementsByType(elementType);
     132              : 
     133            0 :     for (mu::engraving::EngravingItem* element : unfilteredList) {
     134            0 :         if (filterFunc(element)) {
     135            0 :             resultList << element;
     136              :         }
     137              :     }
     138              : 
     139            0 :     return resultList;
     140            0 : }
     141              : 
     142            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::takeAllElements() const
     143              : {
     144            0 :     return m_exposedElementList;
     145              : }
     146              : 
     147            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::exposeRawElements(const QList<mu::engraving::EngravingItem*>& rawElementList)
     148              : const
     149              : {
     150            0 :     QList<mu::engraving::EngravingItem*> resultList;
     151              : 
     152            0 :     for (mu::engraving::EngravingItem* element : rawElementList) {
     153            0 :         mu::engraving::ElementType elementType = element->type();
     154              : 
     155              :         //! NOTE: instrument names can't survive the layout process,
     156              :         //! so we have to exclude them from the list to prevent
     157              :         //! crashes on invalid pointers in the propertiespanel
     158            0 :         if (elementType == mu::engraving::ElementType::INSTRUMENT_NAME) {
     159            0 :             continue;
     160              :         }
     161              : 
     162            0 :         if (elementType == mu::engraving::ElementType::BRACKET) {
     163            0 :             resultList << mu::engraving::toBracket(element)->bracketItem();
     164            0 :             continue;
     165              :         }
     166              : 
     167            0 :         resultList << element;
     168              :     }
     169              : 
     170            0 :     return resultList;
     171            0 : }
     172              : 
     173            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findChords() const
     174              : {
     175            0 :     QSet<mu::engraving::EngravingItem*> elements;
     176              : 
     177            0 :     for (mu::engraving::EngravingItem* element : m_exposedElementList) {
     178            0 :         if (element->type() == mu::engraving::ElementType::CHORD) {
     179            0 :             elements << element;
     180            0 :             continue;
     181              :         }
     182              : 
     183            0 :         if (element->type() == mu::engraving::ElementType::BEAM) {
     184            0 :             const mu::engraving::Beam* beam = mu::engraving::toBeam(element);
     185              : 
     186            0 :             for (mu::engraving::ChordRest* chordRest : beam->elements()) {
     187            0 :                 if (!chordRest->isChord()) {
     188            0 :                     continue;
     189              :                 }
     190            0 :                 elements << chordRest;
     191              :             }
     192            0 :             continue;
     193            0 :         }
     194              : 
     195            0 :         mu::engraving::EngravingItem* chord = element->findAncestor(mu::engraving::ElementType::CHORD);
     196            0 :         if (chord) {
     197            0 :             elements << chord;
     198              :         }
     199              :     }
     200              : 
     201            0 :     return QList<mu::engraving::EngravingItem*>(elements.begin(), elements.end());
     202            0 : }
     203              : 
     204            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findNotes() const
     205              : {
     206            0 :     QList<mu::engraving::EngravingItem*> result;
     207              : 
     208            0 :     for (engraving::EngravingItem* element : m_rawElementList) {
     209            0 :         if (element->isNote()) {
     210            0 :             result << element;
     211            0 :             continue;
     212              :         }
     213              : 
     214            0 :         engraving::EngravingItem* elementBase = element->elementBase();
     215              : 
     216            0 :         if (elementBase->isChord()) {
     217            0 :             engraving::Chord* chord = engraving::toChord(elementBase);
     218              : 
     219            0 :             for (mu::engraving::Note* note : chord->notes()) {
     220            0 :                 result << note;
     221              :             }
     222            0 :         } else if (elementBase->isBeam()) {
     223            0 :             const mu::engraving::Beam* beam = mu::engraving::toBeam(elementBase);
     224              : 
     225            0 :             for (mu::engraving::ChordRest* chordRest : beam->elements()) {
     226            0 :                 if (!chordRest->isChord()) {
     227            0 :                     continue;
     228              :                 }
     229              : 
     230            0 :                 for (mu::engraving::Note* note : engraving::toChord(chordRest)->notes()) {
     231            0 :                     result << note;
     232              :                 }
     233              :             }
     234              :         }
     235              :     }
     236              : 
     237            0 :     return result;
     238            0 : }
     239              : 
     240            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findNoteHeads() const
     241              : {
     242            0 :     QList<mu::engraving::EngravingItem*> resultList;
     243              : 
     244            0 :     for (mu::engraving::EngravingItem* element : m_rawElementList) {
     245            0 :         if (element->isNote()) {
     246            0 :             resultList << element;
     247              :         }
     248              :     }
     249              : 
     250            0 :     return resultList;
     251            0 : }
     252              : 
     253            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findStems() const
     254              : {
     255            0 :     QList<mu::engraving::EngravingItem*> resultList;
     256              : 
     257            0 :     for (const mu::engraving::EngravingItem* element : findChords()) {
     258            0 :         const mu::engraving::Chord* chord = mu::engraving::toChord(element);
     259              : 
     260            0 :         if (chord && chord->stem()) {
     261            0 :             resultList << chord->stem();
     262              :         }
     263            0 :     }
     264              : 
     265            0 :     return resultList;
     266            0 : }
     267              : 
     268            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findHooks() const
     269              : {
     270            0 :     QList<mu::engraving::EngravingItem*> resultList;
     271              : 
     272            0 :     for (const mu::engraving::EngravingItem* element : findChords()) {
     273            0 :         const mu::engraving::Chord* chord = mu::engraving::toChord(element);
     274              : 
     275            0 :         if (chord && chord->hook()) {
     276            0 :             resultList << chord->hook();
     277              :         }
     278            0 :     }
     279              : 
     280            0 :     return resultList;
     281            0 : }
     282              : 
     283            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findBeams() const
     284              : {
     285            0 :     QList<mu::engraving::EngravingItem*> resultList;
     286              : 
     287            0 :     for (const mu::engraving::EngravingItem* element : findChords()) {
     288            0 :         mu::engraving::EngravingItem* beam = nullptr;
     289              : 
     290            0 :         if (element->isChord()) {
     291            0 :             const mu::engraving::Chord* chord = mu::engraving::toChord(element);
     292              : 
     293            0 :             if (!chord) {
     294            0 :                 continue;
     295              :             }
     296              : 
     297            0 :             beam = chord->beam();
     298            0 :         } else if (element->isBeam()) {
     299            0 :             beam = const_cast<mu::engraving::EngravingItem*>(element);
     300              :         }
     301              : 
     302            0 :         if (!beam || resultList.contains(beam)) {
     303            0 :             continue;
     304              :         }
     305              : 
     306            0 :         resultList << beam;
     307            0 :     }
     308              : 
     309            0 :     return resultList;
     310            0 : }
     311              : 
     312            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findLines(mu::engraving::ElementType lineType) const
     313              : {
     314              :     static const QMap<mu::engraving::ElementType, mu::engraving::ElementType> lineTypeToSegmentType {
     315              :         { mu::engraving::ElementType::GLISSANDO, mu::engraving::ElementType::GLISSANDO_SEGMENT },
     316              :         { mu::engraving::ElementType::VIBRATO, mu::engraving::ElementType::VIBRATO_SEGMENT },
     317              :         { mu::engraving::ElementType::PEDAL, mu::engraving::ElementType::PEDAL_SEGMENT },
     318              :         { mu::engraving::ElementType::HAIRPIN, mu::engraving::ElementType::HAIRPIN_SEGMENT },
     319              :         { mu::engraving::ElementType::VOLTA, mu::engraving::ElementType::VOLTA_SEGMENT },
     320              :         { mu::engraving::ElementType::LET_RING, mu::engraving::ElementType::LET_RING_SEGMENT },
     321              :         { mu::engraving::ElementType::PALM_MUTE, mu::engraving::ElementType::PALM_MUTE_SEGMENT },
     322              :         { mu::engraving::ElementType::OTTAVA, mu::engraving::ElementType::OTTAVA_SEGMENT },
     323              :         { mu::engraving::ElementType::TEXTLINE, mu::engraving::ElementType::TEXTLINE_SEGMENT },
     324              :         { mu::engraving::ElementType::TEXTLINE_BASE, mu::engraving::ElementType::TEXTLINE_SEGMENT },
     325              :         { mu::engraving::ElementType::NOTELINE, mu::engraving::ElementType::NOTELINE_SEGMENT },
     326              :         { mu::engraving::ElementType::SLUR, mu::engraving::ElementType::SLUR_SEGMENT },
     327              :         { mu::engraving::ElementType::HAMMER_ON_PULL_OFF, mu::engraving::ElementType::HAMMER_ON_PULL_OFF_SEGMENT },
     328              :         { mu::engraving::ElementType::TIE, mu::engraving::ElementType::TIE_SEGMENT },
     329              :         { mu::engraving::ElementType::LAISSEZ_VIB, mu::engraving::ElementType::LAISSEZ_VIB_SEGMENT },
     330              :         { mu::engraving::ElementType::PARTIAL_TIE, mu::engraving::ElementType::PARTIAL_TIE_SEGMENT },
     331              :         { mu::engraving::ElementType::GRADUAL_TEMPO_CHANGE, mu::engraving::ElementType::GRADUAL_TEMPO_CHANGE_SEGMENT },
     332              :         { mu::engraving::ElementType::LYRICSLINE, mu::engraving::ElementType::LYRICSLINE_SEGMENT },
     333              :         { mu::engraving::ElementType::PARTIAL_LYRICSLINE, mu::engraving::ElementType::PARTIAL_LYRICSLINE_SEGMENT }
     334            0 :     };
     335              : 
     336            0 :     QList<mu::engraving::EngravingItem*> resultList;
     337              : 
     338            0 :     IF_ASSERT_FAILED(lineTypeToSegmentType.contains(lineType)) {
     339            0 :         return resultList;
     340              :     }
     341              : 
     342            0 :     mu::engraving::ElementType segmentType = lineTypeToSegmentType[lineType];
     343              : 
     344            0 :     for (mu::engraving::EngravingItem* element : m_exposedElementList) {
     345            0 :         if (element->type() == segmentType || (lineType == ElementType::TEXTLINE_BASE && element->isTextLineBaseSegment())) {
     346            0 :             const mu::engraving::SpannerSegment* segment = mu::engraving::toSpannerSegment(element);
     347            0 :             mu::engraving::Spanner* line = segment ? segment->spanner() : nullptr;
     348              : 
     349            0 :             if (line) {
     350            0 :                 resultList << line;
     351              :             }
     352            0 :         } else if (element->type() == lineType) {
     353            0 :             resultList << element;
     354              :         }
     355              :     }
     356              : 
     357            0 :     return resultList;
     358            0 : }
     359              : 
     360            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findStaffs() const
     361              : {
     362            0 :     QList<mu::engraving::EngravingItem*> resultList;
     363              : 
     364            0 :     for (const mu::engraving::EngravingItem* element : m_exposedElementList) {
     365            0 :         if (!element->staff()) {
     366            0 :             continue;
     367              :         }
     368              : 
     369            0 :         resultList << element->staff();
     370              :     }
     371              : 
     372            0 :     return resultList;
     373            0 : }
     374              : 
     375            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findSectionBreaks() const
     376              : {
     377            0 :     QList<mu::engraving::EngravingItem*> resultList;
     378              : 
     379            0 :     for (mu::engraving::EngravingItem* element : m_exposedElementList) {
     380            0 :         if (element && element->type() == mu::engraving::ElementType::LAYOUT_BREAK) {
     381            0 :             const mu::engraving::LayoutBreak* layoutBreak = mu::engraving::toLayoutBreak(element);
     382            0 :             if (layoutBreak->layoutBreakType() != mu::engraving::LayoutBreakType::SECTION) {
     383            0 :                 continue;
     384              :             }
     385              : 
     386            0 :             resultList << element;
     387              :         }
     388              :     }
     389              : 
     390            0 :     return resultList;
     391            0 : }
     392              : 
     393            0 : std::vector<EngravingItem*> ElementRepositoryService::findTextDelegates(EngravingItem* element) const
     394              : {
     395            0 :     if (element->isTextLineBaseSegment()) {
     396            0 :         std::vector<EngravingItem*> textItems;
     397            0 :         TextLineBase* tl = toTextLineBaseSegment(element)->textLineBase();
     398            0 :         for (SpannerSegment* seg : tl->spannerSegments()) {
     399            0 :             if (Text* text = toTextLineBaseSegment(seg)->text()) {
     400            0 :                 textItems.push_back(text);
     401              :             }
     402              : 
     403            0 :             if (Text* endText = toTextLineBaseSegment(seg)->endText()) {
     404            0 :                 textItems.push_back(endText);
     405              :             }
     406              :         }
     407              : 
     408            0 :         return textItems;
     409            0 :     }
     410              : 
     411            0 :     if (element->isBarLine()) {
     412            0 :         Segment* seg = toBarLine(element)->segment();
     413            0 :         if (PlayCountText* playCountText = toPlayCountText(seg->findAnnotation(ElementType::PLAY_COUNT_TEXT, 0, 0))) {
     414            0 :             return { playCountText };
     415              :         }
     416            0 :         return {};
     417              :     }
     418              : 
     419            0 :     if (TEXT_ELEMENT_TYPES.contains(element->type())) {
     420            0 :         return { element };
     421              :     }
     422              : 
     423            0 :     return {};
     424              : }
     425              : 
     426            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findTexts() const
     427              : {
     428            0 :     QList<mu::engraving::EngravingItem*> resultList;
     429              : 
     430            0 :     for (mu::engraving::EngravingItem* element : m_exposedElementList) {
     431            0 :         std::vector<EngravingItem*> delegateItems = findTextDelegates(element);
     432            0 :         for (mu::engraving::EngravingItem* el : delegateItems) {
     433            0 :             resultList << el;
     434              :         }
     435            0 :     }
     436              : 
     437            0 :     return resultList;
     438            0 : }
     439              : 
     440            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findBrackets() const
     441              : {
     442            0 :     QList<mu::engraving::EngravingItem*> resultList;
     443              : 
     444            0 :     for (mu::engraving::EngravingItem* element : m_exposedElementList) {
     445            0 :         if (element->isBracketItem()) {
     446            0 :             resultList << element;
     447              :         }
     448              :     }
     449              : 
     450            0 :     return resultList;
     451            0 : }
     452              : 
     453            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findRests() const
     454              : {
     455            0 :     QList<mu::engraving::EngravingItem*> resultList;
     456              : 
     457            0 :     for (mu::engraving::EngravingItem* element : m_exposedElementList) {
     458            0 :         if (element->isRest()) {
     459            0 :             resultList << element;
     460            0 :         } else if (element->isBeam()) {
     461            0 :             const mu::engraving::Beam* beam = mu::engraving::toBeam(element);
     462              : 
     463            0 :             for (mu::engraving::ChordRest* chordRest : beam->elements()) {
     464            0 :                 if (!chordRest->isRest()) {
     465            0 :                     continue;
     466              :                 }
     467            0 :                 resultList << chordRest;
     468              :             }
     469              :         }
     470              :     }
     471              : 
     472            0 :     return resultList;
     473            0 : }
     474              : 
     475            0 : QList<mu::engraving::EngravingItem*> ElementRepositoryService::findOrnaments() const
     476              : {
     477            0 :     QList<mu::engraving::EngravingItem*> resultList;
     478              : 
     479            0 :     for (mu::engraving::EngravingItem* element : m_exposedElementList) {
     480            0 :         if (element->isOrnament()) {
     481            0 :             resultList << element;
     482            0 :         } else if (element->isTrill()) {
     483            0 :             resultList << (EngravingItem*)(toTrill(element)->ornament());
     484            0 :         } else if (element->isTrillSegment()) {
     485            0 :             resultList << (EngravingItem*)(toTrillSegment(element)->trill()->ornament());
     486              :         }
     487              :     }
     488              : 
     489            0 :     return resultList;
     490            0 : }
     491              : 
     492            0 : QList<EngravingItem*> ElementRepositoryService::findLyrics() const
     493              : {
     494            0 :     QList<mu::engraving::EngravingItem*> resultList;
     495            0 :     for (mu::engraving::EngravingItem* element : m_exposedElementList) {
     496            0 :         if (element->isLyrics()) {
     497            0 :             resultList << element;
     498              :         }
     499              :     }
     500              : 
     501            0 :     return resultList;
     502            0 : }
     503              : 
     504            0 : muse::async::Channel<QList<EngravingItem*> > ElementRepositoryService::elementsUpdated() const
     505              : {
     506            0 :     return m_elementsUpdated;
     507              : }
        

Generated by: LCOV version 2.0-1