1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
|
// Copyright (C) 2025 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR BSD-3-Clause
#include "datastorage.h"
#include "queueworker.h"
DataStorage::DataStorage() : QObject{ nullptr }
{
/* Generate a list of IDs to use locally.
* DataStorage will use indexes for accessing the remote data.
*/
m_idList.reserve(RemoteMedia::count());
for (int id = 1; id <= RemoteMedia::count(); ++id) {
m_idList.append(id);
}
m_worker = new QueueWorker;
connect(&m_workerThread, &QThread::finished, m_worker, &QObject::deleteLater);
m_worker->moveToThread(&m_workerThread);
connect(m_worker, &QueueWorker::dataFetched, this, &DataStorage::dataReceived);
connect(m_worker, &QueueWorker::processing, this, &DataStorage::fetchStarted);
connect(m_worker, &QueueWorker::dropped, this, &DataStorage::fetchAborted);
connect(this, &DataStorage::dataFetchNeeded, m_worker, &QueueWorker::fetchData);
m_workerThread.start();
}
DataStorage::~DataStorage()
{
/* Clean the worker object by stopping it and then ending the thread */
m_worker->abort();
m_worker = nullptr;
m_workerThread.quit();
m_workerThread.wait();
}
QList<int> DataStorage::idList()
{
return m_idList;
}
MediaElement DataStorage::item(int id) const
{
if (id < 1)
return MediaElement{};
//! [Send signal if no data]
if (!m_items.contains(id)) {
m_items.insert(id, MediaElement{});
emit dataFetchNeeded(m_idList.indexOf(id));
}
return m_items.value(id);
//! [Send signal if no data]
}
std::optional<int> DataStorage::currentlyFetchedId() const
{
return m_currentlyFetchedId;
}
void DataStorage::fetchStarted(int index)
{
const auto idBeingFetched = m_idList.at(index);
m_currentlyFetchedId = idBeingFetched;
emit dataUpdated(idBeingFetched);
}
void DataStorage::fetchAborted(int index)
{
/* The data will never be fetched. Remove the empty item (so storge will send a signal to thread
* if needed). Then send dataUpdated signal. If the item is still visible, view will re-request
* its data and item will be requeued to thread. If item is no longer in visible area, view will
* ignore the dataChanged signal and storage will not receive any calls.
*/
const auto idAborted = m_idList.at(index);
m_items.remove(idAborted);
if (m_currentlyFetchedId == idAborted)
m_currentlyFetchedId = std::nullopt;
emit dataUpdated(idAborted);
}
void DataStorage::dataReceived(int index, MediaElement element)
{
const auto idUpdated = m_idList.at(index);
m_items.insert(idUpdated, element);
emit dataUpdated(idUpdated);
}
|