diff --git a/Subsurface-mobile.pro b/Subsurface-mobile.pro index a817a84d4..d7218a0c6 100644 --- a/Subsurface-mobile.pro +++ b/Subsurface-mobile.pro @@ -171,7 +171,6 @@ SOURCES += subsurface-mobile-main.cpp \ qt-models/weightsysteminfomodel.cpp \ qt-models/filterconstraintmodel.cpp \ qt-models/filterpresetmodel.cpp \ - profile-widget/qmlprofile.cpp \ profile-widget/divecartesianaxis.cpp \ profile-widget/diveeventitem.cpp \ profile-widget/divepercentageitem.cpp \ @@ -337,7 +336,6 @@ HEADERS += \ qt-models/weightsysteminfomodel.h \ qt-models/filterconstraintmodel.h \ qt-models/filterpresetmodel.h \ - profile-widget/qmlprofile.h \ profile-widget/divepercentageitem.h \ profile-widget/diveprofileitem.h \ profile-widget/profilescene.h \ diff --git a/mobile-widgets/qml/DiveDetailsView.qml b/mobile-widgets/qml/DiveDetailsView.qml index 9939e893b..283475198 100644 --- a/mobile-widgets/qml/DiveDetailsView.qml +++ b/mobile-widgets/qml/DiveDetailsView.qml @@ -231,13 +231,13 @@ Item { Layout.columnSpan: 3 clip: true - QMLProfile { + ProfileView { id: qmlProfile visible: !noDive anchors.fill: parent clip: true - property real lastScale: 1.0 // final scale at the end of previous pinch diveId: detailsView.myId + property real dpr: 0.8 // TODO: make this dynamic Rectangle { color: "transparent" opacity: 0.6 @@ -253,36 +253,20 @@ Item { // before realizing that this is actually a pinch/zoom. So let's reset this // just in case qmlProfile.opacity = 1.0 - if (manager.verboseEnabled) - manager.appendTextToLog("pinch started w/ previousScale " + qmlProfile.lastScale) + qmlProfile.pinchStart() } onPinchUpdated: { - if (pinch.scale * qmlProfile.lastScale < 1.0) - qmlProfile.lastScale = 1.0 / pinch.scale // this way we never shrink and the changes stay smooth - // the underlying widget deals with the scaling, no need to send an update request - qmlProfile.scale = pinch.scale * qmlProfile.lastScale - if (manager.verboseEnabled) - manager.appendTextToLog("pinch updated to scale " + qmlProfile.scale); - } - onPinchFinished: { - // remember the final scale value so we can continue from there next time the user pinches - qmlProfile.lastScale = pinch.scale * qmlProfile.lastScale + qmlProfile.pinch(pinch.scale) } MouseArea { // we want to pan the profile if we are zoomed in, but we want to immediately // pass the mouse events through to the ListView if we are not. That way you // can swipe through the dive list, even if you happen to swipe the profile - property bool isZoomed: qmlProfile.scale - 1.0 > 0.02 + property bool isZoomed: qmlProfile.zoomLevel > 1.02 // this indicates that we are actually dragging property bool dragging: false - // cursor/finger position as we start dragging - property real initialX - property real initialY - // the offset previously used to show the profile - property real oldXOffset - property real oldYOffset // if the profile is not scaled in, don't start panning // but if the profile is scaled in, then start almost immediately @@ -291,16 +275,6 @@ Item { // pass events through to the parent and eventually into the ListView propagateComposedEvents: true - // for testing / debugging on a desktop - scrollGestureEnabled: true - onWheel: { - manager.appendTextToLog("wheel " + wheel.angleDelta) - if (wheel.angleDelta.y > 0) - qmlProfile.scale += 0.2 - if (wheel.angleDelta.y < 0 && qmlProfile.scale > 1.1) - qmlProfile.scale -= 0.2 - } - anchors.fill: parent drag.target: qmlProfile drag.axis: Drag.XAndYAxis @@ -311,10 +285,7 @@ Item { } onPressAndHold: { dragging = true; - oldXOffset = qmlProfile.xOffset - oldYOffset = qmlProfile.yOffset - initialX = mouse.x - initialY = mouse.y + qmlProfile.panStart(mouse.x, mouse.y) if (manager.verboseEnabled) manager.appendTextToLog("press and hold at mouse" + Math.round(10 * mouse.x) / 10 + " / " + Math.round(10 * mouse.y) / 10) // give visual feedback to the user that they now can drag @@ -322,13 +293,9 @@ Item { } onPositionChanged: { if (dragging) { - var x = (mouse.x - initialX) / qmlProfile.scale - var y = (mouse.y - initialY) / qmlProfile.scale if (manager.verboseEnabled) manager.appendTextToLog("drag mouse " + Math.round(10 * mouse.x) / 10 + " / " + Math.round(10 * mouse.y) / 10 + " delta " + Math.round(x) + " / " + Math.round(y)) - qmlProfile.xOffset = oldXOffset + x - qmlProfile.yOffset = oldYOffset + y - qmlProfile.update() + qmlProfile.pan(mouse.x, mouse.y) } else { mouse.accepted = false } @@ -344,7 +311,6 @@ Item { onClicked: { // reset the position if not zoomed in if (!isZoomed) { - qmlProfile.xOffset = qmlProfile.yOffset = oldXOffset = oldYOffset = 0 mouse.accepted = false } } diff --git a/profile-widget/CMakeLists.txt b/profile-widget/CMakeLists.txt index d60185b57..9804f1189 100644 --- a/profile-widget/CMakeLists.txt +++ b/profile-widget/CMakeLists.txt @@ -32,8 +32,6 @@ set(SUBSURFACE_PROFILE_LIB_SRCS if (SUBSURFACE_TARGET_EXECUTABLE MATCHES "MobileExecutable") set(SUBSURFACE_PROFILE_LIB_SRCS ${SUBSURFACE_PROFILE_LIB_SRCS} - qmlprofile.cpp - qmlprofile.h ) else () set(SUBSURFACE_PROFILE_LIB_SRCS diff --git a/profile-widget/profileview.cpp b/profile-widget/profileview.cpp index 2f60baeab..2f1f5f6cc 100644 --- a/profile-widget/profileview.cpp +++ b/profile-widget/profileview.cpp @@ -3,6 +3,7 @@ #include "profilescene.h" #include "zvalues.h" #include "core/dive.h" +#include "core/divelog.h" #include "core/errorhelper.h" #include "core/pref.h" #include "core/settings/qPrefDisplay.h" @@ -42,17 +43,10 @@ public: } }; -static double calcZoom(int zoomLevel) -{ - // Base of exponential zoom function: one wheel-click will increase the zoom by 15%. - constexpr double zoomFactor = 1.15; - return zoomLevel == 0 ? 1.0 : pow(zoomFactor, zoomLevel); -} - ProfileView::ProfileView(QQuickItem *parent) : ChartView(parent, ProfileZValue::Count), d(nullptr), dc(0), - zoomLevel(0), + zoomLevel(1.00), zoomedPosition(0.0), panning(false), empty(true), @@ -141,7 +135,7 @@ void ProfileView::plotDive(const struct dive *dIn, int dcIn, int flags) // We can't create the scene in the constructor, because we can't get the DPR property there. Oh joy! if (!profileScene) { - double dpr = std::clamp(property("dpr").toReal(), 1.0, 100.0); + double dpr = std::clamp(property("dpr").toReal(), 0.5, 100.0); profileScene = std::make_unique(dpr, false, false); } // If there was no previously displayed dive, turn off animations @@ -162,14 +156,12 @@ void ProfileView::plotDive(const struct dive *dIn, int dcIn, int flags) DivePlannerPointsModel *model = nullptr; bool inPlanner = flags & RenderFlags::PlanMode; - double zoom = calcZoom(zoomLevel); - int animSpeed = flags & RenderFlags::Instant ? 0 : qPrefDisplay::animation_speed(); profileScene->resize(size()); profileScene->plotDive(d, dc, animSpeed, model, inPlanner, flags & RenderFlags::DontRecalculatePlotInfo, - shouldCalculateMax, zoom, zoomedPosition); + shouldCalculateMax, zoomLevel, zoomedPosition); background = inPlanner ? QColor("#D7E3EF") : getColor(::BACKGROUND, false); profileItem->draw(size(), background, *profileScene); @@ -220,14 +212,17 @@ void ProfileView::anim(double fraction) void ProfileView::resetZoom() { - zoomLevel = 0; + zoomLevel = 1.0; zoomedPosition = 0.0; } -void ProfileView::setZoom(int level) +void ProfileView::setZoom(double level) { - zoomLevel = level; - plotDive(d, dc, RenderFlags::DontRecalculatePlotInfo); + level = std::clamp(level, 1.0, 20.0); + double old = std::exchange(zoomLevel, level); + if (level != old) + plotDive(d, dc, RenderFlags::DontRecalculatePlotInfo); + emit zoomLevelChanged(); } void ProfileView::wheelEvent(QWheelEvent *event) @@ -238,13 +233,13 @@ void ProfileView::wheelEvent(QWheelEvent *event) return; // No change in zoom level while panning. if (event->buttons() == Qt::LeftButton) return; - if (event->angleDelta().y() > 0 && zoomLevel < 20) - setZoom(++zoomLevel); - else if (event->angleDelta().y() < 0 && zoomLevel > 0) - setZoom(--zoomLevel); + if (event->angleDelta().y() > 0) + setZoom(zoomLevel * 1.15); + else if (event->angleDelta().y() < 0) + setZoom(zoomLevel / 1.15); else if (event->angleDelta().x() && zoomLevel > 0) { double oldPos = zoomedPosition; - zoomedPosition = profileScene->calcZoomPosition(calcZoom(zoomLevel), + zoomedPosition = profileScene->calcZoomPosition(zoomLevel, oldPos, oldPos - event->angleDelta().x()); if (oldPos != zoomedPosition) @@ -255,8 +250,8 @@ void ProfileView::wheelEvent(QWheelEvent *event) void ProfileView::mousePressEvent(QMouseEvent *event) { panning = true; - panningOriginalMousePosition = mapToScene(event->pos()).x(); - panningOriginalProfilePosition = zoomedPosition; + QPointF pos = mapToScene(event->pos()); + panStart(pos.x(), pos.y()); setCursor(Qt::ClosedHandCursor); event->accept(); } @@ -276,14 +271,8 @@ void ProfileView::mouseReleaseEvent(QMouseEvent *) void ProfileView::mouseMoveEvent(QMouseEvent *event) { QPointF pos = mapToScene(event->pos()); - if (panning) { - double oldPos = zoomedPosition; - zoomedPosition = profileScene->calcZoomPosition(calcZoom(zoomLevel), - panningOriginalProfilePosition, - panningOriginalMousePosition - pos.x()); - if (oldPos != zoomedPosition) - plotDive(d, dc, RenderFlags::Instant | RenderFlags::DontRecalculatePlotInfo); // TODO: animations don't work when scrolling - } + if (panning) + pan(pos.x(), pos.y()); //toolTipItem->refresh(d, mapToScene(mapFromGlobal(QCursor::pos())), currentState == PLAN); @@ -296,3 +285,65 @@ void ProfileView::mouseMoveEvent(QMouseEvent *event) //mouseFollowerVertical->setLine(x, rect.top(), x, rect.bottom()); //} } + +int ProfileView::getDiveId() const +{ + return d ? d->id : -1; +} + +void ProfileView::setDiveId(int id) +{ + plotDive(divelog.dives.get_by_uniq_id(id), 0); +} + +int ProfileView::numDC() const +{ + return d ? d->number_of_computers() : 0; +} + +void ProfileView::pinchStart() +{ + zoomLevelPinchStart = zoomLevel; +} + +void ProfileView::pinch(double factor) +{ + setZoom(zoomLevelPinchStart * factor); +} + +void ProfileView::nextDC() +{ + rotateDC(1); +} + +void ProfileView::prevDC() +{ + rotateDC(-1); +} + +void ProfileView::rotateDC(int dir) +{ + int num = numDC(); + if (num <= 1) + return; + dc = (dc + dir) % num; + if (dc < 0) + dc += num; + replot(); +} + +void ProfileView::panStart(double x, double y) +{ + panningOriginalMousePosition = x; + panningOriginalProfilePosition = zoomedPosition; +} + +void ProfileView::pan(double x, double y) +{ + double oldPos = zoomedPosition; + zoomedPosition = profileScene->calcZoomPosition(zoomLevel, + panningOriginalProfilePosition, + panningOriginalMousePosition - x); + if (oldPos != zoomedPosition) + plotDive(d, dc, RenderFlags::Instant | RenderFlags::DontRecalculatePlotInfo); // TODO: animations don't work when scrolling +} diff --git a/profile-widget/profileview.h b/profile-widget/profileview.h index 2adfb9969..cc5ce255c 100644 --- a/profile-widget/profileview.h +++ b/profile-widget/profileview.h @@ -11,6 +11,11 @@ class ProfileScene; class ProfileView : public ChartView { Q_OBJECT + + // Communication with the mobile interface is via properties. I hate it. + Q_PROPERTY(int diveId READ getDiveId WRITE setDiveId) + Q_PROPERTY(int numDC READ numDC NOTIFY numDCChanged) + Q_PROPERTY(double zoomLevel MEMBER zoomLevel NOTIFY zoomLevelChanged) public: ProfileView(); ProfileView(QQuickItem *parent); @@ -28,10 +33,21 @@ public: void clear(); void resetZoom(); void anim(double fraction); + + // For mobile + Q_INVOKABLE void pinchStart(); + Q_INVOKABLE void pinch(double factor); + Q_INVOKABLE void nextDC(); + Q_INVOKABLE void prevDC(); + Q_INVOKABLE void panStart(double x, double y); + Q_INVOKABLE void pan(double x, double y); +signals: + void numDCChanged(); + void zoomLevelChanged(); private: const struct dive *d; int dc; - int zoomLevel; + double zoomLevel, zoomLevelPinchStart; double zoomedPosition; // Position when zoomed: 0.0 = beginning, 1.0 = end. bool panning; // Currently panning. double panningOriginalMousePosition; @@ -46,12 +62,18 @@ private: void plotAreaChanged(const QSizeF &size) override; void resetPointers() override; void replot(); - void setZoom(int level); + void setZoom(double level); void wheelEvent(QWheelEvent *event) override; void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; + + // For mobile + int getDiveId() const; + void setDiveId(int id); + int numDC() const; + void rotateDC(int dir); }; #endif diff --git a/profile-widget/qmlprofile.cpp b/profile-widget/qmlprofile.cpp deleted file mode 100644 index f82ba188f..000000000 --- a/profile-widget/qmlprofile.cpp +++ /dev/null @@ -1,163 +0,0 @@ -// SPDX-License-Identifier: GPL-2. -#include "qmlprofile.h" -#include "profilescene.h" -#include "mobile-widgets/qmlmanager.h" -#include "core/divelist.h" -#include "core/errorhelper.h" -#include "core/subsurface-float.h" -#include "core/metrics.h" -#include "core/subsurface-string.h" -#include -#include -#include - -QMLProfile::QMLProfile(QQuickItem *parent) : - QQuickPaintedItem(parent), - m_diveId(0), - m_dc(0), - m_devicePixelRatio(1.0), - m_margin(0), - m_xOffset(0.0), - m_yOffset(0.0) -{ - createProfileView(); - setAntialiasing(true); - setFlags(QQuickItem::ItemClipsChildrenToShape | QQuickItem::ItemHasContents ); - connect(QMLManager::instance(), &QMLManager::sendScreenChanged, this, &QMLProfile::screenChanged); - connect(this, &QMLProfile::scaleChanged, this, &QMLProfile::triggerUpdate); - connect(&diveListNotifier, &DiveListNotifier::divesChanged, this, &QMLProfile::divesChanged); - setDevicePixelRatio(QMLManager::instance()->lastDevicePixelRatio()); -} - -QMLProfile::~QMLProfile() -{ -} - -void QMLProfile::createProfileView() -{ - m_profileWidget.reset(new ProfileScene(m_devicePixelRatio * 0.8, false, false)); -} - -// we need this so we can connect update() to the scaleChanged() signal - which the connect above cannot do -// directly as it chokes on the default parameter for update(). -// If the scale changes we may need to change our offsets to ensure that we still only show a subset of -// the profile and not empty space around it, which the paint() method below will take care of, which will -// eventually get called after we call update() -void QMLProfile::triggerUpdate() -{ - update(); -} - -void QMLProfile::paint(QPainter *painter) -{ - QElapsedTimer timer; - if (verbose) - timer.start(); - - // let's look at the intended size of the content and scale our scene accordingly - // for some odd reason the painter transformation is set up to scale by the dpr - which results - // in applying that dpr scaling twice. So we hard-code it here to be the identity matrix - QRect painterRect = painter->viewport(); - painter->resetTransform(); - if (m_diveId < 0) - return; - struct dive *d = divelog.dives.get_by_uniq_id(m_diveId); - if (!d) - return; - m_profileWidget->draw(painter, painterRect, d, m_dc, nullptr, false); -} - -void QMLProfile::setMargin(int margin) -{ - m_margin = margin; -} - -int QMLProfile::diveId() const -{ - return m_diveId; -} - -void QMLProfile::setDiveId(int diveId) -{ - m_diveId = diveId; - emit numDCChanged(); -} - -qreal QMLProfile::devicePixelRatio() const -{ - return m_devicePixelRatio; -} - -void QMLProfile::setDevicePixelRatio(qreal dpr) -{ - if (dpr != m_devicePixelRatio) { - m_devicePixelRatio = dpr; - // Recreate the view to redraw the text items with the new scale. - createProfileView(); - emit devicePixelRatioChanged(); - } -} - -// don't update the profile here, have the user update x and y and then manually trigger an update -void QMLProfile::setXOffset(qreal value) -{ - if (nearly_equal(value, m_xOffset)) - return; - m_xOffset = value; - emit xOffsetChanged(); -} - -// don't update the profile here, have the user update x and y and then manually trigger an update -void QMLProfile::setYOffset(qreal value) -{ - if (nearly_equal(value, m_yOffset)) - return; - m_yOffset = value; - emit yOffsetChanged(); -} - -void QMLProfile::screenChanged(QScreen *screen) -{ - setDevicePixelRatio(screen->devicePixelRatio()); -} - -void QMLProfile::divesChanged(const QVector &dives, DiveField) -{ - for (struct dive *d: dives) { - if (d->id == m_diveId) { - report_info("dive #%d changed, trigger profile update", d->number); - triggerUpdate(); - return; - } - } -} - -void QMLProfile::nextDC() -{ - rotateDC(1); -} - -void QMLProfile::prevDC() -{ - rotateDC(-1); -} - -void QMLProfile::rotateDC(int dir) -{ - struct dive *d = divelog.dives.get_by_uniq_id(m_diveId); - if (!d) - return; - int numDC = d->number_of_computers(); - if (numDC == 1) - return; - m_dc = (m_dc + dir) % numDC; - if (m_dc < 0) - m_dc += numDC; - triggerUpdate(); -} - -int QMLProfile::numDC() const -{ - struct dive *d = divelog.dives.get_by_uniq_id(m_diveId); - return d ? d->number_of_computers() : 0; -} diff --git a/profile-widget/qmlprofile.h b/profile-widget/qmlprofile.h deleted file mode 100644 index ddff67f1f..000000000 --- a/profile-widget/qmlprofile.h +++ /dev/null @@ -1,62 +0,0 @@ -// SPDX-License-Identifier: GPL-2.0 -#ifndef QMLPROFILE_H -#define QMLPROFILE_H - -#include "core/subsurface-qt/divelistnotifier.h" -#include -#include - -class ProfileScene; - -class QMLProfile : public QQuickPaintedItem -{ - Q_OBJECT - Q_PROPERTY(int diveId MEMBER m_diveId WRITE setDiveId) - Q_PROPERTY(int numDC READ numDC NOTIFY numDCChanged) - Q_PROPERTY(qreal devicePixelRatio READ devicePixelRatio WRITE setDevicePixelRatio NOTIFY devicePixelRatioChanged) - Q_PROPERTY(qreal xOffset MEMBER m_xOffset WRITE setXOffset NOTIFY xOffsetChanged) - Q_PROPERTY(qreal yOffset MEMBER m_yOffset WRITE setYOffset NOTIFY yOffsetChanged) - -public: - explicit QMLProfile(QQuickItem *parent = 0); - ~QMLProfile(); - - void paint(QPainter *painter); - - int diveId() const; - void setDiveId(int diveId); - qreal devicePixelRatio() const; - void setDevicePixelRatio(qreal dpr); - void setXOffset(qreal value); - void setYOffset(qreal value); - Q_INVOKABLE void nextDC(); - Q_INVOKABLE void prevDC(); - -public slots: - void setMargin(int margin); - void screenChanged(QScreen *screen); - void triggerUpdate(); - -private: - int m_diveId; - int m_dc; - qreal m_devicePixelRatio; - int m_margin; - qreal m_xOffset, m_yOffset; - std::unique_ptr m_profileWidget; - void createProfileView(); - void rotateDC(int dir); - int numDC() const; - -private slots: - void divesChanged(const QVector &dives, DiveField); - -signals: - void rightAlignedChanged(); - void devicePixelRatioChanged(); - void xOffsetChanged(); - void yOffsetChanged(); - void numDCChanged(); -}; - -#endif // QMLPROFILE_H diff --git a/qt-quick/chartview.cpp b/qt-quick/chartview.cpp index 6a4e66f90..aae8991d2 100644 --- a/qt-quick/chartview.cpp +++ b/qt-quick/chartview.cpp @@ -13,10 +13,6 @@ ChartView::ChartView(QQuickItem *parent, size_t maxZ) : QQuickItem(parent), setFlag(ItemHasContents, true); } -ChartView::~ChartView() -{ -} - // Define a hideable dummy QSG node that is used as a parent node to make // all objects of a z-level visible / invisible. using ZNode = HideableQSGNode; @@ -24,22 +20,22 @@ using ZNode = HideableQSGNode; class RootNode : public QSGNode { public: - RootNode(ChartView &view, QColor backgroundColor, size_t maxZ); + RootNode(ChartView *view, QColor backgroundColor, size_t maxZ); ~RootNode(); - ChartView &view; + ChartView *view; std::unique_ptr backgroundNode; // solid background // We entertain one node per Z-level. std::vector> zNodes; }; -RootNode::RootNode(ChartView &view, QColor backgroundColor, size_t maxZ) : view(view) +RootNode::RootNode(ChartView *view, QColor backgroundColor, size_t maxZ) : view(view) { zNodes.resize(maxZ); // Add a background rectangle with a solid color. This could // also be done on the widget level, but would have to be done // separately for desktop and mobile, so do it here. - backgroundNode.reset(view.w()->createRectangleNode()); + backgroundNode.reset(view->w()->createRectangleNode()); appendChildNode(backgroundNode.get()); for (auto &zNode: zNodes) { @@ -50,7 +46,16 @@ RootNode::RootNode(ChartView &view, QColor backgroundColor, size_t maxZ) : view( RootNode::~RootNode() { - view.emergencyShutdown(); + if (view) + view->emergencyShutdown(); +} + +ChartView::~ChartView() +{ + // Sometimes the rootNode is destructed before the view, + // sometimes the other way around. QtQuick is a mess! + if (rootNode) + rootNode->view = nullptr; } void ChartView::freeDeletedChartItems() @@ -69,7 +74,7 @@ QSGNode *ChartView::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNod // This is just a copy of what is found in Qt's documentation. RootNode *n = static_cast(oldNode); if (!n) - n = rootNode = new RootNode(*this, backgroundColor, maxZ); + n = rootNode = new RootNode(this, backgroundColor, maxZ); // Delete all chart items that are marked for deletion. freeDeletedChartItems(); @@ -93,7 +98,7 @@ QSGNode *ChartView::updatePaintNode(QSGNode *oldNode, QQuickItem::UpdatePaintNod // permission to do so! If the widget is reused, we try to delete the // stale items, whose nodes have already been deleted by QtQuick, leading // to a double-free(). Instead of searching for the cause of this behavior, -// let's just hook into the rootNodes destructor and delete the objects +// let's just hook into the rootNode's destructor and delete the objects // in a controlled manner, so that QtQuick has no more access to them. void ChartView::emergencyShutdown() { diff --git a/subsurface-helper.cpp b/subsurface-helper.cpp index 5da07f798..cd804bc3c 100644 --- a/subsurface-helper.cpp +++ b/subsurface-helper.cpp @@ -27,7 +27,6 @@ #include "qt-models/divesummarymodel.h" #include "qt-models/messagehandlermodel.h" #include "qt-models/mobilelistmodel.h" -#include "profile-widget/qmlprofile.h" #include "core/downloadfromdcthread.h" #include "core/subsurfacestartup.h" // for testqml #include "core/metrics.h" @@ -220,7 +219,6 @@ static void register_qml_types(QQmlEngine *engine) #ifdef SUBSURFACE_MOBILE register_qml_type("QMLManager"); register_qml_type("StatsManager"); - register_qml_type("QMLProfile"); register_qml_type("DCImportModel"); register_qml_type("DiveSummaryModel"); register_qml_type("ChartListModel");