Skip to content

Commit 34be71e

Browse files
committed
fix #140: Optimize list monitors
1 parent 958346c commit 34be71e

7 files changed

+135
-25
lines changed

src/internal/ListMonitor.qml

+20
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ Rectangle {
7777
ListView {
7878
property real oldContentY
7979
readonly property int scrollBarWidth: 15
80+
property int itemHeight: 24 // NOTE: Hard-coded value
8081

8182
id: listView
8283
anchors.left: parent.left
@@ -87,6 +88,25 @@ Rectangle {
8788
clip: true
8889
model: root.model ? root.model.listModel : null
8990
boundsBehavior: Flickable.StopAtBounds
91+
onContentXChanged: updateVisibleIndexRange()
92+
onContentYChanged: updateVisibleIndexRange()
93+
onCountChanged: updateVisibleIndexRange()
94+
95+
function getVisibleIndexRange() {
96+
if(count === 0)
97+
return [0, 0];
98+
99+
let y1 = listView.contentY - itemHeight;
100+
let y2 = listView.contentY + listView.height;
101+
return [Math.max(0, Math.ceil(y1 / itemHeight)),
102+
Math.min(Math.floor(y2 / itemHeight), count - 1)];
103+
}
104+
105+
function updateVisibleIndexRange() {
106+
let range = getVisibleIndexRange();
107+
root.model.minIndex = range[0];
108+
root.model.maxIndex = range[1];
109+
}
90110

91111
ScrollBar.vertical: ScrollBar {
92112
id: scrollBar

src/listmonitorlistmodel.cpp

+8-7
Original file line numberDiff line numberDiff line change
@@ -11,11 +11,14 @@ ListMonitorListModel::ListMonitorListModel(QObject *parent) :
1111
{
1212
}
1313

14-
void ListMonitorListModel::setList(libscratchcpp::List *list)
14+
void ListMonitorListModel::setList(libscratchcpp::List *list, size_t minVisibleIndex, size_t maxVisibleIndex)
1515
{
1616
if (!list)
1717
return;
1818

19+
m_minIndex = minVisibleIndex;
20+
m_maxIndex = maxVisibleIndex;
21+
1922
// Initial load
2023
if (m_list != list) {
2124
beginResetModel();
@@ -25,10 +28,8 @@ void ListMonitorListModel::setList(libscratchcpp::List *list)
2528
return;
2629
}
2730

28-
// Notify about changed items
29-
int count = std::min(m_oldRowCount, static_cast<int>(m_list->size()));
30-
31-
for (int i = 0; i < count; i++)
31+
// Update visible items
32+
for (size_t i = minVisibleIndex; i <= maxVisibleIndex; i++)
3233
emit dataChanged(index(i), index(i));
3334

3435
// Notify about new items (at the end of the list)
@@ -54,8 +55,8 @@ int ListMonitorListModel::rowCount(const QModelIndex &parent) const
5455

5556
QVariant ListMonitorListModel::data(const QModelIndex &index, int role) const
5657
{
57-
if (!m_list || index.row() < 0 || index.row() >= m_list->size())
58-
return QVariant();
58+
if (!m_list || index.row() < m_minIndex || index.row() > m_maxIndex)
59+
return "";
5960

6061
return QString::fromStdString(libscratchcpp::Value((*m_list)[index.row()]).toString());
6162
}

src/listmonitorlistmodel.h

+4-2
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,17 @@ class ListMonitorListModel : public QAbstractListModel
1919
public:
2020
explicit ListMonitorListModel(QObject *parent = nullptr);
2121

22-
void setList(libscratchcpp::List *list);
22+
void setList(libscratchcpp::List *list, size_t minVisibleIndex, size_t maxVisibleIndex);
2323

2424
int rowCount(const QModelIndex &parent) const override;
2525
QVariant data(const QModelIndex &index, int role) const override;
2626
QHash<int, QByteArray> roleNames() const override;
2727

2828
private:
2929
libscratchcpp::List *m_list = nullptr;
30-
int m_oldRowCount = 0;
30+
size_t m_oldRowCount = 0;
31+
size_t m_minIndex = 0;
32+
size_t m_maxIndex = 0;
3133
};
3234

3335
} // namespace scratchcpprender

src/listmonitormodel.cpp

+29-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ void ListMonitorModel::onValueChanged(const libscratchcpp::VirtualMachine *vm)
2323
if (vm->registerCount() == 1) {
2424
long index = vm->getInput(0, 1)->toLong();
2525
libscratchcpp::List *list = vm->lists()[index];
26-
m_listModel->setList(list);
26+
m_listModel->setList(list, m_minIndex, m_maxIndex);
2727
}
2828
}
2929

@@ -36,3 +36,31 @@ ListMonitorListModel *ListMonitorModel::listModel() const
3636
{
3737
return m_listModel;
3838
}
39+
40+
size_t ListMonitorModel::minIndex() const
41+
{
42+
return m_minIndex;
43+
}
44+
45+
void ListMonitorModel::setMinIndex(size_t newMinIndex)
46+
{
47+
if (m_minIndex == newMinIndex)
48+
return;
49+
50+
m_minIndex = newMinIndex;
51+
emit minIndexChanged();
52+
}
53+
54+
size_t ListMonitorModel::maxIndex() const
55+
{
56+
return m_maxIndex;
57+
}
58+
59+
void ListMonitorModel::setMaxIndex(size_t newMaxIndex)
60+
{
61+
if (m_maxIndex == newMaxIndex)
62+
return;
63+
64+
m_maxIndex = newMaxIndex;
65+
emit maxIndexChanged();
66+
}

src/listmonitormodel.h

+12
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ class ListMonitorModel : public MonitorModel
1818
Q_OBJECT
1919
QML_ELEMENT
2020
Q_PROPERTY(ListMonitorListModel *listModel READ listModel NOTIFY listModelChanged)
21+
Q_PROPERTY(size_t minIndex READ minIndex WRITE setMinIndex NOTIFY minIndexChanged FINAL);
22+
Q_PROPERTY(size_t maxIndex READ maxIndex WRITE setMaxIndex NOTIFY maxIndexChanged FINAL)
2123

2224
public:
2325
ListMonitorModel(QObject *parent = nullptr);
@@ -29,12 +31,22 @@ class ListMonitorModel : public MonitorModel
2931

3032
ListMonitorListModel *listModel() const;
3133

34+
size_t minIndex() const;
35+
void setMinIndex(size_t newMinIndex);
36+
37+
size_t maxIndex() const;
38+
void setMaxIndex(size_t newMaxIndex);
39+
3240
signals:
3341
void colorChanged();
3442
void listModelChanged();
43+
void minIndexChanged();
44+
void maxIndexChanged();
3545

3646
private:
3747
ListMonitorListModel *m_listModel = nullptr;
48+
size_t m_minIndex = 0;
49+
size_t m_maxIndex = 0;
3850
};
3951

4052
} // namespace scratchcpprender

