Skip to content

Commit bed46ce

Browse files
committed
Add ListMonitorListModel class
1 parent 79066df commit bed46ce

File tree

5 files changed

+338
-0
lines changed

5 files changed

+338
-0
lines changed

src/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ qt_add_qml_module(scratchcpp-render
2525
monitormodel.h
2626
valuemonitormodel.cpp
2727
valuemonitormodel.h
28+
listmonitorlistmodel.cpp
29+
listmonitorlistmodel.h
2830
irenderedtarget.h
2931
renderedtarget.cpp
3032
renderedtarget.h

src/listmonitorlistmodel.cpp

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
3+
#include <scratchcpp/list.h>
4+
5+
#include "listmonitorlistmodel.h"
6+
7+
using namespace scratchcpprender;
8+
9+
ListMonitorListModel::ListMonitorListModel(QObject *parent) :
10+
QAbstractListModel(parent)
11+
{
12+
}
13+
14+
void ListMonitorListModel::setList(libscratchcpp::List *list)
15+
{
16+
if (!list)
17+
return;
18+
19+
// Initial load
20+
if (m_list != list) {
21+
beginResetModel();
22+
m_list = list;
23+
m_oldRowCount = m_list->size();
24+
endResetModel();
25+
return;
26+
}
27+
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++)
32+
emit dataChanged(index(i), index(i));
33+
34+
// Notify about new items (at the end of the list)
35+
if (m_list->size() > m_oldRowCount) {
36+
beginInsertRows(QModelIndex(), m_oldRowCount, m_list->size() - 1);
37+
endInsertRows();
38+
} else if (m_list->size() < m_oldRowCount) {
39+
// Notify about removed items (at the end of the list)
40+
beginRemoveRows(QModelIndex(), m_list->size(), m_oldRowCount - 1);
41+
endRemoveRows();
42+
}
43+
44+
m_oldRowCount = m_list->size();
45+
}
46+
47+
int ListMonitorListModel::rowCount(const QModelIndex &parent) const
48+
{
49+
if (m_list)
50+
return m_list->size();
51+
else
52+
return 0;
53+
}
54+
55+
QVariant ListMonitorListModel::data(const QModelIndex &index, int role) const
56+
{
57+
if (!m_list || index.row() < 0 || index.row() >= m_list->size())
58+
return QVariant();
59+
60+
return QString::fromStdString((*m_list)[index.row()].toString());
61+
}
62+
63+
QHash<int, QByteArray> ListMonitorListModel::roleNames() const
64+
{
65+
return { { 0, "value" } };
66+
}

src/listmonitorlistmodel.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// SPDX-License-Identifier: LGPL-3.0-or-later
2+
3+
#pragma once
4+
5+
#include <QAbstractListModel>
6+
7+
namespace libscratchcpp
8+
{
9+
10+
class List;
11+
12+
}
13+
14+
namespace scratchcpprender
15+
{
16+
17+
class ListMonitorListModel : public QAbstractListModel
18+
{
19+
public:
20+
explicit ListMonitorListModel(QObject *parent = nullptr);
21+
22+
void setList(libscratchcpp::List *list);
23+
24+
int rowCount(const QModelIndex &parent) const override;
25+
QVariant data(const QModelIndex &index, int role) const override;
26+
QHash<int, QByteArray> roleNames() const override;
27+
28+
private:
29+
libscratchcpp::List *m_list = nullptr;
30+
int m_oldRowCount = 0;
31+
};
32+
33+
} // namespace scratchcpprender

