@@ -89,7 +89,11 @@ void ConnectionLine::updatePosition() {
89
89
90
90
// NoteRelationScene Implementation
91
91
NoteRelationScene::NoteRelationScene (QObject *parent)
92
- : QGraphicsScene(parent), m_connecting(false ), m_tempLine(nullptr ), m_startItem(nullptr ) {}
92
+ : QGraphicsScene(parent), m_connecting(false ), m_tempLine(nullptr ), m_startItem(nullptr ) {
93
+ // Connect the signal to the slot with a queued connection
94
+ connect (this , &NoteRelationScene::addItemRequested, this , &NoteRelationScene::addItemToScene,
95
+ Qt::QueuedConnection);
96
+ }
93
97
94
98
void NoteRelationScene::mouseMoveEvent (QGraphicsSceneMouseEvent *event) {
95
99
if (m_connecting && m_tempLine && m_startItem) {
@@ -130,48 +134,90 @@ NoteItem *NoteRelationScene::createNoteItem(const QPointF &pos, Note note, int l
130
134
auto *noteItem = new NoteItem (note, 0 , 0 , xpos, ypos, level);
131
135
noteItem->setPos (posPoint);
132
136
// The scene is taking ownership over the note item
133
- addItem (noteItem);
137
+ // addItem(noteItem);
138
+ emit addItemRequested (noteItem);
134
139
135
140
return noteItem;
136
141
}
137
142
138
143
void NoteRelationScene::createConnection (NoteItem *startItem, NoteItem *endItem) {
139
144
auto *connection = new ConnectionLine (startItem, endItem);
140
- addItem (connection);
145
+ // addItem(connection);
146
+ emit addItemRequested (connection);
141
147
m_connections.push_back (connection);
142
148
}
143
149
144
- void NoteRelationScene::drawForNote (const Note& note) {
150
+ void NoteRelationScene::addItemToScene (QGraphicsItem *item) {
151
+ // This will run in the GUI thread
152
+ addItem (item);
153
+ }
154
+
155
+ void NoteRelationScene::drawForNote (const Note ¬e) {
156
+ qDebug () << __func__
157
+ << " - 'this->m_drawFuture.isRunning()': " << this ->m_drawFuture .isRunning ();
158
+ // Disallow more drawing and cancel the current thread
159
+ stopDrawing ();
160
+
161
+ // Fetch all notes while waiting for the previous thread to finish
162
+ const auto noteList = Note::fetchAll ();
163
+
164
+ // Wait a little more for if the thread is still running
165
+ if (this ->m_drawFuture .isRunning ()) {
166
+ this ->m_drawFuture .waitForFinished ();
167
+ }
168
+
169
+ // Allow drawing again and clear the scene
170
+ setAllowDrawing ();
145
171
m_connections.clear ();
146
172
clear ();
147
- const auto noteList = Note::fetchAll ();
148
173
149
- #if QT_VERSION >= QT_VERSION_CHECK(5, 4, 0)
150
- QFuture<void > future = QtConcurrent::run ([this , note, noteList]() {
174
+ // This runs the gathering of note relations in a different thread
175
+ // The drawing of the note items and connections will be done in the GUI thread, because the
176
+ // QGraphicsView framework is not designed for multithreading (QTimer errors)
177
+ // A different database connection to the memory database will also be use, because you cannot
178
+ // use the same connection in different threads
179
+ this ->m_drawFuture = QtConcurrent::run ([this , note, noteList]() {
151
180
const QString connectionName = DatabaseService::generateConnectionName ();
152
- qDebug () << __func__ << " - 'connectionName': " << connectionName;
153
181
154
- QSqlDatabase db = DatabaseService::createSharedMemoryDatabase (connectionName);
182
+ {
183
+ QSqlDatabase db = DatabaseService::createSharedMemoryDatabase (connectionName);
155
184
156
- auto rootNoteItem = createNoteItem (QPointF (100 , 100 ), note);
157
- createLinkedNoteItems (noteList, connectionName, note, rootNoteItem);
185
+ auto rootNoteItem = createNoteItem (QPointF (100 , 100 ), note);
186
+ createLinkedNoteItems (noteList, connectionName, note, rootNoteItem);
158
187
159
- // Update all connections
160
- for (auto connection : m_connections) {
161
- connection->updatePosition ();
162
- }
188
+ // Update all connections
189
+ for (auto connection : m_connections) {
190
+ connection->updatePosition ();
191
+ }
163
192
164
- // Update the scene
165
- update ();
193
+ // Update the scene
194
+ update ();
166
195
167
- db.close ();
196
+ db.close ();
197
+ } // db goes out of scope and is removed, so the database can be removed
198
+
199
+ // Remove database connection after the database is closed
168
200
QSqlDatabase::removeDatabase (connectionName);
169
- qDebug () << __func__ << " - 'connectionName' closed: " << connectionName;
170
201
});
171
- #endif
172
202
}
173
203
174
- void NoteRelationScene::createLinkedNoteItems (const QVector<Note>& noteList, const QString &connectionName, Note note, NoteItem *rootNoteItem, int level) {
204
+ void NoteRelationScene::stopDrawing () {
205
+ if (m_drawFuture.isRunning ()) {
206
+ // Disallow more drawing and cancel the thread
207
+ setAllowDrawing (false );
208
+ m_drawFuture.cancel ();
209
+ }
210
+ }
211
+
212
+ void NoteRelationScene::setAllowDrawing (bool allow) { m_allowDrawing = allow; }
213
+
214
+ void NoteRelationScene::createLinkedNoteItems (const QVector<Note> ¬eList,
215
+ const QString &connectionName, Note note,
216
+ NoteItem *rootNoteItem, int level) {
217
+ if (!this ->m_allowDrawing ) {
218
+ return ;
219
+ }
220
+
175
221
auto linkedNotes = note.findLinkedNotes (noteList, connectionName);
176
222
177
223
// Get root note position (center)
@@ -190,9 +236,13 @@ void NoteRelationScene::createLinkedNoteItems(const QVector<Note>& noteList, con
190
236
int index = 0 ;
191
237
level = level + 1 ;
192
238
for (auto it = linkedNotes.begin (); it != linkedNotes.end (); ++it) {
239
+ if (!this ->m_allowDrawing ) {
240
+ break ;
241
+ }
242
+
193
243
// Calculate position in a circle around the root note item
194
244
QPointF notePos = calculateRadialPosition (rootCenter, index , linkedNotes.size (), radius);
195
- const Note& linkedNote = it.key ();
245
+ const Note & linkedNote = it.key ();
196
246
197
247
// Create note item at calculated position
198
248
NoteItem *linkedNoteItem = createNoteItem (notePos, linkedNote, level);
0 commit comments