Skip to content

Commit

Permalink
Merge pull request #1045 from kiwix/refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
mgautierfr authored Mar 7, 2024
2 parents 6c03254 + 5d28f8a commit 75ecdeb
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 136 deletions.
90 changes: 64 additions & 26 deletions src/contentmanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ ContentManager::ContentManager(Library* library, kiwix::Downloader* downloader,
connect(&m_remoteLibraryManager, &OpdsRequestManager::categoriesReceived, this, &ContentManager::updateCategories);
setCategories();
setLanguages();

m_downloadUpdateTimer.start(1000);
connect(&m_downloadUpdateTimer, &QTimer::timeout,
this, &ContentManager::updateDownloads);
}

ContentManager::BookInfoList ContentManager::getBooksList()
Expand Down Expand Up @@ -159,7 +163,7 @@ void ContentManager::onCustomContextMenu(const QPoint &point)
QAction menuOpenFolder(gt("open-folder"), this);

if (const auto download = bookNode->getDownloadState()) {
if (download->getDownloadInfo().paused) {
if (download->paused) {
contextMenu.addAction(&menuResumeBook);
} else {
contextMenu.addAction(&menuPauseBook);
Expand Down Expand Up @@ -406,8 +410,15 @@ void ContentManager::downloadStarted(const kiwix::Book& book, const std::string&
emit(oneBookChanged(QString::fromStdString(book.getId())));
}

void ContentManager::removeDownload(QString bookId)
{
m_downloads.remove(bookId);
managerModel->removeDownload(bookId);
}

void ContentManager::downloadCancelled(QString bookId)
{
removeDownload(bookId);
kiwix::Book bCopy(mp_library->getBookById(bookId));
bCopy.setDownloadId("");
mp_library->getKiwixLibrary()->addOrUpdateBook(bCopy);
Expand All @@ -417,6 +428,7 @@ void ContentManager::downloadCancelled(QString bookId)

void ContentManager::downloadCompleted(QString bookId, QString path)
{
removeDownload(bookId);
kiwix::Book bCopy(mp_library->getBookById(bookId));
bCopy.setPath(QDir::toNativeSeparators(path).toStdString());
bCopy.setDownloadId("");
Expand All @@ -433,7 +445,7 @@ void ContentManager::downloadCompleted(QString bookId, QString path)
}
}

ContentManager::DownloadInfo ContentManager::getDownloadInfo(QString bookId, const QStringList &keys) const
DownloadInfo ContentManager::getDownloadInfo(QString bookId, const QStringList &keys) const
{
DownloadInfo values;
if (!mp_downloader) {
Expand All @@ -460,28 +472,49 @@ ContentManager::DownloadInfo ContentManager::getDownloadInfo(QString bookId, con
return values;
}

ContentManager::DownloadInfo ContentManager::updateDownloadInfos(QString bookId, QStringList keys)
void ContentManager::updateDownload(QString bookId)
{
if ( !keys.contains("status") ) keys.append("status");
if ( !keys.contains("path") ) keys.append("path");
const auto downloadState = m_downloads.value(bookId);
if ( downloadState && !downloadState->paused ) {
const auto downloadInfo = getDownloadInfo(bookId, {"status", "completedLength", "totalLength", "downloadSpeed", "path"});

const DownloadInfo result = getDownloadInfo(bookId, keys);
if ( downloadInfo.isEmpty() ) {
downloadCancelled(bookId);
} else if ( downloadInfo["status"] == "completed" ) {
downloadCompleted(bookId, downloadInfo["path"].toString());
} else {
downloadState->update(downloadInfo);
managerModel->updateDownload(bookId);
}
}
}

if ( result.isEmpty() ) {
downloadCancelled(bookId);
} else if ( result["status"] == "completed" ) {
downloadCompleted(bookId, result["path"].toString());
void ContentManager::updateDownloads()
{
for ( const auto& bookId : m_downloads.keys() ) {
updateDownload(bookId);
}
}

return result;
namespace
{

std::shared_ptr<RowNode> getSharedPointer(RowNode* ptr)
{
return std::static_pointer_cast<RowNode>(ptr->shared_from_this());
}

} // unnamed namespace

void ContentManager::downloadBook(const QString &id, QModelIndex index)
{
try
{
downloadBook(id);
emit managerModel->startDownload(index);
auto node = getSharedPointer(static_cast<RowNode*>(index.internalPointer()));
const auto newDownload = std::make_shared<DownloadState>();
m_downloads[id] = newDownload;
node->setDownloadState(newDownload);
}
catch ( const ContentManagerError& err )
{
Expand All @@ -499,30 +532,33 @@ const kiwix::Book& ContentManager::getRemoteOrLocalBook(const QString &id)
}
}

std::string ContentManager::startDownload(const kiwix::Book& book)
{
auto downloadPath = KiwixApp::instance()->getSettingsManager()->getDownloadDir();
checkEnoughStorageAvailable(book, downloadPath);

typedef std::vector<std::pair<std::string, std::string>> DownloadOptions;

const DownloadOptions downloadOptions{{"dir", downloadPath.toStdString()}};

const auto d = mp_downloader->startDownload(book.getUrl(), downloadOptions);
return d->getDid();
}

void ContentManager::downloadBook(const QString &id)
{
if (!mp_downloader)
throwDownloadUnavailableError();

const auto& book = getRemoteOrLocalBook(id);
auto downloadPath = KiwixApp::instance()->getSettingsManager()->getDownloadDir();
checkEnoughStorageAvailable(book, downloadPath);

auto booksList = mp_library->getBookIds();
for (auto b : booksList) {
if (b.toStdString() == book.getId())
throwDownloadUnavailableError(); // but why???
}

std::shared_ptr<kiwix::Download> download;
std::string downloadId;
try {
std::pair<std::string, std::string> downloadDir("dir", downloadPath.toStdString());
const std::vector<std::pair<std::string, std::string>> options = { downloadDir };
download = mp_downloader->startDownload(book.getUrl(), options);
downloadId = startDownload(book);
} catch (std::exception& e) {
throwDownloadUnavailableError();
}
downloadStarted(book, download->getDid());
downloadStarted(book, downloadId);
}

void ContentManager::eraseBookFilesFromComputer(const QString dirPath, const QString fileName, const bool moveToTrash)
Expand Down Expand Up @@ -632,7 +668,7 @@ void ContentManager::cancelBook(const QString& id, QModelIndex index)
text = text.replace("{{ZIM}}", QString::fromStdString(mp_library->getBookById(id).getTitle()));
showConfirmBox(gt("cancel-download"), text, mp_view, [=]() {
cancelBook(id);
emit managerModel->cancelDownload(index);
emit managerModel->removeDownload(id);
});
}

Expand All @@ -646,6 +682,8 @@ void ContentManager::cancelBook(const QString& id)
if (download->getStatus() != kiwix::Download::K_COMPLETE) {
download->cancelDownload();
}
m_downloads.remove(id);

QString dirPath = QString::fromStdString(kiwix::removeLastPathElement(download->getPath()));
QString filename = QString::fromStdString(kiwix::getLastPathElement(download->getPath())) + "*";
// incompleted downloaded file should be perma deleted
Expand Down
9 changes: 5 additions & 4 deletions src/contentmanager.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,6 @@ class ContentManager : public QObject
typedef ContentManagerModel::BookInfo BookInfo;
typedef ContentManagerModel::BookInfoList BookInfoList;

// XXX: potentional source of confusion with ::DownloadInfo from rownode.h
typedef QMap<QString, QVariant> DownloadInfo;

public: // functions
explicit ContentManager(Library* library, kiwix::Downloader *downloader, QObject *parent = nullptr);
virtual ~ContentManager() {}
Expand Down Expand Up @@ -52,7 +49,6 @@ public slots:
QStringList getTranslations(const QStringList &keys);
BookInfo getBookInfos(QString id, const QStringList &keys);
void openBook(const QString& id);
DownloadInfo updateDownloadInfos(QString bookId, QStringList keys);
void downloadBook(const QString& id);
void downloadBook(const QString& id, QModelIndex index);
void updateLibrary();
Expand All @@ -71,6 +67,7 @@ public slots:
void cancelBook(const QString& id, QModelIndex index);
void onCustomContextMenu(const QPoint &point);
void openBookWithIndex(const QModelIndex& index);
void updateDownloads();

private: // functions
QStringList getBookIds();
Expand All @@ -85,6 +82,9 @@ public slots:
// the remote or local library (in that order).
const kiwix::Book& getRemoteOrLocalBook(const QString &id);

std::string startDownload(const kiwix::Book& book);
void updateDownload(QString bookId);
void removeDownload(QString bookId);
void downloadStarted(const kiwix::Book& book, const std::string& downloadId);
void downloadCancelled(QString bookId);
void downloadCompleted(QString bookId, QString path);
Expand All @@ -95,6 +95,7 @@ public slots:
kiwix::LibraryPtr mp_remoteLibrary;
kiwix::Downloader* mp_downloader;
ContentManagerModel::Downloads m_downloads;
QTimer m_downloadUpdateTimer;
OpdsRequestManager m_remoteLibraryManager;
ContentManagerView* mp_view;
bool m_local = true;
Expand Down
7 changes: 3 additions & 4 deletions src/contentmanagerdelegate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ void createDownloadStats(QPainter *painter, QRect box, QString downloadSpeed, QS
painter->setFont(oldFont);
}

void showDownloadProgress(QPainter *painter, QRect box, DownloadInfo downloadInfo)
void showDownloadProgress(QPainter *painter, QRect box, const DownloadState& downloadInfo)
{
int x,y,w,h;
x = box.left();
Expand Down Expand Up @@ -179,8 +179,7 @@ void ContentManagerDelegate::paint(QPainter *painter, const QStyleOptionViewItem
QStyleOptionViewItem eOpt = option;
if (index.column() == 5) {
if (const auto downloadState = node->getDownloadState()) {
auto downloadInfo = downloadState->getDownloadInfo();
showDownloadProgress(painter, r, downloadInfo);
showDownloadProgress(painter, r, *downloadState);
}
else {
baseButton->style()->drawControl( QStyle::CE_PushButton, &button, painter, baseButton.data());
Expand Down Expand Up @@ -250,7 +249,7 @@ void ContentManagerDelegate::handleLastColumnClicked(const QModelIndex& index, Q
int w = r.width();

if (const auto downloadState = node->getDownloadState()) {
if (downloadState->getDownloadInfo().paused) {
if (downloadState->paused) {
if (clickX < (x + w/2)) {
KiwixApp::instance()->getContentManager()->cancelBook(id, index);
} else {
Expand Down
58 changes: 12 additions & 46 deletions src/contentmanagermodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
#include "kiwixapp.h"
#include <kiwix/tools.h>

ContentManagerModel::ContentManagerModel(Downloads* downloads, QObject *parent)
ContentManagerModel::ContentManagerModel(const Downloads* downloads, QObject *parent)
: QAbstractItemModel(parent)
, m_downloads(*downloads)
{
Expand Down Expand Up @@ -245,57 +245,18 @@ void ContentManagerModel::updateImage(QString bookId, QString url, QByteArray im
emit dataChanged(index, index);
}

std::shared_ptr<RowNode> getSharedPointer(RowNode* ptr)
{
return std::static_pointer_cast<RowNode>(ptr->shared_from_this());
}

void ContentManagerModel::startDownload(QModelIndex index)
{
auto node = getSharedPointer(static_cast<RowNode*>(index.internalPointer()));
const auto bookId = node->getBookId();
const auto newDownload = std::make_shared<DownloadState>();
m_downloads[bookId] = newDownload;
node->setDownloadState(newDownload);
QTimer *timer = newDownload->getDownloadUpdateTimer();
connect(timer, &QTimer::timeout, this, [=]() {
updateDownload(bookId);
});
}

void ContentManagerModel::updateDownload(QString bookId)
{
const auto download = m_downloads.value(bookId);

if ( ! download )
return;

const bool downloadStillValid = download->update(bookId);

// The download->update() call above may result in
// ContentManagerModel::setBooksData() being called (through a chain
// of signals), which in turn will rebuild bookIdToRowMap. Hence
// bookIdToRowMap access must happen after it.

const auto it = bookIdToRowMap.constFind(bookId);

if ( ! downloadStillValid ) {
m_downloads.remove(bookId);
if ( it != bookIdToRowMap.constEnd() ) {
const size_t row = it.value();
RowNode& rowNode = static_cast<RowNode&>(*rootNode->child(row));
rowNode.setDownloadState(nullptr);
}
}

if ( it != bookIdToRowMap.constEnd() ) {
const size_t row = it.value();
const QModelIndex rootNodeIndex = this->index(0, 0);
const QModelIndex newIndex = this->index(row, 5, rootNodeIndex);
const QModelIndex newIndex = this->index(row, 5);
emit dataChanged(newIndex, newIndex);
}
}


void ContentManagerModel::pauseDownload(QModelIndex index)
{
emit dataChanged(index, index);
Expand All @@ -306,11 +267,16 @@ void ContentManagerModel::resumeDownload(QModelIndex index)
emit dataChanged(index, index);
}

void ContentManagerModel::cancelDownload(QModelIndex index)
void ContentManagerModel::removeDownload(QString bookId)
{
auto node = static_cast<RowNode*>(index.internalPointer());
node->setDownloadState(nullptr);
m_downloads.remove(node->getBookId());
const auto it = bookIdToRowMap.constFind(bookId);
if ( it == bookIdToRowMap.constEnd() )
return;

const size_t row = it.value();
auto& node = static_cast<RowNode&>(*rootNode->child(row));
node.setDownloadState(nullptr);
const QModelIndex index = this->index(row, 5);
emit dataChanged(index, index);
}

11 changes: 4 additions & 7 deletions src/contentmanagermodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ class ContentManagerModel : public QAbstractItemModel
typedef QMap<QString, std::shared_ptr<DownloadState>> Downloads;

public: // functions
ContentManagerModel(Downloads* downloads, QObject *parent = nullptr);
ContentManagerModel(const Downloads* downloads, QObject *parent = nullptr);
~ContentManagerModel();

QVariant data(const QModelIndex &index, int role) const override;
Expand All @@ -47,26 +47,23 @@ class ContentManagerModel : public QAbstractItemModel

public slots:
void updateImage(QString bookId, QString url, QByteArray imageData);
void startDownload(QModelIndex index);
void pauseDownload(QModelIndex index);
void resumeDownload(QModelIndex index);
void cancelDownload(QModelIndex index);
void removeDownload(QString bookId);
void updateDownload(QString bookId);

protected: // functions
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;

private: // functions
void updateDownload(QString bookId);

private: // data
BookInfoList m_data;
std::shared_ptr<RowNode> rootNode;
int zimCount = 0;
ThumbnailDownloader td;
QMap<QString, size_t> bookIdToRowMap;
QMap<QString, QByteArray> iconMap;
Downloads& m_downloads;
const Downloads& m_downloads;
};

#endif // CONTENTMANAGERMODEL_H
Loading

0 comments on commit 75ecdeb

Please sign in to comment.