test/monitor_models/CMakeLists.txt

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
# monitormodel
12
add_executable(
23
monitormodel_test
34
monitormodel_test.cpp
@@ -14,6 +15,7 @@ target_link_libraries(
1415
add_test(monitormodel_test)
1516
gtest_discover_tests(monitormodel_test)
1617

18+
# valuemonitormodel
1719
add_executable(
1820
valuemonitormodel_test
1921
valuemonitormodel_test.cpp
@@ -31,3 +33,20 @@ target_link_libraries(
3133

3234
add_test(valuemonitormodel_test)
3335
gtest_discover_tests(valuemonitormodel_test)
36+
37+
# listmonitorlistmodel
38+
add_executable(
39+
listmonitorlistmodel_test
40+
listmonitorlistmodel_test.cpp
41+
)
42+
43+
target_link_libraries(
44+
listmonitorlistmodel_test
45+
GTest::gtest_main
46+
scratchcpp-render
47+
${QT_LIBS}
48+
Qt6::Test
49+
)
50+
51+
add_test(listmonitorlistmodel_test)
52+
gtest_discover_tests(listmonitorlistmodel_test)
Lines changed: 218 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,218 @@
1+
#include <QtTest/QSignalSpy>
2+
#include <scratchcpp/list.h>
3+
#include <listmonitorlistmodel.h>
4+
5+
#include "../common.h"
6+
7+
using namespace scratchcpprender;
8+
using namespace libscratchcpp;
9+
10+
TEST(ListMonitorListModelTest, Constructors)
11+
{
12+
ListMonitorListModel model1;
13+
ListMonitorListModel model2(&model1);
14+
ASSERT_EQ(model2.parent(), &model1);
15+
}
16+
17+
TEST(ListMonitorListModelTest, LoadData)
18+
{
19+
ListMonitorListModel model;
20+
QSignalSpy dataChangedSpy(&model, &ListMonitorListModel::dataChanged);
21+
QSignalSpy aboutToResetSpy(&model, &ListMonitorListModel::modelAboutToBeReset);
22+
QSignalSpy resetSpy(&model, &ListMonitorListModel::modelReset);
23+
QSignalSpy aboutToInsertSpy(&model, &ListMonitorListModel::rowsAboutToBeInserted);
24+
QSignalSpy insertSpy(&model, &ListMonitorListModel::rowsInserted);
25+
QSignalSpy aboutToRemoveSpy(&model, &ListMonitorListModel::rowsAboutToBeRemoved);
26+
QSignalSpy removeSpy(&model, &ListMonitorListModel::rowsRemoved);
27+
28+
List list1("", "");
29+
list1.push_back(1);
30+
list1.push_back(2);
31+
model.setList(&list1);
32+
ASSERT_TRUE(dataChangedSpy.empty());
33+
ASSERT_EQ(aboutToResetSpy.count(), 1);
34+
ASSERT_EQ(resetSpy.count(), 1);
35+
ASSERT_TRUE(aboutToInsertSpy.empty());
36+
ASSERT_TRUE(insertSpy.empty());
37+
ASSERT_TRUE(aboutToRemoveSpy.empty());
38+
ASSERT_TRUE(removeSpy.empty());
39+
40+
model.setList(&list1);
41+
ASSERT_EQ(dataChangedSpy.count(), 2);
42+
ASSERT_EQ(aboutToResetSpy.count(), 1);
43+
ASSERT_EQ(resetSpy.count(), 1);
44+
ASSERT_TRUE(aboutToInsertSpy.empty());
45+
ASSERT_TRUE(insertSpy.empty());
46+
ASSERT_TRUE(aboutToRemoveSpy.empty());
47+
ASSERT_TRUE(removeSpy.empty());
48+
49+
auto args = dataChangedSpy.at(0);
50+
QModelIndex arg1 = args.at(0).value<QModelIndex>();
51+
QModelIndex arg2 = args.at(1).value<QModelIndex>();
52+
ASSERT_EQ(arg1.row(), 0);
53+
ASSERT_EQ(arg1.column(), 0);
54+
ASSERT_EQ(arg2.row(), 0);
55+
ASSERT_EQ(arg2.column(), 0);
56+
ASSERT_TRUE(args.at(2).toList().isEmpty());
57+
58+
args = dataChangedSpy.at(1);
59+
arg1 = args.at(0).value<QModelIndex>();
60+
arg2 = args.at(1).value<QModelIndex>();
61+
ASSERT_EQ(arg1.row(), 1);
62+
ASSERT_EQ(arg1.column(), 0);
63+
ASSERT_EQ(arg2.row(), 1);
64+
ASSERT_EQ(arg2.column(), 0);
65+
ASSERT_TRUE(args.at(2).toList().isEmpty());
66+
67+
List list2("", "");
68+
model.setList(&list2);
69+
ASSERT_EQ(dataChangedSpy.count(), 2);
70+
ASSERT_EQ(aboutToResetSpy.count(), 2);
71+
ASSERT_EQ(resetSpy.count(), 2);
72+
ASSERT_TRUE(aboutToInsertSpy.empty());
73+
ASSERT_TRUE(insertSpy.empty());
74+
ASSERT_TRUE(aboutToRemoveSpy.empty());
75+
ASSERT_TRUE(removeSpy.empty());
76+
}
77+
78+
TEST(ListMonitorListModelTest, AddRows)
79+
{
80+
ListMonitorListModel model;
81+
QSignalSpy dataChangedSpy(&model, &ListMonitorListModel::dataChanged);
82+
QSignalSpy aboutToResetSpy(&model, &ListMonitorListModel::modelAboutToBeReset);
83+
QSignalSpy resetSpy(&model, &ListMonitorListModel::modelReset);
84+
QSignalSpy aboutToInsertSpy(&model, &ListMonitorListModel::rowsAboutToBeInserted);
85+
QSignalSpy insertSpy(&model, &ListMonitorListModel::rowsInserted);
86+
QSignalSpy aboutToRemoveSpy(&model, &ListMonitorListModel::rowsAboutToBeRemoved);
87+
QSignalSpy removeSpy(&model, &ListMonitorListModel::rowsRemoved);
88+
89+
List list1("", "");
90+
list1.push_back(1);
91+
list1.push_back(2);
92+
model.setList(&list1);
93+
ASSERT_TRUE(dataChangedSpy.empty());
94+
ASSERT_EQ(aboutToResetSpy.count(), 1);
95+
ASSERT_EQ(resetSpy.count(), 1);
96+
ASSERT_TRUE(aboutToInsertSpy.empty());
97+
ASSERT_TRUE(insertSpy.empty());
98+
ASSERT_TRUE(aboutToRemoveSpy.empty());
99+
ASSERT_TRUE(removeSpy.empty());
100+
101+
list1.push_back(9);
102+
list1.push_back(8);
103+
list1.push_back(7);
104+
model.setList(&list1);
105+
ASSERT_EQ(dataChangedSpy.count(), 2);
106+
ASSERT_EQ(aboutToResetSpy.count(), 1);
107+
ASSERT_EQ(resetSpy.count(), 1);
108+
ASSERT_EQ(aboutToInsertSpy.count(), 1);
109+
ASSERT_EQ(insertSpy.count(), 1);
110+
ASSERT_TRUE(aboutToRemoveSpy.empty());
111+
ASSERT_TRUE(removeSpy.empty());
112+
113+
auto args = dataChangedSpy.at(0);
114+
QModelIndex arg1 = args.at(0).value<QModelIndex>();
115+
QModelIndex arg2 = args.at(1).value<QModelIndex>();
116+
ASSERT_EQ(arg1.row(), 0);
117+
ASSERT_EQ(arg1.column(), 0);
118+
ASSERT_EQ(arg2.row(), 0);
119+
ASSERT_EQ(arg2.column(), 0);
120+
ASSERT_TRUE(args.at(2).toList().isEmpty());
121+
122+
args = dataChangedSpy.at(1);
123+
arg1 = args.at(0).value<QModelIndex>();
124+
arg2 = args.at(1).value<QModelIndex>();
125+
ASSERT_EQ(arg1.row(), 1);
126+
ASSERT_EQ(arg1.column(), 0);
127+
ASSERT_EQ(arg2.row(), 1);
128+
ASSERT_EQ(arg2.column(), 0);
129+
ASSERT_TRUE(args.at(2).toList().isEmpty());
130+
131+
args = aboutToInsertSpy.at(0);
132+
arg1 = args.at(0).value<QModelIndex>();
133+
ASSERT_EQ(arg1, QModelIndex());
134+
ASSERT_EQ(args.at(1).toInt(), 2);
135+
ASSERT_EQ(args.at(2).toInt(), 4);
136+
}
137+
138+
TEST(ListMonitorListModelTest, RemoveRows)
139+
{
140+
ListMonitorListModel model;
141+
QSignalSpy dataChangedSpy(&model, &ListMonitorListModel::dataChanged);
142+
QSignalSpy aboutToResetSpy(&model, &ListMonitorListModel::modelAboutToBeReset);
143+
QSignalSpy resetSpy(&model, &ListMonitorListModel::modelReset);
144+
QSignalSpy aboutToInsertSpy(&model, &ListMonitorListModel::rowsAboutToBeInserted);
145+
QSignalSpy insertSpy(&model, &ListMonitorListModel::rowsInserted);
146+
QSignalSpy aboutToRemoveSpy(&model, &ListMonitorListModel::rowsAboutToBeRemoved);
147+
QSignalSpy removeSpy(&model, &ListMonitorListModel::rowsRemoved);
148+
149+
List list1("", "");
150+
list1.push_back(1);
151+
list1.push_back(2);
152+
list1.push_back(3);
153+
model.setList(&list1);
154+
ASSERT_TRUE(dataChangedSpy.empty());
155+
ASSERT_EQ(aboutToResetSpy.count(), 1);
156+
ASSERT_EQ(resetSpy.count(), 1);
157+
ASSERT_TRUE(aboutToInsertSpy.empty());
158+
ASSERT_TRUE(insertSpy.empty());
159+
ASSERT_TRUE(aboutToRemoveSpy.empty());
160+
ASSERT_TRUE(removeSpy.empty());
161+
162+
list1.removeAt(2);
163+
list1.removeAt(0);
164+
model.setList(&list1);
165+
ASSERT_EQ(dataChangedSpy.count(), 1);
166+
ASSERT_EQ(aboutToResetSpy.count(), 1);
167+
ASSERT_EQ(resetSpy.count(), 1);
168+
ASSERT_TRUE(aboutToInsertSpy.empty());
169+
ASSERT_TRUE(insertSpy.empty());
170+
ASSERT_EQ(aboutToRemoveSpy.count(), 1);
171+
ASSERT_EQ(removeSpy.count(), 1);
172+
173+
auto args = dataChangedSpy.at(0);
174+
QModelIndex arg1 = args.at(0).value<QModelIndex>();
175+
QModelIndex arg2 = args.at(1).value<QModelIndex>();
176+
ASSERT_EQ(arg1.row(), 0);
177+
ASSERT_EQ(arg1.column(), 0);
178+
ASSERT_EQ(arg2.row(), 0);
179+
ASSERT_EQ(arg2.column(), 0);
180+
ASSERT_TRUE(args.at(2).toList().isEmpty());
181+
182+
args = aboutToRemoveSpy.at(0);
183+
arg1 = args.at(0).value<QModelIndex>();
184+
ASSERT_EQ(arg1, QModelIndex());
185+
ASSERT_EQ(args.at(1).toInt(), 1);
186+
ASSERT_EQ(args.at(2).toInt(), 2);
187+
}
188+
189+
TEST(ListMonitorListModelTest, RowCount)
190+
{
191+
ListMonitorListModel model;
192+
List list("", "");
193+
list.push_back(1);
194+
list.push_back(2);
195+
list.push_back(3);
196+
model.setList(&list);
197+
ASSERT_EQ(model.rowCount(QModelIndex()), list.size());
198+
}
199+
200+
TEST(ListMonitorListModelTest, Data)
201+
{
202+
ListMonitorListModel model;
203+
List list("", "");
204+
list.push_back(1);
205+
list.push_back(2);
206+
list.push_back(3);
207+
model.setList(&list);
208+
ASSERT_EQ(model.data(model.index(0), 0).toString(), "1");
209+
ASSERT_EQ(model.data(model.index(1), 0).toString(), "2");
210+
ASSERT_EQ(model.data(model.index(2), 0).toString(), "3");
211+
}
212+
213+
TEST(ListMonitorListModelTest, RoleNames)
214+
{
215+
ListMonitorListModel model;
216+
QHash<int, QByteArray> names({ { 0, "value" } });
217+
ASSERT_EQ(model.roleNames(), names);
218+
}

0 commit comments

Comments
 (0)