test/monitor_models/listmonitorlistmodel_test.cpp

+26-15
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,9 @@ TEST(ListMonitorListModelTest, LoadData)
2828
List list1("", "");
2929
list1.append(1);
3030
list1.append(2);
31-
model.setList(&list1);
31+
list1.append(3);
32+
list1.append(4);
33+
model.setList(&list1, 0, 3);
3234
ASSERT_TRUE(dataChangedSpy.empty());
3335
ASSERT_EQ(aboutToResetSpy.count(), 1);
3436
ASSERT_EQ(resetSpy.count(), 1);
@@ -37,8 +39,17 @@ TEST(ListMonitorListModelTest, LoadData)
3739
ASSERT_TRUE(aboutToRemoveSpy.empty());
3840
ASSERT_TRUE(removeSpy.empty());
3941

40-
model.setList(&list1);
41-
ASSERT_EQ(dataChangedSpy.count(), 2);
42+
model.setList(&list1, 0, 3);
43+
ASSERT_EQ(dataChangedSpy.count(), 4);
44+
ASSERT_EQ(aboutToResetSpy.count(), 1);
45+
ASSERT_EQ(resetSpy.count(), 1);
46+
ASSERT_TRUE(aboutToInsertSpy.empty());
47+
ASSERT_TRUE(insertSpy.empty());
48+
ASSERT_TRUE(aboutToRemoveSpy.empty());
49+
ASSERT_TRUE(removeSpy.empty());
50+
51+
model.setList(&list1, 1, 3);
52+
ASSERT_EQ(dataChangedSpy.count(), 7);
4253
ASSERT_EQ(aboutToResetSpy.count(), 1);
4354
ASSERT_EQ(resetSpy.count(), 1);
4455
ASSERT_TRUE(aboutToInsertSpy.empty());
@@ -65,8 +76,8 @@ TEST(ListMonitorListModelTest, LoadData)
6576
ASSERT_TRUE(args.at(2).toList().isEmpty());
6677

