Merge lp:~mhr3/dee-qt/changeset-support into lp:dee-qt
- changeset-support
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Paweł Stołowski |
Approved revision: | 89 |
Merged at revision: | 83 |
Proposed branch: | lp:~mhr3/dee-qt/changeset-support |
Merge into: | lp:dee-qt |
Diff against target: |
1133 lines (+894/-37) 9 files modified
CMakeLists.txt (+7/-2) cmake/COPYING-CMAKE-SCRIPTS (+22/-0) cmake/Coverage.cmake (+37/-0) debian/changelog (+6/-0) deelistmodel.cpp (+174/-25) tests/CMakeLists.txt (+10/-1) tests/conversiontest.cpp (+59/-6) tests/deelistmodeltest.cpp (+5/-3) tests/signaltest.cpp (+574/-0) |
To merge this branch: | bzr merge lp:~mhr3/dee-qt/changeset-support |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Paweł Stołowski (community) | Approve | ||
PS Jenkins bot (community) | continuous-integration | Approve | |
Review via email:
|
Commit message
Takes advantage of added changeset API in dee 1.2.7 to map more naturally to Qt's way of dealing with changes to models.
Description of the change
Takes advantage of added changeset API in dee 1.2.7 to map more naturally to Qt's way of dealing with changes to models.
Also added support for generating coverage and added a bunch of tests to bump the coverage number to >95% (from ~50%).
Requires lp:~mhr3/dee/add-changesets

PS Jenkins bot (ps-jenkins) wrote : | # |

PS Jenkins bot (ps-jenkins) wrote : | # |
FAILED: Continuous integration, rev:88
http://
Executed test runs:
SUCCESS: http://
FAILURE: http://
Click here to trigger a rebuild:
http://

Paweł Stołowski (stolowski) wrote : | # |
357 + if (model-
Shouldn't this say "if (!model-

Paweł Stołowski (stolowski) wrote : | # |
221 + // have the "extra" row from the addition, so we need to hide it
Can you enhance this comment a bit - how is "hiding" actually achieved here?
230 + m_count += m_changesetRowEnd - m_changesetRowStart + 1;
241 + m_count -= m_changesetRowEnd - m_changesetRowStart + 1;
Why "+1"
- 89. By Michal Hruby
-
Explain things better, split up the flushing into separate method

Michal Hruby (mhr3) wrote : | # |
> 357 + if (model-
>
> Shouldn't this say "if (!model-
No, this is callback for row-changed, in case of transaction we need to flush everything we received so far.

Michal Hruby (mhr3) wrote : | # |
> 221 + // have the "extra" row from the addition, so we need to hide
> it
> Can you enhance this comment a bit - how is "hiding" actually achieved here?
Updated the comments, hopefully it's more clear now.
> 230 + m_count += m_changesetRowEnd - m_changesetRowStart + 1;
> 241 + m_count -= m_changesetRowEnd - m_changesetRowStart + 1;
>
> Why "+1"
Because a single insert is beginInsertRows(0, 0) => ie rowStart = 0, rowEnd = 0; count += 0 - 0 + 1;
For insertion of two rows: beginInsertRows(0, 1) => rowStart = 0, rowEnd = 1; count += 1 - 0 + 1;

PS Jenkins bot (ps-jenkins) wrote : | # |
PASSED: Continuous integration, rev:89
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://

Paweł Stołowski (stolowski) wrote : | # |
398 + // there's an extra row in the backend, skip it by incrementing
399 + row++;
400 + }
401 + } else {
402 + if (d->m_rowBeingR
403 + // we need to skip the about-to-be-removed row
404 + row++;
Why are we skipping only one row? The changeset may span multiple rows, shouldn't this be taken into account?

Michal Hruby (mhr3) wrote : | # |
When processing a transaction/
The primary thing here is that the skipping only happens when inside the row-* callback.
Consider how the transaction looks like in pseudocode:
// starting inside dee
var rows = dbus_signal.
while (rows.has_next())
{
row = rows.next();
var row_signal = this.submit_
this.
{
// inside the signal emission we get into the DeeListModel plugin code
if (consecutive_
else flushChangesAnd
{
beginRows
// now qt will emit rowsInserted() or rowsRemoved()
endRowsIn
{
// view code that will read the model
for (int i = begin; i < end; i++)
});
});
});
}
Of course the situation is different when the entire transaction is consecutive:
// starting inside dee
var rows = dbus_signal.
while (rows.has_next())
{
row = rows.next();
var row_signal = this.submit_
this.
}
this.emit(
{
// inside the signal emission we get into the DeeListModel plugin code
flushChanges(() =>
{
beginRowsIn
// now qt will emit rowsInserted() or rowsRemoved()
endRowsInse
{
// view code that will read the model
for (int i = begin; i < end; i++)
});
});
});

