LCOV - code coverage report
Current view: top level - src/palette/internal - palettecell.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 221 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 "palettecell.h"
      23              : #include "palettecompat.h"
      24              : 
      25              : #include "mimedatautils.h"
      26              : 
      27              : #include "engraving/dom/actionicon.h"
      28              : #include "engraving/dom/engravingitem.h"
      29              : #include "engraving/dom/factory.h"
      30              : #include "engraving/dom/fret.h"
      31              : #include "engraving/dom/masterscore.h"
      32              : #include "engraving/dom/textbase.h"
      33              : #include "engraving/dom/tremolosinglechord.h"
      34              : #include "engraving/dom/tremolotwochord.h"
      35              : 
      36              : #include "engraving/rw/rwregister.h"
      37              : #include "engraving/rw/compat/tremolocompat.h"
      38              : 
      39              : #include "widgets/palettewidget.h"
      40              : 
      41              : #include "log.h"
      42              : #include "translation.h"
      43              : 
      44              : using namespace muse;
      45              : using namespace mu::palette;
      46              : using namespace mu::engraving;
      47              : 
      48            0 : static bool needsStaff(ElementPtr e)
      49              : {
      50            0 :     if (!e) {
      51            0 :         return false;
      52              :     }
      53            0 :     switch (e->type()) {
      54            0 :     case ElementType::CHORD:
      55              :     case ElementType::BAR_LINE:
      56              :     case ElementType::CLEF:
      57              :     case ElementType::KEYSIG:
      58              :     case ElementType::TIMESIG:
      59              :     case ElementType::REST:
      60              :     case ElementType::BAGPIPE_EMBELLISHMENT:
      61            0 :         return true;
      62            0 :     default:
      63            0 :         return false;
      64              :     }
      65              : }
      66              : 
      67            0 : PaletteCell::PaletteCell(const muse::modularity::ContextPtr& iocCtx, QObject* parent)
      68            0 :     : QObject(parent), muse::Contextable(iocCtx)
      69              : {
      70            0 :     id = makeId();
      71            0 : }
      72              : 
      73            0 : PaletteCell::PaletteCell(const muse::modularity::ContextPtr& iocCtx, ElementPtr e, const QString& _name, qreal _mag, const QPointF& _offset,
      74            0 :                          const QString& _tag, QObject* parent)
      75            0 :     : QObject(parent), muse::Contextable(iocCtx), element(e), name(_name), mag(_mag), xoffset(_offset.x()), yoffset(_offset.y()), tag(_tag)
      76              : {
      77            0 :     id = makeId();
      78            0 :     drawStaff = needsStaff(element);
      79            0 : }
      80              : 
      81            0 : QAccessibleInterface* PaletteCell::accessibleInterface(QObject* object)
      82              : {
      83            0 :     PaletteCell* cell = qobject_cast<PaletteCell*>(object);
      84            0 :     IF_ASSERT_FAILED(cell) {
      85            0 :         return nullptr;
      86              :     }
      87              : 
      88            0 :     return static_cast<QAccessibleInterface*>(new AccessiblePaletteCellInterface(cell));
      89              : }
      90              : 
      91            0 : QString PaletteCell::makeId()
      92              : {
      93              :     static unsigned int id = 0;
      94            0 :     return QString::number(++id);
      95              : }
      96              : 
      97            0 : const char* PaletteCell::translationContext() const
      98              : {
      99              :     // Keep in sync with PaletteCreator and all element types
     100            0 :     const ElementType type = element ? element->type() : ElementType::INVALID;
     101            0 :     switch (type) {
     102            0 :     case ElementType::ACTION_ICON:
     103            0 :         return "action";
     104            0 :     case ElementType::ARPEGGIO:
     105              :     case ElementType::CHORD_BRACKET:
     106              :     case ElementType::CHORDLINE:
     107              :     case ElementType::GLISSANDO:
     108              :     case ElementType::HARMONY:
     109              :     case ElementType::JUMP:
     110              :     case ElementType::KEYSIG:
     111              :     case ElementType::MARKER:
     112            0 :         return "engraving";
     113            0 :     case ElementType::BAGPIPE_EMBELLISHMENT:
     114            0 :         return "engraving/bagpipeembellishment";
     115            0 :     case ElementType::CLEF:
     116            0 :         return "engraving/cleftype";
     117            0 :     case ElementType::DYNAMIC:
     118            0 :         return "engraving/dynamictype";
     119            0 :     case ElementType::HAIRPIN:
     120            0 :         return "engraving/hairpintype";
     121            0 :     case ElementType::LAYOUT_BREAK:
     122            0 :         return "engraving/layoutbreaktype";
     123            0 :     case ElementType::NOTEHEAD:
     124            0 :         return "engraving/noteheadgroup";
     125            0 :     case ElementType::OTTAVA:
     126            0 :         return "engraving/ottavatype";
     127            0 :     case ElementType::SPACER:
     128            0 :         return "engraving/spacertype";
     129            0 :     case ElementType::ACCIDENTAL:
     130              :     case ElementType::ARTICULATION:
     131              :     case ElementType::BAR_LINE:
     132              :     case ElementType::BREATH:
     133              :     case ElementType::FERMATA:
     134              :     case ElementType::MEASURE_REPEAT:
     135              :     case ElementType::ORNAMENT:
     136              :     case ElementType::SYMBOL:
     137            0 :         return "engraving/sym";
     138            0 :     case ElementType::PLAYTECH_ANNOTATION:
     139            0 :         return "engraving/playtechtype";
     140            0 :     case ElementType::TIMESIG:
     141            0 :         return "engraving/timesig";
     142            0 :     case ElementType::TREMOLO_SINGLECHORD:
     143              :     case ElementType::TREMOLO_TWOCHORD:
     144            0 :         return "engraving/tremolotype";
     145            0 :     case ElementType::TRILL:
     146            0 :         return "engraving/trilltype";
     147            0 :     case ElementType::TRIPLET_FEEL:
     148            0 :         return "engraving/tripletfeel";
     149            0 :     case ElementType::VIBRATO:
     150            0 :         return "engraving/vibratotype";
     151            0 :     default:
     152            0 :         break;
     153              :     }
     154            0 :     return "palette";
     155              : }
     156              : 
     157            0 : QString PaletteCell::translatedName() const
     158              : {
     159            0 :     const QString trName = muse::qtrc(translationContext(), name.toUtf8());
     160              : 
     161            0 :     if (element && element->isTextBase() && name.contains("%1")) {
     162            0 :         return trName.arg(toTextBase(element.get())->plainText());
     163              :     }
     164            0 :     return trName;
     165            0 : }
     166              : 
     167              : /// Retranslates cell content, e.g. text if the element is TextBase.
     168            0 : void PaletteCell::retranslate()
     169              : {
     170            0 :     if (untranslatedElement && element->isTextBase()) {
     171            0 :         TextBase* target = toTextBase(element.get());
     172            0 :         TextBase* orig = toTextBase(untranslatedElement.get());
     173            0 :         const QString& text = orig->xmlText();
     174            0 :         target->setXmlText(muse::qtrc("palette", text.toUtf8().constData()));
     175            0 :     }
     176            0 : }
     177              : 
     178            0 : void PaletteCell::setElementTranslated(bool translate)
     179              : {
     180            0 :     if (translate && element) {
     181            0 :         untranslatedElement = element;
     182            0 :         element.reset(untranslatedElement->clone());
     183            0 :         retranslate();
     184              :     } else {
     185            0 :         untranslatedElement.reset();
     186              :     }
     187            0 : }
     188              : 
     189            0 : bool PaletteCell::read(XmlReader& e, bool pasteMode)
     190              : {
     191              :     UNUSED(pasteMode);
     192              : 
     193            0 :     bool add = true;
     194            0 :     name = e.attribute("name");
     195              : 
     196              :     // using attributes instead of nested tags for
     197              :     // pre-3.3 version compatibility
     198            0 :     custom = e.hasAttribute("custom") ? e.intAttribute("custom") : false; // TODO: actually check master palette?
     199            0 :     visible = e.hasAttribute("visible") ? e.intAttribute("visible") : true;
     200              : 
     201            0 :     const bool translateElement = e.hasAttribute("trElement") ? e.intAttribute("trElement") : false;
     202              : 
     203            0 :     while (e.readNextStartElement()) {
     204            0 :         const AsciiStringView s(e.name());
     205            0 :         if (s == "staff") {
     206            0 :             drawStaff = e.readInt();
     207            0 :         } else if (s == "xoffset") {
     208            0 :             xoffset = e.readDouble();
     209            0 :         } else if (s == "yoffset") {
     210            0 :             yoffset = e.readDouble();
     211            0 :         } else if (s == "mag") {
     212            0 :             mag = e.readDouble();
     213            0 :         } else if (s == "tag") {
     214            0 :             tag = e.readText();
     215              :         }
     216              :         // added on palettes rework
     217              :         // TODO: remove or leave to switch from using attributes later?
     218            0 :         else if (s == "custom") {
     219            0 :             custom = e.readBool();
     220            0 :         } else if (s == "visible") {
     221            0 :             visible = e.readBool();
     222            0 :         } else if (s == "Tremolo") {
     223            0 :             Score* paletteScore = paletteScoreProvider()->paletteScore();
     224            0 :             compat::TremoloCompat tc { paletteScore->dummy() };
     225            0 :             rw::RWRegister::reader(paletteScore->mscVersion())->readTremoloCompat(&tc, e);
     226            0 :             if (tc.single) {
     227            0 :                 element.reset(tc.single);
     228            0 :             } else if (tc.two) {
     229            0 :                 element.reset(tc.two);
     230              :             } else {
     231            0 :                 UNREACHABLE;
     232              :             }
     233              : 
     234            0 :             if (element) {
     235            0 :                 element->styleChanged();
     236              :             }
     237              :         } else {
     238            0 :             element.reset(Factory::createItemByName(s, paletteScoreProvider()->paletteScore()->dummy()));
     239            0 :             if (!element) {
     240            0 :                 e.unknown();
     241              :             } else {
     242            0 :                 rw::RWRegister::reader(paletteScoreProvider()->paletteScore()->mscVersion())->readItem(element.get(), e);
     243              :             }
     244              :         }
     245              :     }
     246              : 
     247            0 :     setElementTranslated(translateElement);
     248              : 
     249            0 :     if (element) {
     250            0 :         PaletteCompat::migrateOldPaletteCellIfNeeded(this, paletteScoreProvider()->paletteScore());
     251            0 :         element->styleChanged();
     252              :     }
     253              : 
     254            0 :     return add && element;
     255              : }
     256              : 
     257            0 : void PaletteCell::write(XmlWriter& xml, bool pasteMode) const
     258              : {
     259              :     UNUSED(pasteMode);
     260              : 
     261            0 :     if (!element) {
     262            0 :         xml.tag("Cell");
     263            0 :         return;
     264              :     }
     265              : 
     266              :     // using attributes for `custom` and `visible` properties instead of nested tags
     267              :     // for pre-3.3 version compatibility
     268            0 :     XmlWriter::Attributes cellAttrs;
     269            0 :     if (!name.isEmpty()) {
     270            0 :         cellAttrs.push_back({ "name", name });
     271              :     }
     272            0 :     if (custom) {
     273            0 :         cellAttrs.push_back({ "custom", "1" });
     274              :     }
     275            0 :     if (!visible) {
     276            0 :         cellAttrs.push_back({ "visible", "0" });
     277              :     }
     278              : 
     279            0 :     if (untranslatedElement) {
     280            0 :         cellAttrs.push_back({ "trElement", "1" });
     281              :     }
     282              : 
     283            0 :     xml.startElement("Cell", cellAttrs);
     284              : 
     285            0 :     if (drawStaff) {
     286            0 :         xml.tag("staff", drawStaff);
     287              :     }
     288            0 :     if (xoffset) {
     289            0 :         xml.tag("xoffset", xoffset);
     290              :     }
     291            0 :     if (yoffset) {
     292            0 :         xml.tag("yoffset", yoffset);
     293              :     }
     294            0 :     if (!tag.isEmpty()) {
     295            0 :         xml.tag("tag", tag);
     296              :     }
     297            0 :     if (!RealIsEqual(mag, 1.0)) {
     298            0 :         xml.tag("mag", mag);
     299              :     }
     300              : 
     301            0 :     if (untranslatedElement) {
     302            0 :         rw::RWRegister::writer()->writeItem(untranslatedElement.get(), xml);
     303              :     } else {
     304            0 :         rw::RWRegister::writer()->writeItem(element.get(), xml);
     305              :     }
     306            0 :     xml.endElement();
     307            0 : }
     308              : 
     309            0 : PaletteCellPtr PaletteCell::fromMimeData(const QByteArray& data, const muse::modularity::ContextPtr& iocCtx)
     310              : {
     311            0 :     return ::fromMimeData<PaletteCell>(data, "Cell", iocCtx);
     312              : }
     313              : 
     314            0 : PaletteCellPtr PaletteCell::fromElementMimeData(const QByteArray& data, const muse::modularity::ContextPtr& iocCtx)
     315              : {
     316            0 :     PointF dragOffset;
     317            0 :     Fraction duration(1, 4);
     318            0 :     muse::ContextInject<engraving::IPaletteScoreProvider> paletteScoreProvider = { iocCtx };
     319            0 :     ElementPtr element(EngravingItem::readMimeData(paletteScoreProvider()->paletteScore(),
     320            0 :                                                    muse::ByteArray::fromQByteArrayNoCopy(data),
     321            0 :                                                    &dragOffset, &duration));
     322              : 
     323            0 :     if (!element) {
     324            0 :         return nullptr;
     325              :     }
     326              : 
     327            0 :     if (!element->isSymbol()) { // not sure this check is necessary, it was so in the old palette
     328            0 :         element->setTrack(0);
     329              :     }
     330              : 
     331            0 :     const String name = (element->isFretDiagram()) ? toFretDiagram(element.get())->harmonyPlainText() : element->translatedTypeUserName();
     332              : 
     333            0 :     return std::make_shared<PaletteCell>(iocCtx, element, name);
     334            0 : }
     335              : 
     336            0 : QByteArray PaletteCell::toMimeData() const
     337              : {
     338            0 :     return ::toMimeData(this);
     339              : }
     340              : 
     341            0 : AccessiblePaletteCellInterface::AccessiblePaletteCellInterface(PaletteCell* cell)
     342              : {
     343            0 :     m_cell = cell;
     344            0 : }
     345              : 
     346            0 : bool AccessiblePaletteCellInterface::isValid() const
     347              : {
     348            0 :     return m_cell != nullptr;
     349              : }
     350              : 
     351            0 : QObject* AccessiblePaletteCellInterface::object() const
     352              : {
     353            0 :     return m_cell;
     354              : }
     355              : 
     356            0 : QAccessibleInterface* AccessiblePaletteCellInterface::childAt(int, int) const
     357              : {
     358            0 :     return nullptr;
     359              : }
     360              : 
     361            0 : QAccessibleInterface* AccessiblePaletteCellInterface::parent() const
     362              : {
     363            0 :     auto paletteWidget = parentWidget();
     364            0 :     if (!paletteWidget) {
     365            0 :         return nullptr;
     366              :     }
     367              : 
     368            0 :     return QAccessible::queryAccessibleInterface(paletteWidget);
     369              : }
     370              : 
     371            0 : QAccessibleInterface* AccessiblePaletteCellInterface::child(int) const
     372              : {
     373            0 :     return nullptr;
     374              : }
     375              : 
     376            0 : int AccessiblePaletteCellInterface::childCount() const
     377              : {
     378            0 :     return 0;
     379              : }
     380              : 
     381            0 : int AccessiblePaletteCellInterface::indexOfChild(const QAccessibleInterface*) const
     382              : {
     383            0 :     return -1;
     384              : }
     385              : 
     386            0 : QString AccessiblePaletteCellInterface::text(QAccessible::Text t) const
     387              : {
     388            0 :     switch (t) {
     389            0 :     case QAccessible::Text::Name:
     390            0 :         return m_cell->element->accessibleInfo();
     391            0 :     default:
     392            0 :         break;
     393              :     }
     394              : 
     395            0 :     return QString();
     396              : }
     397              : 
     398            0 : void AccessiblePaletteCellInterface::setText(QAccessible::Text, const QString&)
     399              : {
     400            0 : }
     401              : 
     402            0 : QRect AccessiblePaletteCellInterface::rect() const
     403              : {
     404            0 :     return QRect();
     405              : }
     406              : 
     407            0 : QAccessible::Role AccessiblePaletteCellInterface::role() const
     408              : {
     409            0 :     return QAccessible::ListItem;
     410              : }
     411              : 
     412            0 : QAccessible::State AccessiblePaletteCellInterface::state() const
     413              : {
     414            0 :     QAccessible::State state;
     415            0 :     state.invisible = false;
     416            0 :     state.invalid = false;
     417            0 :     state.disabled = false;
     418              : 
     419            0 :     state.focusable = true;
     420            0 :     state.focused = m_cell->focused;
     421              : 
     422            0 :     return state;
     423              : }
     424              : 
     425            0 : QObject* AccessiblePaletteCellInterface::parentWidget() const
     426              : {
     427            0 :     auto palette = m_cell->parent();
     428            0 :     if (!palette) {
     429            0 :         return nullptr;
     430              :     }
     431              : 
     432            0 :     return palette->parent();
     433              : }
        

Generated by: LCOV version 2.0-1