6778
List list2("", "");
68-
model.setList(&list2);
69-
ASSERT_EQ(dataChangedSpy.count(), 2);
79+
model.setList(&list2, 0, 3);
80+
ASSERT_EQ(dataChangedSpy.count(), 7);
7081
ASSERT_EQ(aboutToResetSpy.count(), 2);
7182
ASSERT_EQ(resetSpy.count(), 2);
7283
ASSERT_TRUE(aboutToInsertSpy.empty());
@@ -89,7 +100,7 @@ TEST(ListMonitorListModelTest, AddRows)
89100
List list1("", "");
90101
list1.append(1);
91102
list1.append(2);
92-
model.setList(&list1);
103+
model.setList(&list1, 0, 1);
93104
ASSERT_TRUE(dataChangedSpy.empty());
94105
ASSERT_EQ(aboutToResetSpy.count(), 1);
95106
ASSERT_EQ(resetSpy.count(), 1);
@@ -101,7 +112,7 @@ TEST(ListMonitorListModelTest, AddRows)
101112
list1.append(9);
102113
list1.append(8);
103114
list1.append(7);
104-
model.setList(&list1);
115+
model.setList(&list1, 2, 3);
105116
ASSERT_EQ(dataChangedSpy.count(), 2);
106117
ASSERT_EQ(aboutToResetSpy.count(), 1);
107118
ASSERT_EQ(resetSpy.count(), 1);
@@ -113,18 +124,18 @@ TEST(ListMonitorListModelTest, AddRows)
113124
auto args = dataChangedSpy.at(0);
114125
QModelIndex arg1 = args.at(0).value<QModelIndex>();
115126
QModelIndex arg2 = args.at(1).value<QModelIndex>();
116-
ASSERT_EQ(arg1.row(), 0);
127+
ASSERT_EQ(arg1.row(), 2);
117128
ASSERT_EQ(arg1.column(), 0);
118-
ASSERT_EQ(arg2.row(), 0);
129+
ASSERT_EQ(arg2.row(), 2);
119130
ASSERT_EQ(arg2.column(), 0);
120131
ASSERT_TRUE(args.at(2).toList().isEmpty());
121132

122133
args = dataChangedSpy.at(1);
123134
arg1 = args.at(0).value<QModelIndex>();
124135
arg2 = args.at(1).value<QModelIndex>();
125-
ASSERT_EQ(arg1.row(), 1);
136+
ASSERT_EQ(arg1.row(), 3);
126137
ASSERT_EQ(arg1.column(), 0);
127-
ASSERT_EQ(arg2.row(), 1);
138+
ASSERT_EQ(arg2.row(), 3);
128139
ASSERT_EQ(arg2.column(), 0);
129140
ASSERT_TRUE(args.at(2).toList().isEmpty());
130141