Paweł Stołowski (stolowski) wrote : | # |
Nice stuff! Thanks for explanations!
Preview Diff
1 | === modified file 'CMakeLists.txt' | |||
2 | --- CMakeLists.txt 2013-07-25 14:23:11 +0000 | |||
3 | +++ CMakeLists.txt 2013-09-19 17:47:15 +0000 | |||
4 | @@ -2,7 +2,7 @@ | |||
5 | 2 | cmake_minimum_required(VERSION 2.8.6) | 2 | cmake_minimum_required(VERSION 2.8.6) |
6 | 3 | 3 | ||
7 | 4 | set(SONAME 3) | 4 | set(SONAME 3) |
9 | 5 | set(VERSION 3.2) | 5 | set(VERSION 3.3) |
10 | 6 | set(SOVERSION 3.0.0) | 6 | set(SOVERSION 3.0.0) |
11 | 7 | 7 | ||
12 | 8 | # Instruct CMake to run moc automatically when needed. | 8 | # Instruct CMake to run moc automatically when needed. |
13 | @@ -10,6 +10,11 @@ | |||
14 | 10 | 10 | ||
15 | 11 | # Dependencies | 11 | # Dependencies |
16 | 12 | include(FindPkgConfig) | 12 | include(FindPkgConfig) |
17 | 13 | |||
18 | 14 | set(CMAKE_MODULE_PATH "${CMAKE_SOURCE_DIR}/cmake" "${CMAKE_MODULE_PATH}") | ||
19 | 15 | |||
20 | 16 | include(Coverage) | ||
21 | 17 | |||
22 | 13 | if (WITHQT5) | 18 | if (WITHQT5) |
23 | 14 | message("Building Qt5 version") | 19 | message("Building Qt5 version") |
24 | 15 | 20 | ||
25 | @@ -39,7 +44,7 @@ | |||
26 | 39 | 44 | ||
27 | 40 | set(QT_DEE_PKGCONFIG_FILE lib${DEE_QT_LIBNAME}.pc) | 45 | set(QT_DEE_PKGCONFIG_FILE lib${DEE_QT_LIBNAME}.pc) |
28 | 41 | 46 | ||
30 | 42 | pkg_check_modules(DEE REQUIRED dee-1.0) | 47 | pkg_check_modules(DEE REQUIRED dee-1.0>=1.2.7) |
31 | 43 | 48 | ||
32 | 44 | # Build flags | 49 | # Build flags |
33 | 45 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wundef -std=c++0x") | 50 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fvisibility=hidden -Wall -Wundef -std=c++0x") |
34 | 46 | 51 | ||
35 | === added directory 'cmake' | |||
36 | === added file 'cmake/COPYING-CMAKE-SCRIPTS' | |||
37 | --- cmake/COPYING-CMAKE-SCRIPTS 1970-01-01 00:00:00 +0000 | |||
38 | +++ cmake/COPYING-CMAKE-SCRIPTS 2013-09-19 17:47:15 +0000 | |||
39 | @@ -0,0 +1,22 @@ | |||
40 | 1 | Redistribution and use in source and binary forms, with or without | ||
41 | 2 | modification, are permitted provided that the following conditions | ||
42 | 3 | are met: | ||
43 | 4 | |||
44 | 5 | 1. Redistributions of source code must retain the copyright | ||
45 | 6 | notice, this list of conditions and the following disclaimer. | ||
46 | 7 | 2. Redistributions in binary form must reproduce the copyright | ||
47 | 8 | notice, this list of conditions and the following disclaimer in the | ||
48 | 9 | documentation and/or other materials provided with the distribution. | ||
49 | 10 | 3. The name of the author may not be used to endorse or promote products | ||
50 | 11 | derived from this software without specific prior written permission. | ||
51 | 12 | |||
52 | 13 | THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR | ||
53 | 14 | IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||
54 | 15 | OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||
55 | 16 | IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||
56 | 17 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT | ||
57 | 18 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, | ||
58 | 19 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY | ||
59 | 20 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
60 | 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
61 | 22 | THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
62 | 0 | 23 | ||
63 | === added file 'cmake/Coverage.cmake' | |||
64 | --- cmake/Coverage.cmake 1970-01-01 00:00:00 +0000 | |||
65 | +++ cmake/Coverage.cmake 2013-09-19 17:47:15 +0000 | |||
66 | @@ -0,0 +1,37 @@ | |||
67 | 1 | if (CMAKE_BUILD_TYPE MATCHES coverage) | ||
68 | 2 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage") | ||
69 | 3 | set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --coverage") | ||
70 | 4 | set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} --coverage") | ||
71 | 5 | set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --coverage") | ||
72 | 6 | |||
73 | 7 | find_program(GCOVR_EXECUTABLE gcovr HINTS ${GCOVR_ROOT} "${GCOVR_ROOT}/bin") | ||
74 | 8 | if (NOT GCOVR_EXECUTABLE) | ||
75 | 9 | message(STATUS "Gcovr binary was not found, can not generate XML coverage info.") | ||
76 | 10 | else () | ||
77 | 11 | message(STATUS "Gcovr found, can generate XML coverage info.") | ||
78 | 12 | add_custom_target (coverage-xml | ||
79 | 13 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} | ||
80 | 14 | COMMAND "${GCOVR_EXECUTABLE}" --exclude="test.*" --exclude="obj.*" -x -r "${CMAKE_SOURCE_DIR}" | ||
81 | 15 | --object-directory=${CMAKE_BINARY_DIR} -o coverage.xml) | ||
82 | 16 | endif() | ||
83 | 17 | |||
84 | 18 | find_program(LCOV_EXECUTABLE lcov HINTS ${LCOV_ROOT} "${GCOVR_ROOT}/bin") | ||
85 | 19 | find_program(GENHTML_EXECUTABLE genhtml HINTS ${GENHTML_ROOT}) | ||
86 | 20 | if (NOT LCOV_EXECUTABLE) | ||
87 | 21 | message(STATUS "Lcov binary was not found, can not generate HTML coverage info.") | ||
88 | 22 | else () | ||
89 | 23 | if(NOT GENHTML_EXECUTABLE) | ||
90 | 24 | message(STATUS "Genthml binary not found, can not generate HTML coverage info.") | ||
91 | 25 | else() | ||
92 | 26 | message(STATUS "Lcov and genhtml found, can generate HTML coverage info.") | ||
93 | 27 | add_custom_target (coverage-html | ||
94 | 28 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR} | ||
95 | 29 | COMMAND "${LCOV_EXECUTABLE}" --capture --output-file "${CMAKE_BINARY_DIR}/coverage.info" --no-checksum --directory "${CMAKE_BINARY_DIR}" | ||
96 | 30 | COMMAND "${LCOV_EXECUTABLE}" --remove "${CMAKE_BINARY_DIR}/coverage.info" '/usr/*' --output-file "${CMAKE_BINARY_DIR}/coverage.info" | ||
97 | 31 | COMMAND "${LCOV_EXECUTABLE}" --remove "${CMAKE_BINARY_DIR}/coverage.info" '${CMAKE_BINARY_DIR}/moc_*' --output-file "${CMAKE_BINARY_DIR}/coverage.info" | ||
98 | 32 | COMMAND "${LCOV_EXECUTABLE}" --remove "${CMAKE_BINARY_DIR}/coverage.info" '${CMAKE_SOURCE_DIR}/tests/*' --output-file "${CMAKE_BINARY_DIR}/coverage.info" | ||
99 | 33 | COMMAND "${GENHTML_EXECUTABLE}" --prefix "${CMAKE_BINARY_DIR}" --output-directory coveragereport --title "Code Coverage" --legend --show-details coverage.info | ||
100 | 34 | ) | ||
101 | 35 | endif() | ||
102 | 36 | endif() | ||
103 | 37 | endif() | ||
104 | 0 | 38 | ||
105 | === modified file 'debian/changelog' | |||
106 | --- debian/changelog 2013-08-21 16:18:56 +0000 | |||
107 | +++ debian/changelog 2013-09-19 17:47:15 +0000 | |||
108 | @@ -1,3 +1,9 @@ | |||
109 | 1 | dee-qt (3.3-0ubuntu1) UNRELEASED; urgency=low | ||
110 | 2 | |||
111 | 3 | * Take advantage of new changeset API in dee | ||
112 | 4 | |||
113 | 5 | -- Michal Hruby <michal.hruby@canonical.com> Tue, 10 Sep 2013 16:56:00 +0100 | ||
114 | 6 | |||
115 | 1 | dee-qt (3.2+13.10.20130821.1-0ubuntu1) saucy; urgency=low | 7 | dee-qt (3.2+13.10.20130821.1-0ubuntu1) saucy; urgency=low |
116 | 2 | 8 | ||
117 | 3 | [ Albert Astals ] | 9 | [ Albert Astals ] |
118 | 4 | 10 | ||
119 | === modified file 'deelistmodel.cpp' | |||
120 | --- deelistmodel.cpp 2013-08-21 11:03:07 +0000 | |||
121 | +++ deelistmodel.cpp 2013-09-19 17:47:15 +0000 | |||
122 | @@ -28,6 +28,19 @@ | |||
123 | 28 | 28 | ||
124 | 29 | class DeeListModelPrivate { | 29 | class DeeListModelPrivate { |
125 | 30 | public: | 30 | public: |
126 | 31 | enum ProcessingState | ||
127 | 32 | { | ||
128 | 33 | START, | ||
129 | 34 | ADDITIONS, | ||
130 | 35 | REMOVALS | ||
131 | 36 | }; | ||
132 | 37 | |||
133 | 38 | enum ChangeType | ||
134 | 39 | { | ||
135 | 40 | ADDITION, | ||
136 | 41 | REMOVAL | ||
137 | 42 | }; | ||
138 | 43 | |||
139 | 31 | DeeListModelPrivate(DeeListModel* parent); | 44 | DeeListModelPrivate(DeeListModel* parent); |
140 | 32 | ~DeeListModelPrivate(); | 45 | ~DeeListModelPrivate(); |
141 | 33 | 46 | ||
142 | @@ -37,22 +50,43 @@ | |||
143 | 37 | void createRoles(); | 50 | void createRoles(); |
144 | 38 | bool synchronized() const; | 51 | bool synchronized() const; |
145 | 39 | 52 | ||
146 | 53 | void processChange(ChangeType changeType, int changePos); | ||
147 | 54 | void flushChanges(); | ||
148 | 55 | |||
149 | 40 | /* GObject signal handlers for m_deeModel */ | 56 | /* GObject signal handlers for m_deeModel */ |
150 | 41 | static void onSynchronizedChanged(GObject* emitter, GParamSpec *pspec, DeeListModel* model); | 57 | static void onSynchronizedChanged(GObject* emitter, GParamSpec *pspec, DeeListModel* model); |
151 | 42 | static void onRowAdded(GObject* emitter, DeeModelIter* iter, DeeListModel* model); | 58 | static void onRowAdded(GObject* emitter, DeeModelIter* iter, DeeListModel* model); |
152 | 43 | static void onRowRemoved(GObject* emitter, DeeModelIter* iter, DeeListModel* model); | 59 | static void onRowRemoved(GObject* emitter, DeeModelIter* iter, DeeListModel* model); |
153 | 44 | static void onRowChanged(GObject* emitter, DeeModelIter* iter, DeeListModel* model); | 60 | static void onRowChanged(GObject* emitter, DeeModelIter* iter, DeeListModel* model); |
154 | 45 | 61 | ||
155 | 62 | static void onStartChangeset(DeeListModel* model); | ||
156 | 63 | static void onFinishChangeset(DeeListModel* model); | ||
157 | 64 | |||
158 | 46 | DeeListModel* m_parent; | 65 | DeeListModel* m_parent; |
159 | 47 | DeeModel* m_deeModel; | 66 | DeeModel* m_deeModel; |
160 | 48 | QString m_name; | 67 | QString m_name; |
161 | 49 | int m_count; | 68 | int m_count; |
162 | 50 | bool m_listeningSynchronized; | 69 | bool m_listeningSynchronized; |
163 | 51 | QHash<int, QByteArray> m_roleNames; | 70 | QHash<int, QByteArray> m_roleNames; |
164 | 71 | int m_rowBeingAdded; | ||
165 | 52 | int m_rowBeingRemoved; | 72 | int m_rowBeingRemoved; |
166 | 73 | ProcessingState m_changesetState; | ||
167 | 74 | bool m_changesetInProgress; | ||
168 | 75 | int m_changesetRowStart; | ||
169 | 76 | int m_changesetRowEnd; | ||
170 | 53 | }; | 77 | }; |
171 | 54 | 78 | ||
173 | 55 | DeeListModelPrivate::DeeListModelPrivate(DeeListModel* parent) : m_parent(parent), m_deeModel(NULL), m_count(0), m_listeningSynchronized(false), m_rowBeingRemoved(-1) | 79 | DeeListModelPrivate::DeeListModelPrivate(DeeListModel* parent) |
174 | 80 | : m_parent(parent) | ||
175 | 81 | , m_deeModel(NULL) | ||
176 | 82 | , m_count(0) | ||
177 | 83 | , m_listeningSynchronized(false) | ||
178 | 84 | , m_rowBeingAdded(-1) | ||
179 | 85 | , m_rowBeingRemoved(-1) | ||
180 | 86 | , m_changesetState(ProcessingState::START) | ||
181 | 87 | , m_changesetInProgress(false) | ||
182 | 88 | , m_changesetRowStart(-1) | ||
183 | 89 | , m_changesetRowEnd(-1) | ||
184 | 56 | { | 90 | { |
185 | 57 | } | 91 | } |
186 | 58 | 92 | ||
187 | @@ -72,7 +106,10 @@ | |||
188 | 72 | } | 106 | } |
189 | 73 | g_object_disconnect(m_deeModel, "any_signal", G_CALLBACK(onRowAdded), m_parent, | 107 | g_object_disconnect(m_deeModel, "any_signal", G_CALLBACK(onRowAdded), m_parent, |
190 | 74 | "any_signal", G_CALLBACK(onRowRemoved), m_parent, | 108 | "any_signal", G_CALLBACK(onRowRemoved), m_parent, |
192 | 75 | "any_signal", G_CALLBACK(onRowChanged), m_parent, NULL); | 109 | "any_signal", G_CALLBACK(onRowChanged), m_parent, |
193 | 110 | "any_signal", G_CALLBACK(onStartChangeset), m_parent, | ||
194 | 111 | "any_signal", G_CALLBACK(onFinishChangeset), m_parent, | ||
195 | 112 | NULL); | ||
196 | 76 | 113 | ||
197 | 77 | g_object_unref(m_deeModel); | 114 | g_object_unref(m_deeModel); |
198 | 78 | m_deeModel = NULL; | 115 | m_deeModel = NULL; |
199 | @@ -104,6 +141,8 @@ | |||
200 | 104 | g_signal_connect(m_deeModel, "row-added", G_CALLBACK(onRowAdded), m_parent); | 141 | g_signal_connect(m_deeModel, "row-added", G_CALLBACK(onRowAdded), m_parent); |
201 | 105 | g_signal_connect(m_deeModel, "row-removed", G_CALLBACK(onRowRemoved), m_parent); | 142 | g_signal_connect(m_deeModel, "row-removed", G_CALLBACK(onRowRemoved), m_parent); |
202 | 106 | g_signal_connect(m_deeModel, "row-changed", G_CALLBACK(onRowChanged), m_parent); | 143 | g_signal_connect(m_deeModel, "row-changed", G_CALLBACK(onRowChanged), m_parent); |
203 | 144 | g_signal_connect_swapped(m_deeModel, "changeset-started", G_CALLBACK(onStartChangeset), m_parent); | ||
204 | 145 | g_signal_connect_swapped(m_deeModel, "changeset-finished", G_CALLBACK(onFinishChangeset), m_parent); | ||
205 | 107 | if (synchronized()) | 146 | if (synchronized()) |
206 | 108 | { | 147 | { |
207 | 109 | createRoles(); | 148 | createRoles(); |
208 | @@ -134,6 +173,90 @@ | |||
209 | 134 | } | 173 | } |
210 | 135 | 174 | ||
211 | 136 | void | 175 | void |
212 | 176 | DeeListModelPrivate::flushChanges() | ||
213 | 177 | { | ||
214 | 178 | bool countChanged = false; | ||
215 | 179 | // The problem we're facing here is that the signals emitted by DeeListModel are not completely | ||
216 | 180 | // in sync with the backend DeeModel - Qt will likely call our data() method right after calling | ||
217 | 181 | // end{Insert|Remove}Rows() and the backend model might still have extra rows, because we're | ||
218 | 182 | // inside onRowRemoved/onRowAdded callback | ||
219 | 183 | // See the data() method for more details | ||
220 | 184 | if (m_changesetState == ProcessingState::ADDITIONS) { | ||
221 | 185 | /* Force emission of QAbstractItemModel::rowsInserted by calling | ||
222 | 186 | beginInsertRows and endInsertRows. Necessary because according to the | ||
223 | 187 | documentation: | ||
224 | 188 | "It can only be emitted by the QAbstractItemModel implementation, and | ||
225 | 189 | cannot be explicitly emitted in subclass code." | ||
226 | 190 | */ | ||
227 | 191 | m_parent->beginInsertRows(QModelIndex(), m_changesetRowStart, m_changesetRowEnd); | ||
228 | 192 | m_count += m_changesetRowEnd - m_changesetRowStart + 1; | ||
229 | 193 | countChanged = true; | ||
230 | 194 | m_parent->endInsertRows(); | ||
231 | 195 | } else if (m_changesetState == ProcessingState::REMOVALS) { | ||
232 | 196 | /* Force emission of QAbstractItemModel::rowsRemoved by calling | ||
233 | 197 | beginRemoveRows and endRemoveRows. Necessary because according to the | ||
234 | 198 | documentation: | ||
235 | 199 | "It can only be emitted by the QAbstractItemModel implementation, and | ||
236 | 200 | cannot be explicitly emitted in subclass code." | ||
237 | 201 | */ | ||
238 | 202 | m_parent->beginRemoveRows(QModelIndex(), m_changesetRowStart, m_changesetRowEnd); | ||
239 | 203 | m_count -= m_changesetRowEnd - m_changesetRowStart + 1; | ||
240 | 204 | countChanged = true; | ||
241 | 205 | m_parent->endRemoveRows(); | ||
242 | 206 | } | ||
243 | 207 | |||
244 | 208 | if (countChanged) Q_EMIT m_parent->countChanged(); | ||
245 | 209 | |||
246 | 210 | m_changesetState = ProcessingState::START; | ||
247 | 211 | m_changesetRowStart = -1; | ||
248 | 212 | m_changesetRowEnd = -1; | ||
249 | 213 | } | ||
250 | 214 | |||
251 | 215 | void | ||
252 | 216 | DeeListModelPrivate::processChange(ChangeType changeType, int changePos) | ||
253 | 217 | { | ||
254 | 218 | /* flush if changeType doesn't match current processing state */ | ||
255 | 219 | if (m_changesetState != ProcessingState::START && | ||
256 | 220 | ((changeType == ChangeType::ADDITION && m_changesetState != ProcessingState::ADDITIONS) || | ||
257 | 221 | (changeType == ChangeType::REMOVAL && m_changesetState != ProcessingState::REMOVALS))) { | ||
258 | 222 | flushChanges(); | ||
259 | 223 | } | ||
260 | 224 | |||
261 | 225 | /* flush also if current changeType isn't consecutive: | ||
262 | 226 | * - consecutive additions are if changePos == m_changesetRowEnd + 1 | ||
263 | 227 | * - consecutive removals are if changePos == m_changesetRowStart | ||
264 | 228 | */ | ||
265 | 229 | if ((m_changesetState == ProcessingState::ADDITIONS && changePos != m_changesetRowEnd + 1) || | ||
266 | 230 | (m_changesetState == ProcessingState::REMOVALS && changePos != m_changesetRowStart)) { | ||
267 | 231 | flushChanges(); | ||
268 | 232 | } | ||
269 | 233 | |||
270 | 234 | switch (m_changesetState) { | ||
271 | 235 | case ProcessingState::START: | ||
272 | 236 | switch (changeType) { | ||
273 | 237 | case ChangeType::ADDITION: | ||
274 | 238 | m_changesetState = ProcessingState::ADDITIONS; | ||
275 | 239 | m_changesetRowStart = changePos; | ||
276 | 240 | m_changesetRowEnd = changePos; | ||
277 | 241 | break; | ||
278 | 242 | case ChangeType::REMOVAL: | ||
279 | 243 | m_changesetState = ProcessingState::REMOVALS; | ||
280 | 244 | m_changesetRowStart = changePos; | ||
281 | 245 | m_changesetRowEnd = changePos; | ||
282 | 246 | break; | ||
283 | 247 | default: break; | ||
284 | 248 | } | ||
285 | 249 | break; | ||
286 | 250 | case ProcessingState::ADDITIONS: | ||
287 | 251 | m_changesetRowEnd = changePos; | ||
288 | 252 | break; | ||
289 | 253 | case ProcessingState::REMOVALS: | ||
290 | 254 | m_changesetRowEnd++; | ||
291 | 255 | break; | ||
292 | 256 | } | ||
293 | 257 | } | ||
294 | 258 | |||
295 | 259 | void | ||
296 | 137 | DeeListModelPrivate::createRoles() | 260 | DeeListModelPrivate::createRoles() |
297 | 138 | { | 261 | { |
298 | 139 | if (m_deeModel == NULL) { | 262 | if (m_deeModel == NULL) { |
299 | @@ -182,16 +305,14 @@ | |||
300 | 182 | } | 305 | } |
301 | 183 | 306 | ||
302 | 184 | gint position = dee_model_get_position(model->d->m_deeModel, iter); | 307 | gint position = dee_model_get_position(model->d->m_deeModel, iter); |
313 | 185 | /* Force emission of QAbstractItemModel::rowsInserted by calling | 308 | |
314 | 186 | beginInsertRows and endInsertRows. Necessary because according to the | 309 | /* if we're inside transaction, we'll consider this row hidden */ |
315 | 187 | documentation: | 310 | model->d->m_rowBeingAdded = position; |
316 | 188 | "It can only be emitted by the QAbstractItemModel implementation, and | 311 | model->d->processChange(ChangeType::ADDITION, position); |
317 | 189 | cannot be explicitly emitted in subclass code." | 312 | if (!model->d->m_changesetInProgress) { |
318 | 190 | */ | 313 | model->d->flushChanges(); |
319 | 191 | model->beginInsertRows(QModelIndex(), position, position); | 314 | } |
320 | 192 | model->d->m_count++; | 315 | model->d->m_rowBeingAdded = -1; |
311 | 193 | model->endInsertRows(); | ||
312 | 194 | Q_EMIT model->countChanged(); | ||
321 | 195 | } | 316 | } |
322 | 196 | 317 | ||
323 | 197 | void | 318 | void |
324 | @@ -204,22 +325,17 @@ | |||
325 | 204 | } | 325 | } |
326 | 205 | 326 | ||
327 | 206 | /* Note that at this point the row is still present and valid in the DeeModel. | 327 | /* Note that at this point the row is still present and valid in the DeeModel. |
329 | 207 | Therefore the value returned by dee_model_get_n_columns() might not be | 328 | Therefore the value returned by dee_model_get_n_rows() might not be |
330 | 208 | what one would expect. | 329 | what one would expect. |
331 | 209 | See Dee's dee_sequence_model_remove() method. | 330 | See Dee's dee_sequence_model_remove() method. |
332 | 210 | */ | 331 | */ |
333 | 211 | gint position = dee_model_get_position(model->d->m_deeModel, iter); | 332 | gint position = dee_model_get_position(model->d->m_deeModel, iter); |
341 | 212 | /* Force emission of QAbstractItemModel::rowsRemoved by calling | 333 | |
335 | 213 | beginRemoveRows and endRemoveRows. Necessary because according to the | ||
336 | 214 | documentation: | ||
337 | 215 | "It can only be emitted by the QAbstractItemModel implementation, and | ||
338 | 216 | cannot be explicitly emitted in subclass code." | ||
339 | 217 | */ | ||
340 | 218 | model->beginRemoveRows(QModelIndex(), position, position); | ||
342 | 219 | model->d->m_rowBeingRemoved = position; | 334 | model->d->m_rowBeingRemoved = position; |
346 | 220 | model->d->m_count--; | 335 | model->d->processChange(ChangeType::REMOVAL, position); |
347 | 221 | model->endRemoveRows(); | 336 | if (!model->d->m_changesetInProgress) { |
348 | 222 | Q_EMIT model->countChanged(); | 337 | model->d->flushChanges(); |
349 | 338 | } | ||
350 | 223 | model->d->m_rowBeingRemoved = -1; | 339 | model->d->m_rowBeingRemoved = -1; |
351 | 224 | } | 340 | } |
352 | 225 | 341 | ||
353 | @@ -232,11 +348,30 @@ | |||
354 | 232 | return; | 348 | return; |
355 | 233 | } | 349 | } |
356 | 234 | 350 | ||
357 | 351 | /* If we're inside a transaction we need to flush the currently queued | ||
358 | 352 | * changes and emit the dataChanged signal after that */ | ||
359 | 353 | if (model->d->m_changesetInProgress) { | ||
360 | 354 | model->d->flushChanges(); | ||
361 | 355 | } | ||
362 | 356 | |||
363 | 235 | gint position = dee_model_get_position(model->d->m_deeModel, iter); | 357 | gint position = dee_model_get_position(model->d->m_deeModel, iter); |
364 | 236 | QModelIndex index = model->index(position); | 358 | QModelIndex index = model->index(position); |
365 | 237 | Q_EMIT model->dataChanged(index, index); | 359 | Q_EMIT model->dataChanged(index, index); |
366 | 238 | } | 360 | } |
367 | 239 | 361 | ||
368 | 362 | void | ||
369 | 363 | DeeListModelPrivate::onStartChangeset(DeeListModel* model) | ||
370 | 364 | { | ||
371 | 365 | model->d->m_changesetInProgress = true; | ||
372 | 366 | } | ||
373 | 367 | |||
374 | 368 | void | ||
375 | 369 | DeeListModelPrivate::onFinishChangeset(DeeListModel* model) | ||
376 | 370 | { | ||
377 | 371 | model->d->flushChanges(); | ||
378 | 372 | model->d->m_changesetInProgress = false; | ||
379 | 373 | } | ||
380 | 374 | |||
381 | 240 | 375 | ||
382 | 241 | 376 | ||
383 | 242 | DeeListModel::DeeListModel(QObject *parent) : | 377 | DeeListModel::DeeListModel(QObject *parent) : |
384 | @@ -320,8 +455,22 @@ | |||
385 | 320 | DeeModelIter* iter; | 455 | DeeModelIter* iter; |
386 | 321 | 456 | ||
387 | 322 | int row = index.row(); | 457 | int row = index.row(); |
390 | 323 | if (d->m_rowBeingRemoved >= 0 && row >= d->m_rowBeingRemoved) { | 458 | // we're inside the row-{added|removed} callback and the backend model still has the removed row |
391 | 324 | row++; | 459 | // (in case of row-removed) or already has the added row (in case of row-added), there are two cases: |
392 | 460 | // 1) inside a transaction, we need to hide about-to-be-added row (because we just flushed changes unrelated | ||
393 | 461 | // to this addition) | ||
394 | 462 | // 2) outside of transaction, we need to hide about-to-be-removed row (because we're flushing right after | ||
395 | 463 | // receiving the signal) | ||
396 | 464 | if (d->m_changesetInProgress) { | ||
397 | 465 | if (d->m_rowBeingAdded >= 0 && row >= d->m_rowBeingAdded) { | ||
398 | 466 | // there's an extra row in the backend, skip it by incrementing | ||
399 | 467 | row++; | ||
400 | 468 | } | ||
401 | 469 | } else { | ||
402 | 470 | if (d->m_rowBeingRemoved >= 0 && row >= d->m_rowBeingRemoved) { | ||
403 | 471 | // we need to skip the about-to-be-removed row | ||
404 | 472 | row++; | ||
405 | 473 | } | ||
406 | 325 | } | 474 | } |
407 | 326 | 475 | ||
408 | 327 | iter = dee_model_get_iter_at_row(d->m_deeModel, row); | 476 | iter = dee_model_get_iter_at_row(d->m_deeModel, row); |
409 | 328 | 477 | ||
410 | === modified file 'tests/CMakeLists.txt' | |||
411 | --- tests/CMakeLists.txt 2012-11-30 14:51:06 +0000 | |||
412 | +++ tests/CMakeLists.txt 2013-09-19 17:47:15 +0000 | |||
413 | @@ -15,9 +15,18 @@ | |||
414 | 15 | add_executable(conversiontest conversiontest.cpp) | 15 | add_executable(conversiontest conversiontest.cpp) |
415 | 16 | target_link_libraries(conversiontest ${OUR_QT_TEST_LIB} ${DEE_QT_LIBNAME}) | 16 | target_link_libraries(conversiontest ${OUR_QT_TEST_LIB} ${DEE_QT_LIBNAME}) |
416 | 17 | set_target_properties(conversiontest PROPERTIES COMPILE_FLAGS -fPIC) | 17 | set_target_properties(conversiontest PROPERTIES COMPILE_FLAGS -fPIC) |
418 | 18 | add_test(NAME conversiontest COMMAND "dbus-test-runner" "--task" "${CMAKE_CURRENT_BINARY_DIR}/conversiontest" "-p" "-xunitxml" "-p" "-o" "-p" "conversiontest-xunit.xml") | 18 | add_test(NAME conversiontest COMMAND "${CMAKE_CURRENT_BINARY_DIR}/conversiontest" "-o" "${CMAKE_CURRENT_BINARY_DIR}/conversiontest-xunit.xml,xunitxml" "-o" "-,txt") |
419 | 19 | set_property(TEST conversiontest PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=.") | 19 | set_property(TEST conversiontest PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=.") |
420 | 20 | 20 | ||
421 | 21 | if (WITHQT5) | ||
422 | 22 | # the test is using signal connections with lambdas, only available in Qt5 | ||
423 | 23 | add_executable(signaltest signaltest.cpp) | ||
424 | 24 | target_link_libraries(signaltest ${OUR_QT_TEST_LIB} ${DEE_QT_LIBNAME}) | ||
425 | 25 | set_target_properties(signaltest PROPERTIES COMPILE_FLAGS -fPIC) | ||
426 | 26 | add_test(NAME signaltest COMMAND "${CMAKE_CURRENT_BINARY_DIR}/signaltest" "-o" "${CMAKE_CURRENT_BINARY_DIR}/signaltest-xunit.xml,xunitxml" "-o" "-,txt") | ||
427 | 27 | set_property(TEST signaltest PROPERTY ENVIRONMENT "LD_LIBRARY_PATH=.") | ||
428 | 28 | endif () | ||
429 | 29 | |||
430 | 21 | add_executable(test-helper test-helper.cpp) | 30 | add_executable(test-helper test-helper.cpp) |
431 | 22 | target_link_libraries(test-helper ${OUR_QT_CORE_LIB} ${OUR_QT_DBUS_LIB} ${DEE_LDFLAGS}) | 31 | target_link_libraries(test-helper ${OUR_QT_CORE_LIB} ${OUR_QT_DBUS_LIB} ${DEE_LDFLAGS}) |
432 | 23 | set_target_properties(test-helper PROPERTIES COMPILE_FLAGS -fPIC) | 32 | set_target_properties(test-helper PROPERTIES COMPILE_FLAGS -fPIC) |
433 | 24 | 33 | ||
434 | === modified file 'tests/conversiontest.cpp' | |||
435 | --- tests/conversiontest.cpp 2013-06-21 17:12:07 +0000 | |||
436 | +++ tests/conversiontest.cpp 2013-09-19 17:47:15 +0000 | |||
437 | @@ -31,15 +31,11 @@ | |||
438 | 31 | g_type_init(); | 31 | g_type_init(); |
439 | 32 | } | 32 | } |
440 | 33 | 33 | ||
442 | 34 | void GVariantToQVariantConversionTest() | 34 | void ModelQVariantConversionTest() |
443 | 35 | { | 35 | { |
445 | 36 | DeeModel* model = dee_shared_model_new("com.deeqt.conversiontest"); | 36 | DeeModel* model = dee_sequence_model_new(); |
446 | 37 | dee_model_set_schema(model, "b", "y", "n", "q", "i", "u", "x", "t", "d", "s", "a(ii)", "a{sv}", NULL); | 37 | dee_model_set_schema(model, "b", "y", "n", "q", "i", "u", "x", "t", "d", "s", "a(ii)", "a{sv}", NULL); |
447 | 38 | 38 | ||
448 | 39 | // Doc says we need to be synchronized before doing anything | ||
449 | 40 | while(!dee_shared_model_is_synchronized(DEE_SHARED_MODEL(model))) | ||
450 | 41 | qApp->processEvents(); | ||
451 | 42 | |||
452 | 43 | GVariant **tuples = g_new(GVariant *, 2); | 39 | GVariant **tuples = g_new(GVariant *, 2); |
453 | 44 | 40 | ||
454 | 45 | GVariant **t1 = g_new(GVariant *, 2); | 41 | GVariant **t1 = g_new(GVariant *, 2); |
455 | @@ -68,6 +64,7 @@ | |||
456 | 68 | QCOMPARE(model_qt.count(), 0); | 64 | QCOMPARE(model_qt.count(), 0); |
457 | 69 | 65 | ||
458 | 70 | model_qt.setModel(model); | 66 | model_qt.setModel(model); |
459 | 67 | QCOMPARE(model_qt.synchronized(), true); | ||
460 | 71 | QCOMPARE(model_qt.count(), 1); | 68 | QCOMPARE(model_qt.count(), 1); |
461 | 72 | 69 | ||
462 | 73 | const QModelIndex row0Index = model_qt.index(0, 0); | 70 | const QModelIndex row0Index = model_qt.index(0, 0); |
463 | @@ -99,6 +96,62 @@ | |||
464 | 99 | g_free(t2); | 96 | g_free(t2); |
465 | 100 | g_object_unref(model); | 97 | g_object_unref(model); |
466 | 101 | } | 98 | } |
467 | 99 | |||
468 | 100 | void GVariantToQVariantConversionTest() | ||
469 | 101 | { | ||
470 | 102 | GVariant **tuples = g_new(GVariant *, 2); | ||
471 | 103 | |||
472 | 104 | GVariant **t1 = g_new(GVariant *, 2); | ||
473 | 105 | t1[0] = g_variant_new_int32(1); | ||
474 | 106 | t1[1] = g_variant_new_int32(2); | ||
475 | 107 | tuples[0] = g_variant_new_tuple(t1, 2); | ||
476 | 108 | |||
477 | 109 | GVariant **t2 = g_new(GVariant *, 2); | ||
478 | 110 | t2[0] = g_variant_new_int32(3); | ||
479 | 111 | t2[1] = g_variant_new_int32(4); | ||
480 | 112 | tuples[1] = g_variant_new_tuple(t2, 2); | ||
481 | 113 | |||
482 | 114 | GVariant* array_of_tuples = g_variant_new_array(((const GVariantType *) "(ii)"), tuples, 2); | ||
483 | 115 | |||
484 | 116 | QVariant variant(DeeListModel::VariantForData(array_of_tuples)); | ||
485 | 117 | |||
486 | 118 | QList< QVariant > expected_array; | ||
487 | 119 | QList< QVariant > tuple1, tuple2; | ||
488 | 120 | tuple1 << 1 << 2; | ||
489 | 121 | tuple2 << 3 << 4; | ||
490 | 122 | expected_array << QVariant(tuple1) << QVariant(tuple2); | ||
491 | 123 | QCOMPARE(variant, QVariant(expected_array)); | ||
492 | 124 | |||
493 | 125 | g_free(t1); | ||
494 | 126 | g_free(t2); | ||
495 | 127 | g_free(tuples); | ||
496 | 128 | |||
497 | 129 | GVariant* nested_variant = g_variant_new_variant(g_variant_new_string("nested")); | ||
498 | 130 | variant = DeeListModel::VariantForData(nested_variant); | ||
499 | 131 | QCOMPARE(variant.toString(), QString("nested")); | ||
500 | 132 | } | ||
501 | 133 | |||
502 | 134 | void QVariantToGVariantConversionTest() | ||
503 | 135 | { | ||
504 | 136 | int cnt = 0; | ||
505 | 137 | GVariant **children = new GVariant*[8]; | ||
506 | 138 | children[cnt++] = g_variant_new_dict_entry(g_variant_new_string("int"), g_variant_new_variant(g_variant_new_int32(-82))); | ||
507 | 139 | children[cnt++] = g_variant_new_dict_entry(g_variant_new_string("bool"), g_variant_new_variant(g_variant_new_boolean(TRUE))); | ||
508 | 140 | children[cnt++] = g_variant_new_dict_entry(g_variant_new_string("string"), g_variant_new_variant(g_variant_new_string("foo"))); | ||
509 | 141 | children[cnt++] = g_variant_new_dict_entry(g_variant_new_string("uint"), g_variant_new_variant(g_variant_new_uint32(90))); | ||
510 | 142 | children[cnt++] = g_variant_new_dict_entry(g_variant_new_string("int64"), g_variant_new_variant(g_variant_new_int64(-401230))); | ||
511 | 143 | children[cnt++] = g_variant_new_dict_entry(g_variant_new_string("uint64"), g_variant_new_variant(g_variant_new_uint64(401230))); | ||
512 | 144 | children[cnt++] = g_variant_new_dict_entry(g_variant_new_string("double"), g_variant_new_variant(g_variant_new_double(3.1415))); | ||
513 | 145 | children[cnt++] = g_variant_new_dict_entry(g_variant_new_string("int-array"), g_variant_new_variant(g_variant_new_parsed("[1, 2, 3]"))); | ||
514 | 146 | GVariant* hints = g_variant_new_array(G_VARIANT_TYPE("{sv}"), children, cnt); | ||
515 | 147 | |||
516 | 148 | QVariant variant(DeeListModel::VariantForData(hints)); | ||
517 | 149 | GVariant* reconstructed_gvariant = DeeListModel::DataFromVariant(variant); | ||
518 | 150 | |||
519 | 151 | // the ordering in the variant might be different, so don't compare directly | ||
520 | 152 | QVERIFY(g_variant_type_equal(g_variant_get_type(hints), g_variant_get_type(reconstructed_gvariant))); | ||
521 | 153 | QCOMPARE(g_variant_n_children(hints), g_variant_n_children(reconstructed_gvariant)); | ||
522 | 154 | } | ||
523 | 102 | }; | 155 | }; |
524 | 103 | 156 | ||
525 | 104 | QTEST_MAIN(ConversionTest) | 157 | QTEST_MAIN(ConversionTest) |
526 | 105 | 158 | ||
527 | === modified file 'tests/deelistmodeltest.cpp' | |||
528 | --- tests/deelistmodeltest.cpp 2012-11-30 12:56:33 +0000 | |||
529 | +++ tests/deelistmodeltest.cpp 2013-09-19 17:47:15 +0000 | |||
530 | @@ -87,12 +87,10 @@ | |||
531 | 87 | 87 | ||
532 | 88 | void setExistingModelTest() | 88 | void setExistingModelTest() |
533 | 89 | { | 89 | { |
534 | 90 | DeeModel* model = dee_shared_model_new("com.deeqt.test.model"); | ||
535 | 91 | |||
536 | 92 | DeeListModel model_qt; | 90 | DeeListModel model_qt; |
537 | 93 | QCOMPARE(model_qt.count(), 0); | 91 | QCOMPARE(model_qt.count(), 0); |
538 | 94 | 92 | ||
540 | 95 | model_qt.setModel(model); | 93 | model_qt.setName("com.deeqt.test.model"); |
541 | 96 | QCOMPARE(model_qt.synchronized(), false); | 94 | QCOMPARE(model_qt.synchronized(), false); |
542 | 97 | 95 | ||
543 | 98 | while(!model_qt.synchronized()) | 96 | while(!model_qt.synchronized()) |
544 | @@ -101,6 +99,10 @@ | |||
545 | 101 | QCOMPARE(model_qt.synchronized(), true); | 99 | QCOMPARE(model_qt.synchronized(), true); |
546 | 102 | QCOMPARE(model_qt.roleNames().count(), 1); | 100 | QCOMPARE(model_qt.roleNames().count(), 1); |
547 | 103 | QCOMPARE(model_qt.roleNames()[0], QByteArray("column_0")); | 101 | QCOMPARE(model_qt.roleNames()[0], QByteArray("column_0")); |
548 | 102 | |||
549 | 103 | model_qt.setName(""); | ||
550 | 104 | QCOMPARE(model_qt.synchronized(), false); | ||
551 | 105 | QCOMPARE(model_qt.rowCount(), 0); | ||
552 | 104 | } | 106 | } |
553 | 105 | 107 | ||
554 | 106 | void cleanupTestCase() | 108 | void cleanupTestCase() |
555 | 107 | 109 | ||
556 | === added file 'tests/signaltest.cpp' | |||
557 | --- tests/signaltest.cpp 1970-01-01 00:00:00 +0000 | |||
558 | +++ tests/signaltest.cpp 2013-09-19 17:47:15 +0000 | |||
559 | @@ -0,0 +1,574 @@ | |||
560 | 1 | /* | ||
561 | 2 | * Copyright (C) 2012 Canonical, Ltd. | ||
562 | 3 | * | ||
563 | 4 | * This program is free software; you can redistribute it and/or modify | ||
564 | 5 | * it under the terms of the GNU General Public License as published by | ||
565 | 6 | * the Free Software Foundation; version 3. | ||
566 | 7 | * | ||
567 | 8 | * This program is distributed in the hope that it will be useful, | ||
568 | 9 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
569 | 10 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
570 | 11 | * GNU General Public License for more details. | ||
571 | 12 | * | ||
572 | 13 | * You should have received a copy of the GNU General Public License | ||
573 | 14 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
574 | 15 | */ | ||
575 | 16 | |||
576 | 17 | #include <QtTest> | ||
577 | 18 | #include <QObject> | ||
578 | 19 | |||
579 | 20 | #include "deelistmodel.h" | ||
580 | 21 | |||
581 | 22 | #include <dee.h> | ||
582 | 23 | |||
583 | 24 | class DeeListModelTest : public QObject | ||
584 | 25 | { | ||
585 | 26 | Q_OBJECT | ||
586 | 27 | |||
587 | 28 | private Q_SLOTS: | ||
588 | 29 | void initTestCase() | ||
589 | 30 | { | ||
590 | 31 | } | ||
591 | 32 | |||
592 | 33 | void synchronizationTest() | ||
593 | 34 | { | ||
594 | 35 | DeeModel* model = dee_sequence_model_new(); | ||
595 | 36 | dee_model_set_schema(model, "s", "i", NULL); | ||
596 | 37 | |||
597 | 38 | DeeListModel model_qt; | ||
598 | 39 | QCOMPARE(model_qt.rowCount(), 0); | ||
599 | 40 | QCOMPARE(model_qt.count(), 0); | ||
600 | 41 | |||
601 | 42 | model_qt.setModel(model); | ||
602 | 43 | QCOMPARE(model_qt.synchronized(), true); | ||
603 | 44 | QVERIFY(model_qt.name().isNull()); | ||
604 | 45 | |||
605 | 46 | model_qt.setModel(NULL); | ||
606 | 47 | QCOMPARE(model_qt.synchronized(), false); | ||
607 | 48 | QCOMPARE(model_qt.rowCount(), 0); | ||
608 | 49 | QCOMPARE(model_qt.count(), 0); | ||
609 | 50 | } | ||
610 | 51 | |||
611 | 52 | void emitBasicSignalsTest() | ||
612 | 53 | { | ||
613 | 54 | DeeModel* model = dee_sequence_model_new(); | ||
614 | 55 | dee_model_set_schema(model, "s", "i", NULL); | ||
615 | 56 | |||
616 | 57 | DeeListModel model_qt; | ||
617 | 58 | model_qt.setModel(model); | ||
618 | 59 | |||
619 | 60 | int num_insertions = 0; | ||
620 | 61 | |||
621 | 62 | connect(&model_qt, &QAbstractItemModel::rowsInserted, [&num_insertions] (const QModelIndex &parent, int start, int end) { | ||
622 | 63 | num_insertions++; | ||
623 | 64 | }); | ||
624 | 65 | |||
625 | 66 | dee_model_append(model, "foo", 5); | ||
626 | 67 | |||
627 | 68 | QCOMPARE(num_insertions, 1); | ||
628 | 69 | QCOMPARE(model_qt.count(), 1); | ||
629 | 70 | QCOMPARE(model_qt.rowCount(), 1); | ||
630 | 71 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
631 | 72 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
632 | 73 | |||
633 | 74 | int num_removals = 0; | ||
634 | 75 | connect(&model_qt, &QAbstractItemModel::rowsRemoved, [&num_removals] (const QModelIndex &parent, int start, int end) { | ||
635 | 76 | num_removals++; | ||
636 | 77 | }); | ||
637 | 78 | |||
638 | 79 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
639 | 80 | |||
640 | 81 | QCOMPARE(num_removals, 1); | ||
641 | 82 | QCOMPARE(model_qt.count(), 0); | ||
642 | 83 | QCOMPARE(model_qt.rowCount(), 0); | ||
643 | 84 | QCOMPARE(num_insertions, 1); | ||
644 | 85 | } | ||
645 | 86 | |||
646 | 87 | void emitMultipleSignalsTest() | ||
647 | 88 | { | ||
648 | 89 | DeeModel* model = dee_sequence_model_new(); | ||
649 | 90 | dee_model_set_schema(model, "s", "i", NULL); | ||
650 | 91 | |||
651 | 92 | DeeListModel model_qt; | ||
652 | 93 | model_qt.setModel(model); | ||
653 | 94 | |||
654 | 95 | int num_insertions = 0; | ||
655 | 96 | |||
656 | 97 | connect(&model_qt, &QAbstractItemModel::rowsInserted, [&num_insertions] (const QModelIndex &parent, int start, int end) { | ||
657 | 98 | num_insertions++; | ||
658 | 99 | }); | ||
659 | 100 | |||
660 | 101 | dee_model_append(model, "foo", 5); | ||
661 | 102 | QCOMPARE(num_insertions, 1); | ||
662 | 103 | QCOMPARE(model_qt.count(), 1); | ||
663 | 104 | QCOMPARE(model_qt.rowCount(), 1); | ||
664 | 105 | dee_model_append(model, "bar", 6); | ||
665 | 106 | QCOMPARE(num_insertions, 2); | ||
666 | 107 | QCOMPARE(model_qt.count(), 2); | ||
667 | 108 | QCOMPARE(model_qt.rowCount(), 2); | ||
668 | 109 | dee_model_append(model, "baz", 7); | ||
669 | 110 | QCOMPARE(num_insertions, 3); | ||
670 | 111 | QCOMPARE(model_qt.count(), 3); | ||
671 | 112 | QCOMPARE(model_qt.rowCount(), 3); | ||
672 | 113 | dee_model_append(model, "qoo", 8); | ||
673 | 114 | |||
674 | 115 | QCOMPARE(num_insertions, 4); | ||
675 | 116 | QCOMPARE(model_qt.count(), 4); | ||
676 | 117 | QCOMPARE(model_qt.rowCount(), 4); | ||
677 | 118 | |||
678 | 119 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
679 | 120 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
680 | 121 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("bar")); | ||
681 | 122 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 6); | ||
682 | 123 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 0).toString(), QString("baz")); | ||
683 | 124 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 1).toInt(), 7); | ||
684 | 125 | QCOMPARE(model_qt.data(model_qt.index(3, 0), 0).toString(), QString("qoo")); | ||
685 | 126 | QCOMPARE(model_qt.data(model_qt.index(3, 0), 1).toInt(), 8); | ||
686 | 127 | |||
687 | 128 | int num_removals = 0; | ||
688 | 129 | connect(&model_qt, &QAbstractItemModel::rowsRemoved, [&num_removals] (const QModelIndex &parent, int start, int end) { | ||
689 | 130 | num_removals++; | ||
690 | 131 | }); | ||
691 | 132 | |||
692 | 133 | num_insertions = 0; | ||
693 | 134 | |||
694 | 135 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
695 | 136 | QCOMPARE(num_removals, 1); | ||
696 | 137 | QCOMPARE(model_qt.count(), 3); | ||
697 | 138 | QCOMPARE(model_qt.rowCount(), 3); | ||
698 | 139 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
699 | 140 | QCOMPARE(num_removals, 2); | ||
700 | 141 | QCOMPARE(model_qt.count(), 2); | ||
701 | 142 | QCOMPARE(model_qt.rowCount(), 2); | ||
702 | 143 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
703 | 144 | QCOMPARE(num_removals, 3); | ||
704 | 145 | QCOMPARE(model_qt.count(), 1); | ||
705 | 146 | QCOMPARE(model_qt.rowCount(), 1); | ||
706 | 147 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
707 | 148 | QCOMPARE(num_removals, 4); | ||
708 | 149 | QCOMPARE(model_qt.count(), 0); | ||
709 | 150 | QCOMPARE(model_qt.rowCount(), 0); | ||
710 | 151 | dee_model_clear(model); | ||
711 | 152 | QCOMPARE(num_removals, 4); | ||
712 | 153 | QCOMPARE(model_qt.count(), 0); | ||
713 | 154 | QCOMPARE(model_qt.rowCount(), 0); | ||
714 | 155 | |||
715 | 156 | QCOMPARE(num_insertions, 0); | ||
716 | 157 | } | ||
717 | 158 | |||
718 | 159 | void emitConsecutiveInsertsTest() | ||
719 | 160 | { | ||
720 | 161 | DeeModel* model = dee_sequence_model_new(); | ||
721 | 162 | dee_model_set_schema(model, "s", "i", NULL); | ||
722 | 163 | |||
723 | 164 | DeeListModel model_qt; | ||
724 | 165 | model_qt.setModel(model); | ||
725 | 166 | |||
726 | 167 | int num_insertions = 0; | ||
727 | 168 | |||
728 | 169 | connect(&model_qt, &QAbstractItemModel::rowsInserted, [&num_insertions] (const QModelIndex &parent, int start, int end) { | ||
729 | 170 | num_insertions++; | ||
730 | 171 | }); | ||
731 | 172 | |||
732 | 173 | dee_model_begin_changeset(model); | ||
733 | 174 | |||
734 | 175 | dee_model_append(model, "foo", 5); | ||
735 | 176 | dee_model_append(model, "bar", 6); | ||
736 | 177 | dee_model_append(model, "baz", 7); | ||
737 | 178 | dee_model_append(model, "qoo", 8); | ||
738 | 179 | |||
739 | 180 | QCOMPARE(num_insertions, 0); | ||
740 | 181 | |||
741 | 182 | dee_model_end_changeset(model); | ||
742 | 183 | |||
743 | 184 | QCOMPARE(num_insertions, 1); | ||
744 | 185 | QCOMPARE(model_qt.count(), 4); | ||
745 | 186 | QCOMPARE(model_qt.rowCount(), 4); | ||
746 | 187 | |||
747 | 188 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
748 | 189 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
749 | 190 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("bar")); | ||
750 | 191 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 6); | ||
751 | 192 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 0).toString(), QString("baz")); | ||
752 | 193 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 1).toInt(), 7); | ||
753 | 194 | QCOMPARE(model_qt.data(model_qt.index(3, 0), 0).toString(), QString("qoo")); | ||
754 | 195 | QCOMPARE(model_qt.data(model_qt.index(3, 0), 1).toInt(), 8); | ||
755 | 196 | |||
756 | 197 | QVariantMap row2 = model_qt.get(2); | ||
757 | 198 | QCOMPARE(row2["column_0"].toString(), QString("baz")); | ||
758 | 199 | QCOMPARE(row2["column_1"].toInt(), 7); | ||
759 | 200 | } | ||
760 | 201 | |||
761 | 202 | void emitConsecutiveRemovalsTest() | ||
762 | 203 | { | ||
763 | 204 | DeeModel* model = dee_sequence_model_new(); | ||
764 | 205 | dee_model_set_schema(model, "s", "i", NULL); | ||
765 | 206 | |||
766 | 207 | DeeListModel model_qt; | ||
767 | 208 | model_qt.setModel(model); | ||
768 | 209 | |||
769 | 210 | dee_model_append(model, "foo", 5); | ||
770 | 211 | dee_model_append(model, "bar", 6); | ||
771 | 212 | dee_model_append(model, "baz", 7); | ||
772 | 213 | dee_model_append(model, "qoo", 8); | ||
773 | 214 | |||
774 | 215 | QCOMPARE(model_qt.count(), 4); | ||
775 | 216 | QCOMPARE(model_qt.rowCount(), 4); | ||
776 | 217 | |||
777 | 218 | int num_removals = 0; | ||
778 | 219 | |||
779 | 220 | connect(&model_qt, &QAbstractItemModel::rowsRemoved, [&num_removals] (const QModelIndex &parent, int start, int end) { | ||
780 | 221 | num_removals++; | ||
781 | 222 | }); | ||
782 | 223 | |||
783 | 224 | dee_model_begin_changeset(model); | ||
784 | 225 | |||
785 | 226 | dee_model_clear(model); | ||
786 | 227 | |||
787 | 228 | dee_model_end_changeset(model); | ||
788 | 229 | |||
789 | 230 | QCOMPARE(num_removals, 1); | ||
790 | 231 | QCOMPARE(model_qt.count(), 0); | ||
791 | 232 | QCOMPARE(model_qt.rowCount(), 0); | ||
792 | 233 | } | ||
793 | 234 | |||
794 | 235 | void emitConsecutiveInsertsWithChangeTest() | ||
795 | 236 | { | ||
796 | 237 | DeeModel* model = dee_sequence_model_new(); | ||
797 | 238 | dee_model_set_schema(model, "s", "i", NULL); | ||
798 | 239 | |||
799 | 240 | DeeListModel model_qt; | ||
800 | 241 | model_qt.setModel(model); | ||
801 | 242 | |||
802 | 243 | int num_insertions = 0; | ||
803 | 244 | |||
804 | 245 | connect(&model_qt, &QAbstractItemModel::rowsInserted, [&num_insertions] (const QModelIndex &parent, int start, int end) { | ||
805 | 246 | num_insertions++; | ||
806 | 247 | }); | ||
807 | 248 | |||
808 | 249 | dee_model_begin_changeset(model); | ||
809 | 250 | |||
810 | 251 | dee_model_append(model, "koo", -5); | ||
811 | 252 | dee_model_append(model, "bar", 6); | ||
812 | 253 | dee_model_append(model, "baz", 7); | ||
813 | 254 | dee_model_set(model, dee_model_get_first_iter(model), "foo", 5); | ||
814 | 255 | dee_model_append(model, "qoo", 8); | ||
815 | 256 | |||
816 | 257 | QCOMPARE(num_insertions, 1); | ||
817 | 258 | QCOMPARE(model_qt.count(), 3); | ||
818 | 259 | QCOMPARE(model_qt.rowCount(), 3); | ||
819 | 260 | |||
820 | 261 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
821 | 262 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
822 | 263 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("bar")); | ||
823 | 264 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 6); | ||
824 | 265 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 0).toString(), QString("baz")); | ||
825 | 266 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 1).toInt(), 7); | ||
826 | 267 | |||
827 | 268 | dee_model_end_changeset(model); | ||
828 | 269 | |||
829 | 270 | QCOMPARE(num_insertions, 2); | ||
830 | 271 | QCOMPARE(model_qt.count(), 4); | ||
831 | 272 | QCOMPARE(model_qt.rowCount(), 4); | ||
832 | 273 | |||
833 | 274 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
834 | 275 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
835 | 276 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("bar")); | ||
836 | 277 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 6); | ||
837 | 278 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 0).toString(), QString("baz")); | ||
838 | 279 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 1).toInt(), 7); | ||
839 | 280 | QCOMPARE(model_qt.data(model_qt.index(3, 0), 0).toString(), QString("qoo")); | ||
840 | 281 | QCOMPARE(model_qt.data(model_qt.index(3, 0), 1).toInt(), 8); | ||
841 | 282 | } | ||
842 | 283 | |||
843 | 284 | void emitSignalsMixedTest() | ||
844 | 285 | { | ||
845 | 286 | DeeModel* model = dee_sequence_model_new(); | ||
846 | 287 | dee_model_set_schema(model, "s", "i", NULL); | ||
847 | 288 | |||
848 | 289 | DeeListModel model_qt; | ||
849 | 290 | model_qt.setModel(model); | ||
850 | 291 | |||
851 | 292 | int num_insertions = 0; | ||
852 | 293 | int num_removals = 0; | ||
853 | 294 | |||
854 | 295 | connect(&model_qt, &QAbstractItemModel::rowsInserted, [&num_insertions] (const QModelIndex &parent, int start, int end) { | ||
855 | 296 | num_insertions++; | ||
856 | 297 | }); | ||
857 | 298 | |||
858 | 299 | connect(&model_qt, &QAbstractItemModel::rowsRemoved, [&num_removals] (const QModelIndex &parent, int start, int end) { | ||
859 | 300 | num_removals++; | ||
860 | 301 | }); | ||
861 | 302 | |||
862 | 303 | dee_model_begin_changeset(model); | ||
863 | 304 | |||
864 | 305 | dee_model_append(model, "foo", 5); | ||
865 | 306 | dee_model_append(model, "bar", 6); | ||
866 | 307 | dee_model_append(model, "baz", 7); | ||
867 | 308 | dee_model_append(model, "qoo", 8); | ||
868 | 309 | |||
869 | 310 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
870 | 311 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
871 | 312 | |||
872 | 313 | dee_model_end_changeset(model); | ||
873 | 314 | |||
874 | 315 | QCOMPARE(num_insertions, 1); | ||
875 | 316 | QCOMPARE(num_removals, 1); | ||
876 | 317 | QCOMPARE(model_qt.count(), 2); | ||
877 | 318 | QCOMPARE(model_qt.rowCount(), 2); | ||
878 | 319 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("baz")); | ||
879 | 320 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 7); | ||
880 | 321 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("qoo")); | ||
881 | 322 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 8); | ||
882 | 323 | |||
883 | 324 | // continue with more changes that aren't consecutive | ||
884 | 325 | num_insertions = 0; | ||
885 | 326 | num_removals = 0; | ||
886 | 327 | |||
887 | 328 | dee_model_begin_changeset(model); | ||
888 | 329 | |||
889 | 330 | dee_model_append(model, "foo", 5); | ||
890 | 331 | dee_model_remove(model, dee_model_get_iter_at_row(model, 1)); | ||
891 | 332 | dee_model_remove(model, dee_model_get_iter_at_row(model, 0)); | ||
892 | 333 | dee_model_prepend(model, "qoo", 8); | ||
893 | 334 | |||
894 | 335 | dee_model_end_changeset(model); | ||
895 | 336 | |||
896 | 337 | QCOMPARE(num_insertions, 2); | ||
897 | 338 | QCOMPARE(num_removals, 2); | ||
898 | 339 | QCOMPARE(model_qt.count(), 2); | ||
899 | 340 | QCOMPARE(model_qt.rowCount(), 2); | ||
900 | 341 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("qoo")); | ||
901 | 342 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 8); | ||
902 | 343 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("foo")); | ||
903 | 344 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 5); | ||
904 | 345 | |||
905 | 346 | // and once again | ||
906 | 347 | num_insertions = 0; | ||
907 | 348 | num_removals = 0; | ||
908 | 349 | |||
909 | 350 | dee_model_begin_changeset(model); | ||
910 | 351 | |||
911 | 352 | dee_model_remove(model, dee_model_get_first_iter(model)); // ++ rem | ||
912 | 353 | dee_model_append(model, "foo", 5); // ++ ins | ||
913 | 354 | dee_model_clear(model); // ++ rem | ||
914 | 355 | dee_model_append(model, "baz", 7); | ||
915 | 356 | dee_model_append(model, "qoo", 8); | ||
916 | 357 | dee_model_prepend(model, "bar", 6); | ||
917 | 358 | dee_model_prepend(model, "foo", 5); | ||
918 | 359 | |||
919 | 360 | dee_model_end_changeset(model); | ||
920 | 361 | |||
921 | 362 | QCOMPARE(num_insertions, 4); | ||
922 | 363 | QCOMPARE(num_removals, 2); | ||
923 | 364 | QCOMPARE(model_qt.count(), 4); | ||
924 | 365 | QCOMPARE(model_qt.rowCount(), 4); | ||
925 | 366 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
926 | 367 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
927 | 368 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("bar")); | ||
928 | 369 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 6); | ||
929 | 370 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 0).toString(), QString("baz")); | ||
930 | 371 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 1).toInt(), 7); | ||
931 | 372 | QCOMPARE(model_qt.data(model_qt.index(3, 0), 0).toString(), QString("qoo")); | ||
932 | 373 | QCOMPARE(model_qt.data(model_qt.index(3, 0), 1).toInt(), 8); | ||
933 | 374 | } | ||
934 | 375 | |||
935 | 376 | void readDuringTransactionTest() | ||
936 | 377 | { | ||
937 | 378 | DeeModel* model = dee_sequence_model_new(); | ||
938 | 379 | dee_model_set_schema(model, "s", "i", NULL); | ||
939 | 380 | |||
940 | 381 | DeeListModel model_qt; | ||
941 | 382 | model_qt.setModel(model); | ||
942 | 383 | |||
943 | 384 | int num_insertions = 0; | ||
944 | 385 | int num_removals = 0; | ||
945 | 386 | int state = 0; | ||
946 | 387 | |||
947 | 388 | connect(&model_qt, &QAbstractItemModel::rowsInserted, [&] (const QModelIndex &parent, int start, int end) { | ||
948 | 389 | num_insertions++; | ||
949 | 390 | QVERIFY(state >= 0 && state <= 2); | ||
950 | 391 | if (state == 0) { | ||
951 | 392 | QCOMPARE(start, 0); | ||
952 | 393 | QCOMPARE(end, 1); | ||
953 | 394 | QCOMPARE(model_qt.rowCount(), 2); | ||
954 | 395 | QCOMPARE(model_qt.count(), 2); | ||
955 | 396 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
956 | 397 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
957 | 398 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("baz")); | ||
958 | 399 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 7); | ||
959 | 400 | } else if (state == 1) { | ||
960 | 401 | QCOMPARE(start, 0); | ||
961 | 402 | QCOMPARE(end, 0); | ||
962 | 403 | QCOMPARE(model_qt.rowCount(), 3); | ||
963 | 404 | QCOMPARE(model_qt.count(), 3); | ||
964 | 405 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("bar")); | ||
965 | 406 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 6); | ||
966 | 407 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("foo")); | ||
967 | 408 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 5); | ||
968 | 409 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 0).toString(), QString("baz")); | ||
969 | 410 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 1).toInt(), 7); | ||
970 | 411 | } else if (state == 2) { | ||
971 | 412 | QCOMPARE(start, 1); | ||
972 | 413 | QCOMPARE(end, 1); | ||
973 | 414 | QCOMPARE(model_qt.rowCount(), 2); | ||
974 | 415 | QCOMPARE(model_qt.count(), 2); | ||
975 | 416 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("baz")); | ||
976 | 417 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 7); | ||
977 | 418 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("qoo")); | ||
978 | 419 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 8); | ||
979 | 420 | } | ||
980 | 421 | }); | ||
981 | 422 | |||
982 | 423 | connect(&model_qt, &QAbstractItemModel::rowsRemoved, [&] (const QModelIndex &parent, int start, int end) { | ||
983 | 424 | num_removals++; | ||
984 | 425 | QVERIFY(state >= 2 && state <= 2); | ||
985 | 426 | if (state == 2) { | ||
986 | 427 | QCOMPARE(start, 0); | ||
987 | 428 | QCOMPARE(end, 1); | ||
988 | 429 | QCOMPARE(model_qt.rowCount(), 1); | ||
989 | 430 | QCOMPARE(model_qt.count(), 1); | ||
990 | 431 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("baz")); | ||
991 | 432 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 7); | ||
992 | 433 | } | ||
993 | 434 | }); | ||
994 | 435 | |||
995 | 436 | dee_model_begin_changeset(model); | ||
996 | 437 | |||
997 | 438 | dee_model_append(model, "foo", 5); | ||
998 | 439 | dee_model_append(model, "baz", 7); | ||
999 | 440 | dee_model_prepend(model, "bar", 6); | ||
1000 | 441 | |||
1001 | 442 | state = 1; | ||
1002 | 443 | |||
1003 | 444 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
1004 | 445 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
1005 | 446 | |||
1006 | 447 | state = 2; | ||
1007 | 448 | |||
1008 | 449 | dee_model_append(model, "qoo", 8); | ||
1009 | 450 | |||
1010 | 451 | dee_model_end_changeset(model); | ||
1011 | 452 | |||
1012 | 453 | QCOMPARE(num_insertions, 3); | ||
1013 | 454 | QCOMPARE(num_removals, 1); | ||
1014 | 455 | QCOMPARE(model_qt.count(), 2); | ||
1015 | 456 | QCOMPARE(model_qt.rowCount(), 2); | ||
1016 | 457 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("baz")); | ||
1017 | 458 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 7); | ||
1018 | 459 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("qoo")); | ||
1019 | 460 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 8); | ||
1020 | 461 | } | ||
1021 | 462 | |||
1022 | 463 | void readOutsideOfTransactionTest() | ||
1023 | 464 | { | ||
1024 | 465 | DeeModel* model = dee_sequence_model_new(); | ||
1025 | 466 | dee_model_set_schema(model, "s", "i", NULL); | ||
1026 | 467 | |||
1027 | 468 | DeeListModel model_qt; | ||
1028 | 469 | model_qt.setModel(model); | ||
1029 | 470 | |||
1030 | 471 | int num_insertions = 0; | ||
1031 | 472 | int num_removals = 0; | ||
1032 | 473 | int state = 0; | ||
1033 | 474 | |||
1034 | 475 | connect(&model_qt, &QAbstractItemModel::rowsInserted, [&] (const QModelIndex &parent, int start, int end) { | ||
1035 | 476 | num_insertions++; | ||
1036 | 477 | QVERIFY((state >= 0 && state <= 2) || state == 5); | ||
1037 | 478 | if (state == 0) { | ||
1038 | 479 | QCOMPARE(start, 0); | ||
1039 | 480 | QCOMPARE(end, 0); | ||
1040 | 481 | QCOMPARE(model_qt.rowCount(), 1); | ||
1041 | 482 | QCOMPARE(model_qt.count(), 1); | ||
1042 | 483 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
1043 | 484 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
1044 | 485 | } else if (state == 1) { | ||
1045 | 486 | QCOMPARE(start, 1); | ||
1046 | 487 | QCOMPARE(end, 1); | ||
1047 | 488 | QCOMPARE(model_qt.rowCount(), 2); | ||
1048 | 489 | QCOMPARE(model_qt.count(), 2); | ||
1049 | 490 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
1050 | 491 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
1051 | 492 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("baz")); | ||
1052 | 493 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 7); | ||
1053 | 494 | } else if (state == 2) { | ||
1054 | 495 | QCOMPARE(start, 0); | ||
1055 | 496 | QCOMPARE(end, 0); | ||
1056 | 497 | QCOMPARE(model_qt.rowCount(), 3); | ||
1057 | 498 | QCOMPARE(model_qt.count(), 3); | ||
1058 | 499 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("bar")); | ||
1059 | 500 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 6); | ||
1060 | 501 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("foo")); | ||
1061 | 502 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 5); | ||
1062 | 503 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 0).toString(), QString("baz")); | ||
1063 | 504 | QCOMPARE(model_qt.data(model_qt.index(2, 0), 1).toInt(), 7); | ||
1064 | 505 | } else if (state == 5) { | ||
1065 | 506 | QCOMPARE(start, 1); | ||
1066 | 507 | QCOMPARE(end, 1); | ||
1067 | 508 | QCOMPARE(model_qt.rowCount(), 2); | ||
1068 | 509 | QCOMPARE(model_qt.count(), 2); | ||
1069 | 510 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("baz")); | ||
1070 | 511 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 7); | ||
1071 | 512 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("qoo")); | ||
1072 | 513 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 8); | ||
1073 | 514 | } | ||
1074 | 515 | }); | ||
1075 | 516 | |||
1076 | 517 | connect(&model_qt, &QAbstractItemModel::rowsRemoved, [&] (const QModelIndex &parent, int start, int end) { | ||
1077 | 518 | num_removals++; | ||
1078 | 519 | QVERIFY(state >= 3 && state <= 4); | ||
1079 | 520 | if (state == 3) { | ||
1080 | 521 | QCOMPARE(start, 0); | ||
1081 | 522 | QCOMPARE(end, 0); | ||
1082 | 523 | QCOMPARE(model_qt.rowCount(), 2); | ||
1083 | 524 | QCOMPARE(model_qt.count(), 2); | ||
1084 | 525 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("foo")); | ||
1085 | 526 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 5); | ||
1086 | 527 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("baz")); | ||
1087 | 528 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 7); | ||
1088 | 529 | } else if (state == 4) { | ||
1089 | 530 | QCOMPARE(start, 0); | ||
1090 | 531 | QCOMPARE(end, 0); | ||
1091 | 532 | QCOMPARE(model_qt.rowCount(), 1); | ||
1092 | 533 | QCOMPARE(model_qt.count(), 1); | ||
1093 | 534 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("baz")); | ||
1094 | 535 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 7); | ||
1095 | 536 | } | ||
1096 | 537 | }); | ||
1097 | 538 | |||
1098 | 539 | dee_model_append(model, "foo", 5); | ||
1099 | 540 | |||
1100 | 541 | state = 1; | ||
1101 | 542 | |||
1102 | 543 | dee_model_append(model, "baz", 7); | ||
1103 | 544 | |||
1104 | 545 | state = 2; | ||
1105 | 546 | |||
1106 | 547 | dee_model_prepend(model, "bar", 6); | ||
1107 | 548 | |||
1108 | 549 | state = 3; | ||
1109 | 550 | |||
1110 | 551 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
1111 | 552 | |||
1112 | 553 | state = 4; | ||
1113 | 554 | |||
1114 | 555 | dee_model_remove(model, dee_model_get_first_iter(model)); | ||
1115 | 556 | |||
1116 | 557 | state = 5; | ||
1117 | 558 | |||
1118 | 559 | dee_model_append(model, "qoo", 8); | ||
1119 | 560 | |||
1120 | 561 | QCOMPARE(num_insertions, 4); | ||
1121 | 562 | QCOMPARE(num_removals, 2); | ||
1122 | 563 | QCOMPARE(model_qt.count(), 2); | ||
1123 | 564 | QCOMPARE(model_qt.rowCount(), 2); | ||
1124 | 565 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 0).toString(), QString("baz")); | ||
1125 | 566 | QCOMPARE(model_qt.data(model_qt.index(0, 0), 1).toInt(), 7); | ||
1126 | 567 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 0).toString(), QString("qoo")); | ||
1127 | 568 | QCOMPARE(model_qt.data(model_qt.index(1, 0), 1).toInt(), 8); | ||
1128 | 569 | } | ||
1129 | 570 | }; | ||
1130 | 571 | |||
1131 | 572 | QTEST_MAIN(DeeListModelTest) | ||
1132 | 573 | |||
1133 | 574 | #include "signaltest.moc" |
FAILED: Continuous integration, rev:88 jenkins. qa.ubuntu. com/job/ dee-qt- ci/10/ jenkins. qa.ubuntu. com/job/ dee-qt- saucy-amd64- ci/8/console jenkins. qa.ubuntu. com/job/ dee-qt- saucy-armhf- ci/6/console
http://
Executed test runs:
FAILURE: http://
FAILURE: http://
Click here to trigger a rebuild: s-jenkins: 8080/job/ dee-qt- ci/10/rebuild
http://