From 177f9d385c8cd062c4bad78cf6b794a96fa025ad Mon Sep 17 00:00:00 2001 From: Miikka Heikkinen Date: Tue, 21 Jan 2014 08:55:03 +0200 Subject: Selection correction for scatter when data changes MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Implements item 3) in QTRD-2645 Task-number: QTRD-264 Change-Id: Ibe758bbfb3b4a74b55589a410b402bbdf07ea64f Reviewed-by: Tomi Korpipää --- .../engine/abstract3dcontroller.cpp | 12 ++-- .../engine/abstract3dcontroller_p.h | 3 +- src/datavisualization/engine/bars3dcontroller.cpp | 29 +++++---- .../engine/scatter3dcontroller.cpp | 73 +++++++++++++++++----- .../engine/scatter3dcontroller_p.h | 27 ++++++++ .../engine/surface3dcontroller.cpp | 21 +++---- 6 files changed, 120 insertions(+), 45 deletions(-) (limited to 'src/datavisualization/engine') diff --git a/src/datavisualization/engine/abstract3dcontroller.cpp b/src/datavisualization/engine/abstract3dcontroller.cpp index 9942a2fe..1efbea8d 100644 --- a/src/datavisualization/engine/abstract3dcontroller.cpp +++ b/src/datavisualization/engine/abstract3dcontroller.cpp @@ -30,6 +30,7 @@ #include "qabstract3dseries_p.h" #include "thememanager_p.h" #include "q3dscene_p.h" +#include "q3dscene.h" #include @@ -147,9 +148,7 @@ QList Abstract3DController::seriesList() */ void Abstract3DController::synchDataToRenderer() { - // If we don't have a renderer, don't do anything - if (!m_renderer) - return; + // Subclass implementations check for renderer validity already, so no need to check here. // If there is a pending click from renderer, handle that first. if (m_renderer->isClickPending()) { @@ -157,7 +156,7 @@ void Abstract3DController::synchDataToRenderer() m_renderer->clearClickPending(); } - // TODO: start recording inserts/removals + startRecordingRemovesAndInserts(); if (m_scene->d_ptr->m_sceneDirty) m_renderer->updateScene(m_scene); @@ -1016,6 +1015,11 @@ QCategory3DAxis *Abstract3DController::createDefaultCategoryAxis() return defaultAxis; } +void Abstract3DController::startRecordingRemovesAndInserts() +{ + // Default implementation does nothing +} + void Abstract3DController::emitNeedRender() { if (!m_renderPending) { diff --git a/src/datavisualization/engine/abstract3dcontroller_p.h b/src/datavisualization/engine/abstract3dcontroller_p.h index 17c1e1fb..0b89251d 100644 --- a/src/datavisualization/engine/abstract3dcontroller_p.h +++ b/src/datavisualization/engine/abstract3dcontroller_p.h @@ -138,9 +138,9 @@ private: ThemeManager *m_themeManager; QAbstract3DGraph::SelectionFlags m_selectionMode; QAbstract3DGraph::ShadowQuality m_shadowQuality; - Q3DScene *m_scene; protected: + Q3DScene *m_scene; QList m_inputHandlers; // List of all added input handlers QAbstract3DInputHandler *m_activeInputHandler; CameraHelper *m_cameraHelper; @@ -273,6 +273,7 @@ protected: virtual QAbstract3DAxis *createDefaultAxis(QAbstract3DAxis::AxisOrientation orientation); QValue3DAxis *createDefaultValueAxis(); QCategory3DAxis *createDefaultCategoryAxis(); + virtual void startRecordingRemovesAndInserts(); private: void setAxisHelper(QAbstract3DAxis::AxisOrientation orientation, QAbstract3DAxis *axis, diff --git a/src/datavisualization/engine/bars3dcontroller.cpp b/src/datavisualization/engine/bars3dcontroller.cpp index d85e474c..b0627377 100644 --- a/src/datavisualization/engine/bars3dcontroller.cpp +++ b/src/datavisualization/engine/bars3dcontroller.cpp @@ -70,6 +70,9 @@ void Bars3DController::initializeOpenGL() void Bars3DController::synchDataToRenderer() { + if (!isInitialized()) + return; + // Background change requires reloading the meshes in bar graphs, so dirty the series visuals if (m_themeManager->activeTheme()->d_ptr->m_dirtyBits.backgroundEnabledDirty) { m_isSeriesVisualsDirty = true; @@ -79,9 +82,6 @@ void Bars3DController::synchDataToRenderer() Abstract3DController::synchDataToRenderer(); - if (!isInitialized()) - return; - // Notify changes to renderer if (m_changeTracker.barSpecsChanged) { m_renderer->updateBarSpecs(m_barThicknessRatio, m_barSpacing, m_isBarSpecRelative); @@ -135,12 +135,8 @@ void Bars3DController::handleRowsRemoved(int startIndex, int count) { Q_UNUSED(startIndex) Q_UNUSED(count) - QBar3DSeries *series = static_cast(sender())->series(); - if (series->isVisible()) { - adjustAxisRanges(); - m_isDataDirty = true; - } + QBar3DSeries *series = static_cast(sender())->series(); if (series == m_selectedBarSeries) { // If rows removed from selected series before the selection, adjust the selection int selectedRow = m_selectedBar.x(); @@ -154,6 +150,11 @@ void Bars3DController::handleRowsRemoved(int startIndex, int count) } } + if (series->isVisible()) { + adjustAxisRanges(); + m_isDataDirty = true; + } + emitNeedRender(); } @@ -162,11 +163,6 @@ void Bars3DController::handleRowsInserted(int startIndex, int count) Q_UNUSED(startIndex) Q_UNUSED(count) QBar3DSeries *series = static_cast(sender())->series(); - if (series->isVisible()) { - adjustAxisRanges(); - m_isDataDirty = true; - } - if (series == m_selectedBarSeries) { // If rows inserted to selected series before the selection, adjust the selection int selectedRow = m_selectedBar.x(); @@ -176,6 +172,11 @@ void Bars3DController::handleRowsInserted(int startIndex, int count) } } + if (series->isVisible()) { + adjustAxisRanges(); + m_isDataDirty = true; + } + emitNeedRender(); } @@ -244,8 +245,6 @@ void Bars3DController::handlePendingClick() QPoint position = m_renderer->clickedPosition(); QBar3DSeries *series = static_cast(m_renderer->clickedSeries()); - // TODO: Adjust position according to inserts/removes in the series - setSelectedBar(position, series); m_renderer->resetClickedStatus(); diff --git a/src/datavisualization/engine/scatter3dcontroller.cpp b/src/datavisualization/engine/scatter3dcontroller.cpp index 4527ac2a..6aa10a11 100644 --- a/src/datavisualization/engine/scatter3dcontroller.cpp +++ b/src/datavisualization/engine/scatter3dcontroller.cpp @@ -29,11 +29,14 @@ QT_BEGIN_NAMESPACE_DATAVISUALIZATION +static const int insertRemoveRecordReserveSize = 31; + Scatter3DController::Scatter3DController(QRect boundRect, Q3DScene *scene) : Abstract3DController(boundRect, scene), m_renderer(0), m_selectedItem(invalidSelectionIndex()), - m_selectedItemSeries(0) + m_selectedItemSeries(0), + m_recordInsertsAndRemoves(false) { // Setting a null axis creates a new default axis according to orientation and graph type. // Note: These cannot be set in Abstract3DController constructor, as they will call virtual @@ -62,11 +65,11 @@ void Scatter3DController::initializeOpenGL() void Scatter3DController::synchDataToRenderer() { - Abstract3DController::synchDataToRenderer(); - if (!isInitialized()) return; + Abstract3DController::synchDataToRenderer(); + // Notify changes to renderer if (m_changeTracker.selectedItemChanged) { m_renderer->updateSelectedItem(m_selectedItem, m_selectedItemSeries); @@ -157,11 +160,6 @@ void Scatter3DController::handleItemsRemoved(int startIndex, int count) Q_UNUSED(count) // TODO should dirty only affected values? QScatter3DSeries *series = static_cast(sender())->series(); - if (series->isVisible()) { - adjustValueAxisRange(); - m_isDataDirty = true; - } - if (series == m_selectedItemSeries) { // If items removed from selected series before the selection, adjust the selection int selectedItem = m_selectedItem; @@ -175,6 +173,16 @@ void Scatter3DController::handleItemsRemoved(int startIndex, int count) } } + if (series->isVisible()) { + adjustValueAxisRange(); + m_isDataDirty = true; + } + + if (m_recordInsertsAndRemoves) { + InsertRemoveRecord record(false, startIndex, count, series); + m_insertRemoveRecords.append(record); + } + emitNeedRender(); } @@ -184,11 +192,6 @@ void Scatter3DController::handleItemsInserted(int startIndex, int count) Q_UNUSED(count) // TODO should dirty only affected values? QScatter3DSeries *series = static_cast(sender())->series(); - if (series->isVisible()) { - adjustValueAxisRange(); - m_isDataDirty = true; - } - if (series == m_selectedItemSeries) { // If items inserted to selected series before the selection, adjust the selection int selectedItem = m_selectedItem; @@ -198,9 +201,33 @@ void Scatter3DController::handleItemsInserted(int startIndex, int count) } } + if (series->isVisible()) { + adjustValueAxisRange(); + m_isDataDirty = true; + } + + if (m_recordInsertsAndRemoves) { + InsertRemoveRecord record(true, startIndex, count, series); + m_insertRemoveRecords.append(record); + } + emitNeedRender(); } +void Scatter3DController::startRecordingRemovesAndInserts() +{ + m_recordInsertsAndRemoves = false; + + if (m_scene->selectionQueryPosition() != Q3DScene::invalidSelectionPoint()) { + m_recordInsertsAndRemoves = true; + if (m_insertRemoveRecords.size()) { + m_insertRemoveRecords.clear(); + // Reserve some space for remove/insert records to avoid unnecessary reallocations. + m_insertRemoveRecords.reserve(insertRemoveRecordReserveSize); + } + } +} + void Scatter3DController::handleAxisAutoAdjustRangeChangedInOrientation( QAbstract3DAxis::AxisOrientation orientation, bool autoAdjust) { @@ -229,7 +256,25 @@ void Scatter3DController::handlePendingClick() int index = m_renderer->clickedIndex(); QScatter3DSeries *series = static_cast(m_renderer->clickedSeries()); - // TODO: Adjust position according to inserts/removes in the series + // Adjust position according to recorded events + int recordCount = m_insertRemoveRecords.size(); + if (recordCount) { + for (int i = 0; i < recordCount; i++) { + const InsertRemoveRecord &record = m_insertRemoveRecords.at(i); + if (series == record.m_series && record.m_startIndex <= index) { + if (record.m_isInsert) { + index += record.m_count; + } else { + if ((record.m_startIndex + record.m_count) > index) { + index = -1; // Selected row removed + break; + } else { + index -= record.m_count; // Move selected item down by amount of items removed + } + } + } + } + } setSelectedItem(index, series); diff --git a/src/datavisualization/engine/scatter3dcontroller_p.h b/src/datavisualization/engine/scatter3dcontroller_p.h index 35f4015d..2e9ade44 100644 --- a/src/datavisualization/engine/scatter3dcontroller_p.h +++ b/src/datavisualization/engine/scatter3dcontroller_p.h @@ -62,6 +62,30 @@ private: QScatter3DSeries *m_selectedItemSeries; // Points to the series for which the bar is selected // in single series selection cases. + struct InsertRemoveRecord { + bool m_isInsert; + int m_startIndex; + int m_count; + QAbstract3DSeries *m_series; + + InsertRemoveRecord() : + m_isInsert(false), + m_startIndex(0), + m_count(0), + m_series(0) + {} + + InsertRemoveRecord(bool isInsert, int startIndex, int count, QAbstract3DSeries *series) : + m_isInsert(isInsert), + m_startIndex(startIndex), + m_count(count), + m_series(series) + {} + }; + + QVector m_insertRemoveRecords; + bool m_recordInsertsAndRemoves; + public: explicit Scatter3DController(QRect rect, Q3DScene *scene = 0); ~Scatter3DController(); @@ -93,6 +117,9 @@ public slots: void handleItemsRemoved(int startIndex, int count); void handleItemsInserted(int startIndex, int count); +protected: + virtual void startRecordingRemovesAndInserts(); + private: void adjustValueAxisRange(); diff --git a/src/datavisualization/engine/surface3dcontroller.cpp b/src/datavisualization/engine/surface3dcontroller.cpp index 984f65ba..f0dac44b 100644 --- a/src/datavisualization/engine/surface3dcontroller.cpp +++ b/src/datavisualization/engine/surface3dcontroller.cpp @@ -59,7 +59,6 @@ void Surface3DController::initializeOpenGL() m_renderer = new Surface3DRenderer(this); setRenderer(m_renderer); - synchDataToRenderer(); emitNeedRender(); } @@ -388,11 +387,6 @@ void Surface3DController::handleRowsInserted(int startIndex, int count) Q_UNUSED(startIndex) Q_UNUSED(count) QSurface3DSeries *series = static_cast(sender())->series(); - if (series->isVisible()) { - adjustValueAxisRange(); - m_isDataDirty = true; - } - if (series == m_selectedSeries) { // If rows inserted to selected series before the selection, adjust the selection int selectedRow = m_selectedPoint.x(); @@ -402,6 +396,11 @@ void Surface3DController::handleRowsInserted(int startIndex, int count) } } + if (series->isVisible()) { + adjustValueAxisRange(); + m_isDataDirty = true; + } + emitNeedRender(); } @@ -410,11 +409,6 @@ void Surface3DController::handleRowsRemoved(int startIndex, int count) Q_UNUSED(startIndex) Q_UNUSED(count) QSurface3DSeries *series = static_cast(sender())->series(); - if (series->isVisible()) { - adjustValueAxisRange(); - m_isDataDirty = true; - } - if (series == m_selectedSeries) { // If rows removed from selected series before the selection, adjust the selection int selectedRow = m_selectedPoint.x(); @@ -428,6 +422,11 @@ void Surface3DController::handleRowsRemoved(int startIndex, int count) } } + if (series->isVisible()) { + adjustValueAxisRange(); + m_isDataDirty = true; + } + emitNeedRender(); } -- cgit v1.2.3