@@ -150,7 +161,7 @@ TEST(ListMonitorListModelTest, RemoveRows)
150161
list1.append(1);
151162
list1.append(2);
152163
list1.append(3);
153-
model.setList(&list1);
164+
model.setList(&list1, 0, 2);
154165
ASSERT_TRUE(dataChangedSpy.empty());
155166
ASSERT_EQ(aboutToResetSpy.count(), 1);
156167
ASSERT_EQ(resetSpy.count(), 1);
@@ -161,7 +172,7 @@ TEST(ListMonitorListModelTest, RemoveRows)
161172

162173
list1.removeAt(2);
163174
list1.removeAt(0);
164-
model.setList(&list1);
175+
model.setList(&list1, 0, 0);
165176
ASSERT_EQ(dataChangedSpy.count(), 1);
166177
ASSERT_EQ(aboutToResetSpy.count(), 1);
167178
ASSERT_EQ(resetSpy.count(), 1);
@@ -193,7 +204,7 @@ TEST(ListMonitorListModelTest, RowCount)
193204
list.append(1);
194205
list.append(2);
195206
list.append(3);
196-
model.setList(&list);
207+
model.setList(&list, 0, 2);
197208
ASSERT_EQ(model.rowCount(QModelIndex()), list.size());
198209
}
199210

@@ -204,7 +215,7 @@ TEST(ListMonitorListModelTest, Data)
204215
list.append(1);
205216
list.append(2);
206217
list.append(3);
207-
model.setList(&list);
218+
model.setList(&list, 0, 2);
208219
ASSERT_EQ(model.data(model.index(0), 0).toString(), "1");
209220
ASSERT_EQ(model.data(model.index(1), 0).toString(), "2");
210221
ASSERT_EQ(model.data(model.index(2), 0).toString(), "3");

test/monitor_models/listmonitormodel_test.cpp

+36
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ TEST(ListMonitorModelTest, OnValueChanged)
2828
{
2929
ListMonitorModel model;
3030
ListMonitorListModel *listModel = model.listModel();
31+
QSignalSpy dataChangedSpy(listModel, &ListMonitorListModel::dataChanged);
3132
VirtualMachine vm;
3233

3334
List list1("", "");
@@ -57,6 +58,23 @@ TEST(ListMonitorModelTest, OnValueChanged)
5758
model.onValueChanged(&vm);
5859
ASSERT_EQ(listModel->rowCount(QModelIndex()), 3);
5960

61+
vm.reset();
62+
vm.addReturnValue(2);
63+
model.setMinIndex(0);
64+
model.setMaxIndex(3);
65+
model.onValueChanged(&vm);
66+
ASSERT_EQ(listModel->rowCount(QModelIndex()), 3);
67+
ASSERT_EQ(dataChangedSpy.count(), 4);
68+
69+
dataChangedSpy.clear();
70+
vm.reset();
71+
vm.addReturnValue(2);
72+
model.setMinIndex(1);
73+
model.setMaxIndex(2);
74+
model.onValueChanged(&vm);
75+
ASSERT_EQ(listModel->rowCount(QModelIndex()), 3);
76+
ASSERT_EQ(dataChangedSpy.count(), 2);
77+
6078
vm.reset();
6179
vm.addReturnValue(0);
6280
model.onValueChanged(&vm);
@@ -68,3 +86,21 @@ TEST(ListMonitorModelTest, Type)
6886
ListMonitorModel model;
6987
ASSERT_EQ(model.type(), MonitorModel::Type::List);
7088
}
89+
90+
TEST(ListMonitorModelTest, MinIndex)
91+
{
92+
ListMonitorModel model;
93+
ASSERT_EQ(model.minIndex(), 0);
94+
95+
model.setMinIndex(2);
96+
ASSERT_EQ(model.minIndex(), 2);
97+
}
98+
99+
TEST(ListMonitorModelTest, MaxIndex)
100+
{
101+
ListMonitorModel model;
102+
ASSERT_EQ(model.maxIndex(), 0);
103+
104+
model.setMaxIndex(17);
105+
ASSERT_EQ(model.maxIndex(), 17);
106+
}

0 commit comments

Comments
 (0)