LCOV - code coverage report
Current view: top level - muse/framework/uicomponents/qml/Muse/UiComponents - abstracttoolbarmodel.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-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 "abstracttoolbarmodel.h"
      23              : 
      24              : #include "types/translatablestring.h"
      25              : 
      26              : #include "toolbaritem.h"
      27              : #include "menuitem.h"
      28              : 
      29              : #include "log.h"
      30              : 
      31              : using namespace muse::uicomponents;
      32              : using namespace muse::ui;
      33              : #ifdef MUSE_MODULE_ACTIONS_SUPPORT
      34              : using namespace muse::actions;
      35              : #endif
      36              : 
      37              : const int AbstractToolBarModel::INVALID_ITEM_INDEX = -1;
      38              : 
      39            0 : AbstractToolBarModel::AbstractToolBarModel(QObject* parent)
      40            0 :     : QAbstractListModel(parent), muse::Contextable(muse::iocCtxForQmlObject(this))
      41              : {
      42            0 : }
      43              : 
      44            0 : QVariant AbstractToolBarModel::data(const QModelIndex& index, int role) const
      45              : {
      46            0 :     int row = index.row();
      47              : 
      48            0 :     if (!isIndexValid(row)) {
      49            0 :         return QVariant();
      50              :     }
      51              : 
      52            0 :     ToolBarItem* item = m_items.at(row);
      53              : 
      54            0 :     switch (role) {
      55            0 :     case ItemRole: return QVariant::fromValue(item);
      56            0 :     case UserRole: return QVariant();
      57              :     }
      58              : 
      59            0 :     return QVariant();
      60              : }
      61              : 
      62            0 : bool AbstractToolBarModel::isIndexValid(int index) const
      63              : {
      64            0 :     return index >= 0 && index < m_items.size();
      65              : }
      66              : 
      67            0 : int AbstractToolBarModel::rowCount(const QModelIndex&) const
      68              : {
      69            0 :     return m_items.count();
      70              : }
      71              : 
      72            0 : QHash<int, QByteArray> AbstractToolBarModel::roleNames() const
      73              : {
      74              :     static const QHash<int, QByteArray> roles {
      75            0 :         { ItemRole, "item" }
      76            0 :     };
      77              : 
      78            0 :     return roles;
      79            0 : }
      80              : 
      81            0 : QVariantMap AbstractToolBarModel::get(int index)
      82              : {
      83            0 :     QVariantMap result;
      84              : 
      85            0 :     QHash<int, QByteArray> names = roleNames();
      86            0 :     QHashIterator<int, QByteArray> i(names);
      87            0 :     while (i.hasNext()) {
      88            0 :         i.next();
      89            0 :         QModelIndex idx = this->index(index, 0);
      90            0 :         QVariant data = idx.data(i.key());
      91            0 :         result[i.value()] = data;
      92            0 :     }
      93              : 
      94            0 :     return result;
      95            0 : }
      96              : 
      97            0 : void AbstractToolBarModel::load()
      98              : {
      99            0 :     commandsState()->commandStateChanged().onReceive(this, [this](const rcommand::Command& command, const rcommand::CommandState& state) {
     100            0 :         onCommandStateChanged(command, state);
     101            0 :     }, async::Asyncable::Mode::SetReplace);
     102              : 
     103              : #ifdef MUSE_MODULE_ACTIONS_SUPPORT
     104            0 :     uiActionsRegister()->actionStateChanged().onReceive(this, [this](const ActionCodeList& codes) {
     105            0 :         onActionsStateChanges(codes);
     106            0 :     }, async::Asyncable::Mode::SetReplace);
     107              : #endif
     108              : 
     109              : #ifdef MUSE_MODULE_SHORTCUTS_V2
     110            0 :     commandShortcutsRegister()->shortcutsChanged().onNotify(this, [this]() {
     111            0 :         updateShortcutsAll();
     112            0 :     }, async::Asyncable::Mode::SetReplace);
     113              : #else
     114              :     shortcutsRegister()->shortcutsChanged().onNotify(this, [this]() {
     115              :         updateShortcutsAll();
     116              :     }, async::Asyncable::Mode::SetReplace);
     117              : #endif
     118            0 : }
     119              : 
     120            0 : void AbstractToolBarModel::onCommandStateChanged(const rcommand::Command& command, const rcommand::CommandState& state)
     121              : {
     122            0 :     updateState(m_items, command, state);
     123            0 : }
     124              : 
     125            0 : void AbstractToolBarModel::updateState(ToolBarItemList& items, const rcommand::Command& command, const rcommand::CommandState& state)
     126              : {
     127            0 :     for (ToolBarItem* toolBarItem : items) {
     128            0 :         if (!toolBarItem) {
     129            0 :             continue;
     130              :         }
     131              : 
     132            0 :         if (command == toolBarItem->command()) {
     133            0 :             toolBarItem->setCommandState(state);
     134              :         }
     135              : 
     136            0 :         QList<MenuItem*> subitems = toolBarItem->menuItems();
     137            0 :         if (!subitems.empty()) {
     138            0 :             updateState(subitems, command, state);
     139              :         }
     140            0 :     }
     141            0 : }
     142              : 
     143            0 : void AbstractToolBarModel::updateState(QList<MenuItem*>& items, const rcommand::Command& command, const rcommand::CommandState& state)
     144              : {
     145            0 :     for (MenuItem* menuItem : items) {
     146            0 :         if (!menuItem) {
     147            0 :             continue;
     148              :         }
     149              : 
     150            0 :         if (command == menuItem->command()) {
     151            0 :             menuItem->setCommandState(state);
     152              :         }
     153              : 
     154            0 :         MenuItemList subitems = menuItem->subitems();
     155            0 :         if (!subitems.empty()) {
     156            0 :             updateState(subitems, command, state);
     157              :         }
     158            0 :     }
     159            0 : }
     160              : 
     161            0 : ToolBarItem* AbstractToolBarModel::makeItem(const rcommand::Command& command,
     162              :                                             const rcommand::Params& params,
     163              :                                             const TranslatableString& title)
     164              : {
     165            0 :     const rcommand::CommandInfo& info = commandsRegister()->commandInfo(command);
     166            0 :     if (!info.isValid()) {
     167            0 :         LOGW() << "not found command: " << command;
     168            0 :         return nullptr;
     169              :     }
     170              : 
     171            0 :     ToolBarItem* item = new ToolBarItem(info, ToolBarItemType::ACTION, this);
     172            0 :     item->setCommand(command);
     173            0 :     item->setParams(params);
     174            0 :     item->setCommandState(commandsState()->commandState(command));
     175              : 
     176            0 :     if (!title.isEmpty()) {
     177            0 :         item->setTitle(title);
     178              :     }
     179              : 
     180            0 :     return item;
     181              : }
     182              : 
     183            0 : ToolBarItem* AbstractToolBarModel::makeItem(const rcommand::Command& command, const TranslatableString& title)
     184              : {
     185            0 :     return makeItem(command, {}, title);
     186              : }
     187              : 
     188            0 : ToolBarItem& AbstractToolBarModel::findItem(const rcommand::Command& command) const
     189              : {
     190            0 :     if (ToolBarItem* toolBarItem = findItemPtr(command)) {
     191            0 :         return *toolBarItem;
     192              :     }
     193              : 
     194            0 :     static ToolBarItem dummy;
     195            0 :     return dummy;
     196              : }
     197              : 
     198            0 : ToolBarItem* AbstractToolBarModel::findItemPtr(const rcommand::Command& command) const
     199              : {
     200            0 :     for (ToolBarItem* toolBarItem : std::as_const(m_items)) {
     201            0 :         if (toolBarItem->command() == command) {
     202            0 :             return toolBarItem;
     203              :         }
     204              :     }
     205              : 
     206            0 :     return nullptr;
     207              : }
     208              : 
     209            0 : QVariantList AbstractToolBarModel::itemsProperty() const
     210              : {
     211            0 :     QVariantList items;
     212              : 
     213            0 :     for (ToolBarItem* item: m_items) {
     214            0 :         items << QVariant::fromValue(item);
     215              :     }
     216              : 
     217            0 :     return items;
     218            0 : }
     219              : 
     220            0 : const ToolBarItemList& AbstractToolBarModel::items() const
     221              : {
     222            0 :     return m_items;
     223              : }
     224              : 
     225            0 : void AbstractToolBarModel::setItems(const ToolBarItemList& items)
     226              : {
     227            0 :     TRACEFUNC;
     228              : 
     229            0 :     beginResetModel();
     230              : 
     231            0 :     qDeleteAll(m_items);
     232            0 :     m_items.clear();
     233              : 
     234              :     //! NOTE: make sure that we don't have two separators sequentially
     235            0 :     bool isPreviousSeparator = false;
     236              : 
     237            0 :     for (ToolBarItem* item : items) {
     238            0 :         if (item->type() == ToolBarItemType::SEPARATOR) {
     239            0 :             if (isPreviousSeparator) {
     240            0 :                 delete item;
     241            0 :                 continue;
     242              :             }
     243              : 
     244            0 :             isPreviousSeparator = true;
     245              :         } else {
     246            0 :             isPreviousSeparator = false;
     247              :         }
     248              : 
     249            0 :         m_items << item;
     250              :     }
     251              : 
     252            0 :     updateShortcutsAll();
     253              : 
     254            0 :     endResetModel();
     255              : 
     256            0 :     emit itemsChanged();
     257            0 : }
     258              : 
     259            0 : void AbstractToolBarModel::clear()
     260              : {
     261            0 :     setItems(ToolBarItemList());
     262            0 : }
     263              : 
     264            0 : int AbstractToolBarModel::itemIndex(const QString& itemId) const
     265              : {
     266            0 :     for (int i = 0; i < m_items.size(); ++i) {
     267            0 :         if (m_items[i]->id() == itemId) {
     268            0 :             return i;
     269              :         }
     270              :     }
     271              : 
     272            0 :     return INVALID_ITEM_INDEX;
     273              : }
     274              : 
     275            0 : ToolBarItem& AbstractToolBarModel::item(int index)
     276              : {
     277            0 :     ToolBarItem& item = *m_items[index];
     278            0 :     if (item.isValid()) {
     279            0 :         return item;
     280              :     }
     281              : 
     282            0 :     static ToolBarItem dummy;
     283            0 :     return dummy;
     284              : }
     285              : 
     286            0 : ToolBarItem& AbstractToolBarModel::findItem(const QString& itemId)
     287              : {
     288            0 :     return item(m_items, itemId);
     289              : }
     290              : 
     291            0 : ToolBarItem* AbstractToolBarModel::findItemPtr(const QString& itemId)
     292              : {
     293            0 :     for (ToolBarItem* toolBarItem : std::as_const(m_items)) {
     294            0 :         if (toolBarItem->id() == itemId) {
     295            0 :             return toolBarItem;
     296              :         }
     297              :     }
     298              : 
     299            0 :     return nullptr;
     300              : }
     301              : 
     302            0 : ToolBarItem* AbstractToolBarModel::makeSeparator()
     303              : {
     304            0 :     return new ToolBarItem(ToolBarItemType::SEPARATOR, this);
     305              : }
     306              : 
     307            0 : void AbstractToolBarModel::setItem(int index, ToolBarItem* item)
     308              : {
     309            0 :     if (!isIndexValid(index)) {
     310            0 :         return;
     311              :     }
     312              : 
     313            0 :     m_items[index] = item;
     314              : 
     315            0 :     QModelIndex modelIndex = this->index(index);
     316            0 :     emit dataChanged(modelIndex, modelIndex);
     317              : }
     318              : 
     319            0 : ToolBarItem& AbstractToolBarModel::item(const ToolBarItemList& items, const QString& itemId) const
     320              : {
     321            0 :     for (ToolBarItem* toolBarItem : items) {
     322            0 :         if (toolBarItem->id() == itemId) {
     323            0 :             return *toolBarItem;
     324              :         }
     325              :     }
     326              : 
     327            0 :     static ToolBarItem dummy;
     328            0 :     return dummy;
     329              : }
     330              : 
     331              : #ifdef MUSE_MODULE_ACTIONS_SUPPORT
     332            0 : ToolBarItem* AbstractToolBarModel::makeItem(const ActionCode& actionCode, const TranslatableString& title)
     333              : {
     334            0 :     const UiAction& action = uiActionsRegister()->action(actionCode);
     335            0 :     if (!action.isValid()) {
     336            0 :         LOGW() << "not found action: " << actionCode;
     337            0 :         return nullptr;
     338              :     }
     339              : 
     340            0 :     ToolBarItem* item = new ToolBarItem(action, ToolBarItemType::ACTION, this);
     341            0 :     item->setState(uiActionsRegister()->actionState(actionCode));
     342              : 
     343            0 :     if (!title.isEmpty()) {
     344            0 :         item->setTitle(title);
     345              :     }
     346              : 
     347            0 :     return item;
     348              : }
     349              : 
     350            0 : ToolBarItem* AbstractToolBarModel::makeMenuItem(const TranslatableString& title, const ActionCodeList& subitemsActionCodesList,
     351              :                                                 const QString& menuId, bool enabled)
     352              : {
     353            0 :     ToolBarItem* item = new ToolBarItem(this);
     354            0 :     item->setId(menuId);
     355            0 :     item->setTitle(title);
     356            0 :     item->setEnabled(enabled);
     357              : 
     358            0 :     MenuItemList subitems;
     359            0 :     for (const ActionCode& subitemActionCode: subitemsActionCodesList) {
     360            0 :         const UiAction& action = uiActionsRegister()->action(subitemActionCode);
     361            0 :         if (!action.isValid()) {
     362            0 :             LOGW() << "not found action: " << subitemActionCode;
     363            0 :             continue;
     364              :         }
     365              : 
     366            0 :         MenuItem* subitem = new MenuItem(action, this);
     367            0 :         subitem->setState(uiActionsRegister()->actionState(subitemActionCode));
     368              : 
     369            0 :         updateShortcuts(subitem);
     370              : 
     371            0 :         subitems << subitem;
     372              :     }
     373            0 :     item->setMenuItems(subitems);
     374              : 
     375            0 :     return item;
     376            0 : }
     377              : 
     378            0 : ToolBarItem& AbstractToolBarModel::item(const ToolBarItemList& items, const ActionCode& actionCode) const
     379              : {
     380            0 :     for (ToolBarItem* toolBarItem : items) {
     381            0 :         if (!toolBarItem) {
     382            0 :             continue;
     383              :         }
     384              : 
     385            0 :         if (toolBarItem->actionCode() == actionCode) {
     386            0 :             return *toolBarItem;
     387              :         }
     388              :     }
     389              : 
     390            0 :     static ToolBarItem dummy;
     391            0 :     return dummy;
     392              : }
     393              : 
     394            0 : ToolBarItem& AbstractToolBarModel::findItem(const ActionCode& actionCode)
     395              : {
     396            0 :     return item(m_items, actionCode);
     397              : }
     398              : 
     399            0 : ToolBarItem* AbstractToolBarModel::findItemPtr(const actions::ActionCode& actionCode)
     400              : {
     401            0 :     for (ToolBarItem* toolBarItem : std::as_const(m_items)) {
     402            0 :         if (toolBarItem->actionCode() == actionCode) {
     403            0 :             return toolBarItem;
     404              :         }
     405              :     }
     406              : 
     407            0 :     return nullptr;
     408              : }
     409              : 
     410            0 : void AbstractToolBarModel::onActionsStateChanges(const muse::actions::ActionCodeList& codes)
     411              : {
     412            0 :     if (codes.empty()) {
     413            0 :         return;
     414              :     }
     415              : 
     416            0 :     for (const ActionCode& code : codes) {
     417            0 :         ToolBarItem& actionItem = findItem(code);
     418            0 :         if (actionItem.isValid()) {
     419            0 :             actionItem.setState(uiActionsRegister()->actionState(code));
     420              :         }
     421              :     }
     422              : }
     423              : 
     424              : #endif // MUSE_MODULE_ACTIONS_SUPPORT
     425              : 
     426            0 : bool AbstractToolBarModel::isCompactMode() const
     427              : {
     428            0 :     return m_isCompactMode;
     429              : }
     430              : 
     431            0 : void AbstractToolBarModel::setIsCompactMode(bool isCompactMode)
     432              : {
     433            0 :     if (m_isCompactMode == isCompactMode) {
     434            0 :         return;
     435              :     }
     436              : 
     437            0 :     for (ToolBarItem* item : std::as_const(m_items)) {
     438            0 :         if (item) {
     439            0 :             item->setShowTitle(!isCompactMode);
     440              :         }
     441              :     }
     442              : 
     443            0 :     m_isCompactMode = isCompactMode;
     444            0 :     emit isCompactModeChanged();
     445              : }
     446              : 
     447            0 : void AbstractToolBarModel::updateShortcutsAll()
     448              : {
     449            0 :     for (ToolBarItem* toolBarItem : std::as_const(m_items)) {
     450            0 :         if (!toolBarItem) {
     451            0 :             continue;
     452              :         }
     453              : 
     454            0 :         std::vector<std::string> shortcuts;
     455              : #ifdef MUSE_MODULE_SHORTCUTS_V2
     456            0 :         shortcuts = commandShortcutsRegister()->shortcut(toolBarItem->command()).sequences;
     457              : #else
     458              : #ifdef MUSE_MODULE_ACTIONS_SUPPORT
     459              :         shortcuts = shortcutsRegister()->shortcut(toolBarItem->actionCode()).sequences;
     460              : #endif
     461              : #endif
     462            0 :         toolBarItem->setShortcuts(shortcuts);
     463              : 
     464            0 :         for (MenuItem* menuItem : std::as_const(toolBarItem->menuItems())) {
     465            0 :             if (!menuItem) {
     466            0 :                 continue;
     467              :             }
     468              : 
     469            0 :             updateShortcuts(menuItem);
     470              :         }
     471            0 :     }
     472            0 : }
     473              : 
     474            0 : void AbstractToolBarModel::updateShortcuts(MenuItem* menuItem)
     475              : {
     476            0 :     std::vector<std::string> shortcuts;
     477              : #ifdef MUSE_MODULE_SHORTCUTS_V2
     478            0 :     shortcuts = commandShortcutsRegister()->shortcut(menuItem->command()).sequences;
     479              : #else
     480              : #ifdef MUSE_MODULE_ACTIONS_SUPPORT
     481              :     shortcuts = shortcutsRegister()->shortcut(menuItem->actionCode()).sequences;
     482              : #endif
     483              : #endif
     484            0 :     menuItem->setShortcuts(shortcuts);
     485              : 
     486            0 :     for (MenuItem* subItem : menuItem->subitems()) {
     487            0 :         if (!subItem) {
     488            0 :             continue;
     489              :         }
     490              : 
     491            0 :         updateShortcuts(subItem);
     492            0 :     }
     493            0 : }
        

Generated by: LCOV version 2.0-1