LCOV - code coverage report
Current view: top level - muse/framework/dockwindow_v2/qml/Muse/Dock - dockpageview.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 35.5 % 245 87
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              : 
      23              : #include "dockpageview.h"
      24              : 
      25              : #include <QTimer>
      26              : 
      27              : #include "docktoolbarview.h"
      28              : #include "dockingholderview.h"
      29              : #include "dockcentralview.h"
      30              : #include "dockpanelview.h"
      31              : #include "dockstatusbar.h"
      32              : 
      33              : #include "ui/qml/Muse/Ui/navigationcontrol.h"
      34              : 
      35              : #include "log.h"
      36              : 
      37              : using namespace muse::dock;
      38              : using namespace muse::ui;
      39              : 
      40           24 : DockPageView::DockPageView(QQuickItem* parent)
      41           24 :     : QQuickItem(parent), muse::Contextable(muse::iocCtxForQmlObject(this)),
      42           24 :     m_mainToolBars(this),
      43           24 :     m_toolBars(this),
      44           24 :     m_toolBarsDockingHolders(this),
      45           24 :     m_panels(this),
      46           72 :     m_panelsDockingHolders(this)
      47              : {
      48              :     //! NOTE: dockwindow controls the visible state
      49           24 :     setVisible(false);
      50           24 : }
      51              : 
      52            3 : void DockPageView::init()
      53              : {
      54            4 :     TRACEFUNC;
      55              : 
      56           12 :     for (DockBase* dock : allDocks()) {
      57            9 :         dock->setParentItem(this);
      58            9 :         dock->init();
      59              : 
      60            9 :         connect(dock, &DockBase::floatingChanged, [this](){
      61            0 :             reorderSections();
      62            0 :         });
      63              : 
      64            9 :         connect(dock, &DockBase::visibleChanged, [this](){
      65            9 :             reorderSections();
      66            9 :         });
      67            3 :     }
      68              : 
      69            3 :     emit inited();
      70            3 : }
      71              : 
      72            0 : void DockPageView::deinit()
      73              : {
      74            0 :     TRACEFUNC;
      75              : 
      76            0 :     for (DockBase* dock : allDocks()) {
      77            0 :         dock->disconnect(this);
      78            0 :     }
      79            0 : }
      80              : 
      81            3 : QString DockPageView::uri() const
      82              : {
      83            3 :     return m_uri;
      84              : }
      85              : 
      86            3 : void DockPageView::setParams(const QVariantMap& params)
      87              : {
      88            3 :     emit setParamsRequested(params);
      89            3 : }
      90              : 
      91            3 : QQmlListProperty<DockToolBarView> DockPageView::mainToolBarsProperty()
      92              : {
      93            3 :     return m_mainToolBars.property();
      94              : }
      95              : 
      96            0 : QQmlListProperty<DockToolBarView> DockPageView::toolBarsProperty()
      97              : {
      98            0 :     return m_toolBars.property();
      99              : }
     100              : 
     101            3 : QQmlListProperty<DockPanelView> DockPageView::panelsProperty()
     102              : {
     103            3 :     return m_panels.property();
     104              : }
     105              : 
     106            0 : QQmlListProperty<DockingHolderView> DockPageView::toolBarsDockingHoldersProperty()
     107              : {
     108            0 :     return m_toolBarsDockingHolders.property();
     109              : }
     110              : 
     111            0 : QQmlListProperty<DockingHolderView> DockPageView::panelsDockingHoldersProperty()
     112              : {
     113            0 :     return m_panelsDockingHolders.property();
     114              : }
     115              : 
     116           37 : QList<DockToolBarView*> DockPageView::mainToolBars() const
     117              : {
     118           37 :     return m_mainToolBars.list();
     119              : }
     120              : 
     121           25 : QList<DockToolBarView*> DockPageView::toolBars() const
     122              : {
     123           25 :     return m_toolBars.list();
     124              : }
     125              : 
     126            0 : QList<DockingHolderView*> DockPageView::toolBarsHolders() const
     127              : {
     128            0 :     return m_toolBarsDockingHolders.list();
     129              : }
     130              : 
     131            6 : DockCentralView* DockPageView::centralDock() const
     132              : {
     133            6 :     return m_central;
     134              : }
     135              : 
     136            6 : DockStatusBar* DockPageView::statusBar() const
     137              : {
     138            6 :     return m_statusBar;
     139              : }
     140              : 
     141           28 : QList<DockPanelView*> DockPageView::panels() const
     142              : {
     143           28 :     return m_panels.list();
     144              : }
     145              : 
     146            0 : QList<DockingHolderView*> DockPageView::panelsHolders() const
     147              : {
     148            0 :     return m_panelsDockingHolders.list();
     149              : }
     150              : 
     151            0 : DockBase* DockPageView::dockByName(const QString& dockName) const
     152              : {
     153            0 :     for (DockBase* dock : allDocks()) {
     154            0 :         if (dock->objectName() == dockName) {
     155            0 :             return dock;
     156              :         }
     157            0 :     }
     158              : 
     159            0 :     return nullptr;
     160              : }
     161              : 
     162           24 : DockingHolderView* DockPageView::holder(DockType type, Location location) const
     163              : {
     164           24 :     QList<DockingHolderView*> holders;
     165              : 
     166           24 :     if (type == DockType::ToolBar) {
     167           12 :         holders = m_toolBarsDockingHolders.list();
     168           12 :     } else if (type == DockType::Panel) {
     169           12 :         holders = m_panelsDockingHolders.list();
     170              :     }
     171              : 
     172           24 :     for (DockingHolderView* holder : holders) {
     173            0 :         if (holder->location() == location) {
     174            0 :             return holder;
     175              :         }
     176              :     }
     177              : 
     178           24 :     return nullptr;
     179           24 : }
     180              : 
     181            0 : QList<DockPanelView*> DockPageView::findPanelsForDropping(const DockPanelView* panel) const
     182              : {
     183            0 :     QList<DockPanelView*> result;
     184              : 
     185            0 :     for (DockPanelView* destinationPanel : panels()) {
     186            0 :         if (destinationPanel->isTabAllowed(panel)) {
     187            0 :             result << destinationPanel;
     188              :         }
     189            0 :     }
     190              : 
     191            0 :     return result;
     192            0 : }
     193              : 
     194            3 : DockPanelView* DockPageView::findPanelForTab(const DockPanelView* tab) const
     195              : {
     196            6 :     for (DockPanelView* destinationPanel: panels()) {
     197            3 :         if (destinationPanel->isTabAllowed(tab)
     198            3 :             && destinationPanel->location() == tab->location()) {
     199            0 :             return destinationPanel;
     200              :         }
     201            3 :     }
     202              : 
     203            3 :     return nullptr;
     204              : }
     205              : 
     206            0 : bool DockPageView::isDockOpen(const QString& dockName) const
     207              : {
     208            0 :     const DockBase* dock = dockByName(dockName);
     209            0 :     return dock && dock->isOpen();
     210              : }
     211              : 
     212            0 : void DockPageView::toggleDock(const QString& dockName)
     213              : {
     214            0 :     setDockOpen(dockName, !isDockOpen(dockName));
     215            0 : }
     216              : 
     217            0 : void DockPageView::setDockOpen(const QString& dockName, bool open)
     218              : {
     219            0 :     DockBase* dock = dockByName(dockName);
     220            0 :     if (!dock) {
     221            0 :         return;
     222              :     }
     223              : 
     224            0 :     if (!open) {
     225            0 :         dock->close();
     226            0 :         return;
     227              :     }
     228              : 
     229            0 :     DockPanelView* panel = dynamic_cast<DockPanelView*>(dock);
     230            0 :     if (!panel) {
     231            0 :         dock->open();
     232            0 :         return;
     233              :     }
     234              : 
     235            0 :     DockPanelView* destinationPanel = findPanelForTab(panel);
     236            0 :     if (destinationPanel) {
     237            0 :         destinationPanel->addPanelAsTab(panel);
     238              :     } else {
     239            0 :         panel->open();
     240              :     }
     241              : }
     242              : 
     243           12 : void DockPageView::reorderSections()
     244              : {
     245              :     //! NOTE: In some cases, such as setting visible true,
     246              :     //! it is necessary to give the UI time to render the content, so we will add a delay.
     247           12 :     QTimer::singleShot(2000, this, [this](){
     248            0 :         doReorderSections();
     249            0 :     });
     250           12 : }
     251              : 
     252            0 : void DockPageView::doReorderSections()
     253              : {
     254            0 :     TRACEFUNC;
     255              : 
     256            0 :     if (!isVisible()) {
     257            0 :         return;
     258              :     }
     259              : 
     260            0 :     QList<DockBase*> docks = allDocks();
     261            0 :     QList<DockBase*> docksAvailableForNavigation;
     262              : 
     263            0 :     for (DockBase* dock: docks) {
     264            0 :         if (dock->navigationSection() && dock->isVisible()) {
     265            0 :             docksAvailableForNavigation.append(dock);
     266              :         }
     267              :     }
     268              : 
     269            0 :     reorderDocksNavigationSections(docksAvailableForNavigation);
     270            0 : }
     271              : 
     272            0 : void DockPageView::reorderDocksNavigationSections(QList<DockBase*>& docks)
     273              : {
     274            0 :     QHash<muse::ui::INavigationSection*, QList<DockBase*> > orderedSections;
     275            0 :     for (DockBase* dock: docks) {
     276            0 :         if (ui::INavigationSection* section = dock->navigationSection()) {
     277            0 :             orderedSections[section] << dock;
     278              :         }
     279              :     }
     280              : 
     281            0 :     for (QList<DockBase*>& panels : orderedSections.values()) {
     282            0 :         reorderNavigationSectionPanels(panels);
     283            0 :     }
     284            0 : }
     285              : 
     286            0 : void DockPageView::reorderNavigationSectionPanels(QList<DockBase*>& sectionDocks)
     287              : {
     288            0 :     std::sort(sectionDocks.begin(), sectionDocks.end(), [](DockBase* dock1, DockBase* dock2) {
     289            0 :         if (!dock1->navigationSection() || !dock2->navigationSection()) {
     290            0 :             return false;
     291              :         }
     292              : 
     293            0 :         if (dock1 == dock2) {
     294            0 :             return false;
     295              :         }
     296              : 
     297            0 :         QPoint dock1Pos = dock1->globalPosition();
     298            0 :         QPoint dock2Pos = dock2->globalPosition();
     299              : 
     300            0 :         if (dock1->floating() && dock2->floating()) {
     301            0 :             return dock1Pos.x() < dock2Pos.x();
     302            0 :         } else if (dock1->floating()) {
     303            0 :             return false;
     304            0 :         } else if (dock2->floating()) {
     305            0 :             return true;
     306              :         }
     307              : 
     308            0 :         if (dock1Pos.x() == dock2Pos.x()) {
     309            0 :             return dock1Pos.y() < dock2Pos.y();
     310              :         }
     311              : 
     312            0 :         return dock1Pos.x() < dock2Pos.x();
     313              :     });
     314              : 
     315              :     //!NOTE: It is possible that the dock does not contain all the panels.
     316              :     //! For example, MainToolBar is created for the entire window and is always visible.
     317              :     //! Reserve n panels for each dock.
     318            0 :     int i = 10;
     319            0 :     QHash<DockBase*, int> orderedDocks;
     320            0 :     for (DockBase* dock: sectionDocks) {
     321              :         //!NOTE: It is possible that the dock contains multiple panels.
     322              :         //! Reserve n panels for each dock.
     323            0 :         int order = i++ *1000;
     324              : 
     325              :         //! NOTE: If a panel is inside a frame with another panel,
     326              :         //! there is no need to set the order for the frame panel, as it is already set.
     327            0 :         bool exists = false;
     328            0 :         for (DockBase* orderedPanel: orderedDocks.keys()) {
     329            0 :             if (orderedPanel->isInSameFrame(dock)) {
     330            0 :                 exists = true;
     331              :             }
     332            0 :         }
     333              : 
     334            0 :         if (!exists) {
     335            0 :             orderedDocks[dock] = order;
     336            0 :             dock->setFramePanelOrder(order);
     337              :         }
     338              : 
     339            0 :         dock->setContentNavigationPanelOrderStart(order + 1);
     340              :     }
     341            0 : }
     342              : 
     343            0 : bool DockPageView::isDockFloating(const QString& dockName) const
     344              : {
     345            0 :     const DockBase* dock = dockByName(dockName);
     346            0 :     return dock ? dock->floating() : false;
     347              : }
     348              : 
     349            0 : void DockPageView::toggleDockFloating(const QString& dockName)
     350              : {
     351            0 :     DockBase* dock = dockByName(dockName);
     352            0 :     if (!dock) {
     353            0 :         return;
     354              :     }
     355              : 
     356            0 :     dock->setFloating(!dock->floating());
     357              : }
     358              : 
     359            3 : void DockPageView::setUri(const QString& uri)
     360              : {
     361            3 :     if (uri == m_uri) {
     362            0 :         return;
     363              :     }
     364              : 
     365            3 :     m_uri = uri;
     366            3 :     emit uriChanged(uri);
     367              : }
     368              : 
     369            3 : void DockPageView::setCentralDock(DockCentralView* central)
     370              : {
     371            3 :     if (central == m_central) {
     372            0 :         return;
     373              :     }
     374              : 
     375            3 :     m_central = central;
     376            3 :     emit centralDockChanged(central);
     377              : }
     378              : 
     379            0 : void DockPageView::setStatusBar(DockStatusBar* statusBar)
     380              : {
     381            0 :     if (statusBar == m_statusBar) {
     382            0 :         return;
     383              :     }
     384              : 
     385            0 :     m_statusBar = statusBar;
     386            0 :     emit statusBarChanged(statusBar);
     387              : }
     388              : 
     389            3 : void DockPageView::componentComplete()
     390              : {
     391            3 :     QQuickItem::componentComplete();
     392              : 
     393            3 :     Q_ASSERT(!m_uri.isEmpty());
     394            3 :     Q_ASSERT(m_central != nullptr);
     395              : 
     396            3 :     connect(this, &DockPageView::visibleChanged, [this](){
     397            6 :         if (isVisible()) {
     398            3 :             reorderSections();
     399              :         }
     400            6 :     });
     401            3 : }
     402              : 
     403           19 : QList<DockBase*> DockPageView::allDocks() const
     404              : {
     405           19 :     auto mainToolBars = this->mainToolBars();
     406           19 :     auto toolbars = this->toolBars();
     407           19 :     auto panels = this->panels();
     408              : 
     409           19 :     QList<DockBase*> docks;
     410           19 :     docks << QList<DockBase*>(mainToolBars.begin(), mainToolBars.end());
     411           19 :     docks << QList<DockBase*>(toolbars.begin(), toolbars.end());
     412           19 :     docks << QList<DockBase*>(panels.begin(), panels.end());
     413              : 
     414           19 :     docks << m_central;
     415              : 
     416           19 :     if (m_statusBar) {
     417            0 :         docks << m_statusBar;
     418              :     }
     419              : 
     420           19 :     return docks;
     421           19 : }
     422              : 
     423            0 : void DockPageView::setDefaultNavigationControl(muse::ui::NavigationControl* control)
     424              : {
     425            0 :     muse::ui::INavigationControl* _control = dynamic_cast<muse::ui::INavigationControl*>(control);
     426            0 :     navigationController()->setDefaultNavigationControl(_control);
     427            0 : }
     428              : 
     429            0 : void DockPageView::forceLayout()
     430              : {
     431            0 :     emit layoutRequested();
     432            0 : }
     433              : 
     434            0 : QVariant DockPageView::tours() const
     435              : {
     436            0 :     return m_tours;
     437              : }
     438              : 
     439            0 : void DockPageView::setTours(const QVariant& newTours)
     440              : {
     441            0 :     if (m_tours == newTours) {
     442            0 :         return;
     443              :     }
     444              : 
     445            0 :     for (const QVariant& tourVar: newTours.toList()) {
     446            0 :         QVariantMap tourMap = tourVar.toMap();
     447              : 
     448            0 :         String eventCode = tourMap.value("eventCode").toString();
     449              : 
     450            0 :         QVariantMap tourInfoMap = tourMap.value("tour").toMap();
     451              : 
     452            0 :         tours::Tour tour;
     453              : 
     454            0 :         tour.id = tourInfoMap.value("id").toString();
     455              : 
     456            0 :         for (const QVariant& stepVar: tourInfoMap.value("steps").toList()) {
     457            0 :             QVariantMap stepMap = stepVar.toMap();
     458              : 
     459            0 :             tours::TourStep step;
     460            0 :             step.title = stepMap.value("title").toString();
     461            0 :             step.description = stepMap.value("description").toString();
     462            0 :             step.previewImageOrGifUrl = stepMap.value("previewImageOrGifUrl").toString();
     463            0 :             step.videoExplanationUrl = stepMap.value("videoExplanationUrl").toString();
     464            0 :             step.controlUri = Uri(stepMap.value("controlUri").toString());
     465              : 
     466            0 :             tour.steps.emplace_back(step);
     467            0 :         }
     468              : 
     469            0 :         if (!tour.steps.empty()) {
     470            0 :             toursService()->registerTour(eventCode, tour);
     471              :         }
     472            0 :     }
     473              : 
     474            0 :     m_tours = newTours;
     475            0 :     emit toursChanged();
     476              : }
        

Generated by: LCOV version 2.0-1